Accessing the scope of the calling object in a block

There's an interesting question over at subWindow about accessing the scope of the calling object in a block.

If access to local variables is desired, you can yield a Binding object from within the method. Just doing this would require writing things like eval "baz", context, where context is the Binding object returned from a call to binding. I used method_missing on Binding to make things a little more readable in the calling code.

To get at instance variables, it seems instance_variable_get is the way to go. Internally, it calls instance_eval on the string that's passed in, which is very similar to what's happening below.

class BindingTest
  attr_accessor :accessible_baz
  def bar
    baz = "qux"
    foonum = 23
    @instance_baz = "instance_baz"
    @accessible_baz = "accessible_baz"
    yield(binding)
  end
end

# Extends the binding object
class Binding
  def method_missing( method, *args )
    eval method.to_s, self
  end
end

binder = BindingTest.new

puts binder.bar { |context| context.foonum.to_s }
puts binder.bar { |context| context.baz }
puts binder.bar { |context| context.accessible_baz }
#the following line fails; only locals work
#puts binder.bar { |context| puts context.instance_baz }

puts binder.instance_variables

You could also use instance_variables and local_variables to return lists of those respective variables and evaluate them against the binding.

I haven't actually needed anything like this (and I'm sure it's open to abuse), but it's an interesting question that provides an opportunity to explore some of Ruby's reflection facilities.