It's been discussed on -talk this year, so a search in the archive for
'binding' should help. Someone posted a continuations-based solution
that gives you basically what you want, but at considerable runtime
expense, IIRC.
There's no plain-Ruby solution; i.e. the language doesn't go out of
its way to help you here. There's an RCR for it; can't remember which
one.
However, blocks can be useful here, and may just be good enough for
you.
def trace(&block)
expr = block.call
value = eval expr, block
puts "#{expr} = #{value}"
end
def foo
x = 5
y = 12
trace { "Math.sqrt( x**2 + y**2 )" }
end
I gotta say that's pretty handy.
Cheers,
Gavin
···
On Wednesday, August 18, 2004, 8:52:18 AM, Michael wrote:
Hi,
Is there a way to get the binding of the caller?
class A
def m(b=binding)
eval("self", b)
end
end
A.new.m # => #<A:0x81e1bec>
A.new.m(binding) # => main
What I want is exactly the second, but without specifying "binding"
explicitly.
Possible or not?
--
Gavin's vim tip for the day: ':help text-objects'
It's been discussed on -talk this year, so a search in the archive for
'binding' should help. Someone posted a continuations-based solution
that gives you basically what you want, but at considerable runtime
expense, IIRC.
There's no plain-Ruby solution; i.e. the language doesn't go out of
its way to help you here. There's an RCR for it; can't remember which
one.
However, blocks can be useful here, and may just be good enough for
you.
Thanks, this trick did it for me. Of course, it's not 100% perfect but that doesn't matter.
Thanks for the quick answer... uhm, but it does seem to behave as it should:
require 'binding_of_caller'
class A
def m
Binding.of_caller do |binding|
eval("self", binding)
end
end
end
p A.new.m # => #<A:0x8115a14>
I expect "self" to be "main".
That's weird -- can't find an explanation for it, because the following works:
require 'binding_of_caller'
this = self
class A
def m
Binding.of_caller do |binding|
eval("this", binding)
end
end
end
p A.new.m # => main
Maybe somebody has the knowledge needed to explain what's going on there?
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 ;-):
require 'binding_of_caller'
class Decorator
def initialize(&block) @block = block
end
def >>(meth_id)
obj = Binding.of_caller do |binding|
eval("this", binding)
end
old = 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
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
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.
Thanks for this explanation. Now I understand. It's a bit like a time travel
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.