From: Brian Mitchell Date: 2006-05-02T13:29:23+09:00 Subject: Re: from block to code (also: how to get the bindings of a block) On 5/1/06, chiaro scuro wrote: > Not sure about the ATs. even if I don't mind them that much... if I unfocus > my eyes they look like bullet points ;-) > > I have got this one working.. see if you can guess how.. > > recipe "eggs and bacon" do > eggs = [2,:big] > bacon = 3 > the end > If you really want the = look you can capture the binding with the set_trace_func utility. This has drawbacks right now as there is no "clean" way to share set_trace_func cooperatively w/o some code (some small hacking could easily add this though -- sample bellow). So this will get rid of the ugly "the" but you will need to be careful that the Kernel stuff is executed before other things that might possibly want to use the old style tracer: # Could be cleaned up quite a bit but it should work. module Kernel tracers = [] legacy_tracer = nil set_trace_func lambda {|*args| legacy_tracer.call(*args) if legacy_tracer tracers.dup.each {|tracer| tracer.call(*args)} unless args[3] == :trace } define_method(:set_trace_func) {|proc| legacy_tracer = proc nil } # Not thread safe but easy to make so. define_method(:trace) {|tracer, block| tracers << tracer result = block.call # lambda {} == lambda {} work around just in case. tracers.reject! {|x| x.object_id == tracer.object_id} result } end def recipe(name) recipe_binding = nil trace( lambda {|event, file, line, id, binding, classname| recipe_binding = binding unless id }, lambda {yield}) ingrediants = eval("local_variables", recipe_binding) puts "To make #{name} you need:" ingrediants.each {|i| info = eval(i, recipe_binding) info = info.join(' ') if Array === info puts " #{info} #{i}" } end recipe "eggs and bacon" do eggs = 2, :big # Note that ruby has a nicer syntax than explicit [] here. bacon = 3 end I get this output: To make eggs and bacon you need: 2 big eggs 3 bacon Hope this helps, Brian.