>>./libs/binding_of_caller.rb:61:in `of_caller': Binding.of_caller used
>>in non-method context or trailing statements of method using it aren't
>>in the block. (ArgumentError)
>
>The message is quite explicit *g*
Perhaps, but confusing to me
(The phrase "Either your zyloxens aren't grimbled or you tweedled
outside of a borklub" is also explicit, but that don't mean I have a
clue how to solve the problem
>Binding.of_caller do |b|
> evt.source = eval("self", b)
> callbacks.each{|m| m.call evt }
> end
>end
That worked, thanks.
So does "... trailing statements of method using it aren't in the
block" mean "you can't place any statements after the Binding.of_caller
invocation"?
Exactly.
(Like it irrevocably changes the context and can't get you
back to where you were or something?)
That's because Florian's Binding.of_caller works as follows:
* a continuation for the block is created
* of_caller returns; *the enclosing method returns*
* the next event notified to the proc_func is the 'return'; at that
point the binding of the caller is captured
* the continuation is called, and the block is given the Binding that
was obtained previously
* when the block has been executed, the method returns *for the second
time*, with the value returned by the block
It is possible to implement Binding.of_caller without callcc, which
makes it much faster, but that comes at a cost:
* ugly interface
* the value returned is a proxy for the real value (can be fixed with
evil.rb of course for many kinds of objects)
batsman@tux-chan:/tmp$ cat binding_of_caller.rb
# UGLY 'binding of caller' implementation, which doesn't use callcc.
# Based on Florian Groß' original.
# This method allows you to grab the binding of the method that called your
# method. Don't use it when you're not inside a method.
···
On Tue, Sep 28, 2004 at 09:14:02PM +0900, Gavin Kistner wrote:
On Sep 28, 2004, at 2:16 AM, Mauricio Fernández wrote:
>On Tue, Sep 28, 2004 at 12:56:25PM +0900, Gavin Kistner wrote:
#
# It's used like this:
# def inc_counter
# Binding.of_caller(self, r = lambda do
# binding = eval("binding_of_caller", r)
# eval("counter += 1", binding)
# end)
# end
# counter = 0
# 2.times { inc_counter }
# counter # => 2
#
# You will have to put the whole rest of your method into the
# block that you pass into this method. If you don't do this
# an Exception will be raised. Because of the way that this is
# implemented it has to be done this way.
def Binding.of_caller(oldself, block)
old_critical = Thread.critical
Thread.critical = true
count = 0
result = nil
retvalue = Object.new
#FIXME: which methods do we want
#class << retvalue; self end.send(:define_method, :to_s){ result }
class << retvalue; self end.send(:define_method, :value){ result }
tracer = lambda do |*args|
#p args
type, context = args[0], args[4]
if type == "return"
count += 1
# First this method and then calling one will return --
# the trace event of the second event gets the context
# of the method which called the method that called this
# method.
if count == 2
# It would be nice if we could restore the trace_func
# that was set before we swapped in our own one, but
# this is impossible without overloading set_trace_func
# in current Ruby.
set_trace_func(nil)
eval("binding_of_caller = nil; lambda{|binding_of_caller|}", block).call(context)
result = oldself.instance_eval(&block)
Thread.critical = old_critical
end
elsif type != "line"
set_trace_func(nil)
error_msg = "Binding.of_caller used in non-method context or " +
"trailing statements of method using it aren't in the block."
raise(ArgumentError, error_msg)
end
end
set_trace_func(tracer)
retvalue
end
def foo
a = "some string"
bar
end
def bar
Binding.of_caller(self, r = lambda do
binding_of_caller = eval("binding_of_caller", r)
eval("a", binding_of_caller)
end)
end
# we can get rid of the proxy obj with Object#become or whatever
p foo.value
batsman@tux-chan:/tmp$ ruby -v binding_of_caller.rb
ruby 1.8.2 (2004-09-22) [i686-linux]
"some string"
Both implementations have the same problem: you lose the previous
trace_func. It could be restored transparently if Ruby exposed it.
--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com