At 22:23 12/06/2004 +0900, you wrote:
>Gavin Sinclair wrote:
>
>>Something I've wanted to do on a few occasions recently is to evaluate
>>an expression in the context of the calling method.
>
>Use this:
>
>>begin
>>  require 'simplecc'
>>rescue LoadError
>>  def Continuation.create(*args, &block)
>>    cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
>>    result ||= args
>>    return *[cc, *result]
>>  end
>>end
>># This method returns the binding of the method that called your
>># method. Don't use it when you're not inside a method.
>>#
>># It's used like this:
>>#   def inc_counter
>>#     Binding.of_caller do |binding|
>>#       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(&block)
>>  old_critical = Thread.critical
>>  Thread.critical = true
>>  count = 0
>>  cc, result, error = Continuation.create(nil, nil)
>>  error.call if error
>>  tracer = lambda do |*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)
>>        cc.call(eval("binding", context), nil)
>>      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."
>>      cc.call(nil, lambda { raise(ArgumentError, error_msg ) })
>>    end
>>  end
>>  unless result
>>    set_trace_func(tracer)
>>    return nil
>>  else
>>    Thread.critical = old_critical
>>    yield result
>>  end
>>end
>
>Regards,
>Florian Gross

This is a very creative piece of work, congratulations !
I am adding that to my rcr.rb with the proper credit.

I guess that it is not extremely efficient but it will
help me a lot in my exception logging scheme. So far I
used to explicitly pass the binding to be able to dump
the local variables when required. Thanks !

For more speed demanding usage, there would be some need
for native support I guess, but as of today your
solution is probably very close to the most efficient
solution.

BTW: What is "simplecc.rb" ?

Yours,

JeanHuguesRobert

-------------------------------------------------------------------------
Web:  http://hdl.handle.net/1030.37/1.1
Phone: +33 (0) 4 92 27 74 17