On Sun, Nov 6, 2011 at 10:35 PM, Intransition <transfire / gmail.com> wrote: > I'd want to write a DSL such that a surface method_missing catches undefined > methods and records the blocks that they define e.g. > foo do > puts "foo" > end > So I would end up with: > { :foo=>#<Proc ...> } > Presently I have something like this: > > # > class Evaluator < BasicObject > def initialize(&block) > @__config__ = {} > instance_eval(&block) if block > end > def __config__ > @__config__ > end > def method_missing(sym, *args, &block) > @__config__[sym] = block > end > end > However when I call on a block I want it to evaluate as if in the defining > contextin this case toplevel), not inside the "DSL" class that evaluated > via method_missing. > e = Evaluator.new do > foo do > puts "foo" > end > end > > e.__config__[:foo].call > Instead of what I want, I get a method missing error for #puts. > Any ideas? You could capture the calling self by getting it from the binding of the block and hide the evaluating call behind your own #eval method: class Evaluator < BasicObject def initialize(&block) @__config__ = {} if block @context = block.binding.eval("self") instance_eval(&block) end end def __config__ @__config__ end def method_missing(sym, *args, &block) @__config__[sym] = block end def eval(sym, *args) @context.instance_exec(*args, &@__config__[sym]) end end e = Evaluator.new do foo do puts "foo" end bar do |txt| puts "txt = #{txt}" end end e.eval(:foo) # => "foo" e.eval(:bar, "hello") # => "txt = hello" Regards, Sean