Class | Binding |
In: |
vendor/rails/activesupport/lib/active_support/binding_of_caller.rb
|
Parent: | Object |
This method returns the binding of the method that called your method. It will raise an Exception when you’re not inside a method.
It’s used like this:
def inc_counter(amount = 1) Binding.of_caller do |binding| # Create a lambda that will increase the variable 'counter' # in the caller of this method when called. inc = eval("lambda { |arg| counter += arg }", binding) # We can refer to amount from inside this block safely. inc.call(amount) end # No other statements can go here. Put them inside the block. end counter = 0 2.times { inc_counter } counter # => 2
Binding.of_caller must be the last statement in the method. This means that you will have to put everything you want to do after the call to Binding.of_caller into the block of it. This should be no problem however, because Ruby has closures. If you don’t do this an Exception will be raised. Because of the way that Binding.of_caller is implemented it has to be done this way.
# File vendor/rails/activesupport/lib/active_support/binding_of_caller.rb, line 39 39: def Binding.of_caller(&block) 40: old_critical = Thread.critical 41: Thread.critical = true 42: count = 0 43: cc, result, error, extra_data = Continuation.create(nil, nil) 44: error.call if error 45: 46: tracer = lambda do |*args| 47: type, context, extra_data = args[0], args[4], args 48: if type == "return" 49: count += 1 50: # First this method and then calling one will return -- 51: # the trace event of the second event gets the context 52: # of the method which called the method that called this 53: # method. 54: if count == 2 55: # It would be nice if we could restore the trace_func 56: # that was set before we swapped in our own one, but 57: # this is impossible without overloading set_trace_func 58: # in current Ruby. 59: set_trace_func(nil) 60: cc.call(eval("binding", context), nil, extra_data) 61: end 62: elsif type == "line" then 63: nil 64: elsif type == "c-return" and extra_data[3] == :set_trace_func then 65: nil 66: else 67: set_trace_func(nil) 68: error_msg = "Binding.of_caller used in non-method context or " + 69: "trailing statements of method using it aren't in the block." 70: cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil) 71: end 72: end 73: 74: unless result 75: set_trace_func(tracer) 76: return nil 77: else 78: Thread.critical = old_critical 79: case block.arity 80: when 1 then yield(result) 81: else yield(result, extra_data) 82: end 83: end 84: end