Calling in the dark
June 7th, 2008
eval("caller", registration_binding_block.binding)
Wow, what is going on here? After tracing through the RSpec code, I learned that ‘registration_binding_block’ was a block being turned into a Proc via block_pass.
For example:
def describe(&block)
@registration_binding_block = block
yield
end
So now we know what’s being returned by this method, but what about the rest of that line?
Some people may not know that eval can take a Proc as a second argument. For the purposes of eval, a Proc and that Proc’s binding produce the same result.
So we should also be able to say:
eval("caller", registration_binding_block)
What does it even mean to ask for “caller” in a Proc’s binding? What are we asking for? The Proc in question may not even have executed yet. It could just be sitting around, waiting to be called.
It turns out that RSpec wants to know the stack trace, not from this call to ‘eval’, but back from where the “registration_binding_block” was originally written; for example, one of the user’s spec files. RSpec uses this fairly extreme meta-programming trick in order to match your specs back to the file and line they were written on.
After the massive headache of understanding what the fix was, it turned out to be fairly easy to hack into Rubinius, and most of the RSpec specs now pass.
For everyone running benchmarks on unfinished Ruby implementations.. good luck keeping your speed when you are done with the really fun Ruby features.
Anyone out there know an easier way to ask a Proc what its “definition trace” is than what RSpec uses? I can’t think of one myself yet..

on June 7th, 2008 at 10:57 PM
I noticed that recently, and I am gonna look at it soon. Will let you know if any results will be found..
Thanks
on June 8th, 2008 at 03:10 AM
I wrote that line of code, so please be kind :) Thanks for the simplification. I committed it.
We used to parse the file, but that technique doesn’t work well for with nested ExampgeGroups & shared ExampleGroups.
Unfortunately I don’t know of a better way to get the stack trace of an invocation on MRI.
I’m suprised that the following does not work:
on June 8th, 2008 at 07:41 AM
The paucity of reflective methods on potentially useful classes like Proc, Lambda, Binding et al is one of those things that I find frustrating about Ruby. I come to this from Perl, where the methods you need to deploy to get at this stuff is even more arcane than the ruby example you show, but where it’s actually possible to pull out more information before you have to resort to
eval STRING.I’m hoping that turtles all the way down approaches like Rubinius will let people experiment with adding features like
Block#send, hashlike accessors on Binding, metaquote type facilities for dynamic code generation, malleable parsers a million and one other good ideas that could be usefully lifted from languages like Lisp…on June 8th, 2008 at 09:29 AM
I totally agree, Brian. After today in Rubinius, you will be able to ask a Proc this question directly.
on June 8th, 2008 at 12:45 PM
Proc#caller works in Rubinius now. Seems like something MRI could easily add as well.
on June 11th, 2008 at 02:39 AM
Wilson, that is awesome. Thank you.