Logo Devoh

Bound and Determined

As part of a generic filtering mechanism I've been working on for Active Record, I came across a case where I needed to get the arity of a Proc, only the Proc was stored inside of another Proc. I settled upon a solution involving eval and the outer Proc's binding:

arity = eval('options.arity', @scope.binding) rescue nil

All was well and good, and I was proud of myself for being so clever. Then it came time to spec this out (shouldn't that have come first?), but I had no clue how to proceed. I first tried stubbing the eval call.

@filter.stub!(:eval).and_return(-1)

This works to an extent, but the scope binding also has to be stubbed, otherwise the @scope.binding call errors out and the rescue kicks in and set arity to nil.

@scope.stub!(:binding).and_return(nil)
@filter.stub!(:eval).and_return(-1)

But at this point, I felt it would be better to do things properly in order to really get to the heart of the code. This means properly stubbing the binding. Needless to say, I went through several iterations before stumbling upon one that seemed to do the trick.

@arity = lambda { |i| options = Struct.new(:arity).new(i) ; binding }
@scope.stub!(:binding).and_return(@arity.call(-1))

This lets our eval return the desired value, and the stub is easily overridden in any examples which require a value other than -1.

I will say that my big stumbling block was thinking that the following are equivalent:

lambda { }.send(:binding)
lambda { binding }.call

The former won't get us very far, as it's not the binding for which we're looking. The latter, however, gets us exactly where we need to be to perform our magic.

For more information, see Variable Bindings in Ruby.

and tagged with binding and ruby