3 require 'sexp_processor'
8 sexp = transform_sexp(block)
9 ruby = generate_ruby(sexp)
10 eval(ruby).call(*args)
13 def transform_sexp block
14 DoNotation.new.process(block.to_method.to_sexp)
17 # gnarly text munging copied & pasted from ruby2ruby source
18 def generate_ruby sexp
19 ruby = Ruby2Ruby.new.process(sexp)
20 ruby.sub!(/\A(def \S+)\(([^\)]*)\)/, '\1 |\2|') # move args
21 ruby.sub!(/\Adef[^\n\|]+/, 'proc { ') # strip def name
22 ruby.sub!(/end\Z/, '}') # strip end
23 ruby.gsub!(/\s+$/, '') # trailing WS bugs me
28 class DoNotation < SexpProcessor
29 def process_bmethod exp
32 if arg_assignment = process(exp.shift)
33 if arg_assignment.first == :dasgn or arg_assignment.first == :dasgn_curr
34 args = [arg_assignment[1]]
35 elsif arg_assignment.first == :masgn
36 args = arg_assignment[1][1..-1].collect { |e| e[1] }
38 raise DoNotationError, "I can't parse this block :("
44 block = process(exp.shift)
46 assert_type block, :block
52 *rewrite_assignments(block)))
55 def rewrite_assignments exp
56 return [] if exp.empty?
60 if head.first == :call and head[1].first == :vcall and head[2] == :< and head[3].first == :array and head[3][1].last == :-@
62 expression = head[3][1][1]
64 body = rewrite_assignments(exp)
66 if body.first.is_a? Symbol
71 s(:call, process(expression), :bind),
72 s(:dasgn_curr, var_name),
75 head + rewrite_assignments(exp)
79 def self.pp(obj, indent='')
80 return obj.inspect unless obj.is_a? Array
81 return '()' if obj.empty?
83 str = '(' + pp(obj.first, indent + ' ')
88 next_indent = indent + (' ' * str.length)
90 str << obj[1..-1].map{ |o| pp(o, next_indent) }.join("\n#{next_indent}")
99 class DoNotationError < StandardError; end