Michael Neumann wrote:

> Hm, it still doesn't work in my special case, as I get a
> "Binding.of_caller used in non-method context or trailing statements of 
> method using it aren't in the block." exception (and I really don't 
> understand how this Binding.of_caller really works ;-):

It works by installing a temporary trace_func. trace_funcs get an event 
on returns from methods and the binding of the context you where in 
before the method returned. Using continuations Binding.of_caller will 
first let method return, grab the binding of the caller, go back to the 
Binding.of_caller call and this time execute the block. If I wouldn't 
raise the exception you mentioned above then statements that aren't in 
the block would be executed twice. This is why there can be no code 
outside of the Binding.of_caller block after the call to it.

This ought to work, however I find the 'this = self' line quite ugly -- 
I still need to find out why just using self doesn't work and if it can 
be solved. (It appears like the binding which I get from the trace_func 
is nested into the original binding which is why variables can be 
accessed, but not the original binding itself which is why self and 
method calls don't work.)

I couldn't test this code (haven't applied your def -> symbol patch) so 
there might still be a bug in it that I overlooked.

require 'binding_of_caller'

class Decorator
   def initialize(&block)
     @block = block
   end

   def >>(meth_id)
     Binding.of_caller do |context|
       obj = eval("this", context)
       old = obj.method(meth_id)
       new = @block.call(old)

       # the line below is why I need the Binding.of_caller
       obj.class.send(:define_method, meth_id, new)
     end
   end
end

def wrapwith(value)
   Decorator.new {|old|
     proc {|*args|
       print "##", value, "\n"
       old.call(*args)
     }
   }
end

this = self
wrapwith(42) >>
def f(x) x * 2 end

p f(4)

> Regards,
>   Michael

More regards,
Florian Gross