apply. These are methods on function objects that allow you to change what
this points to. If you haven’t stumbled on those methods yet then you have more than likely used them indirectly via
apply. The lessons can be found at http://ejohn.org/apps/learn/.
Ruby has similar context manipulation facilities and they are even more useful. In fact one of the reasons that Ruby programmers are so fond of writing DSLs is because of methods like
instance_variable_set, etc. that allow one to mess with the context. Combined with the syntax sugar that Ruby offers for passing around blocks of code a good Ruby programmer can pretty much bend the language into whatever form desired for solving a problem. Unfortunately I can’t offer a cool set of interactive lessons like John Resig but I can provide some templates that you can mess with to get a feel for some of Ruby’s context management tricks.
We’ll start of with a few simple methods that demonstrate some simple scoping rules for
self. Fire up
irb and type in the following code
I hope you read the comments and thought about what the output of each method should have been. The first call is pretty simple and you shouldn’t be surprised by what it outputs. The second call requires a bit more thought. I have to do this experiment every time to figure out what’s going on. Since the block is created in the topmost context,
self points to
main and when it is evaluated by
block_caller the block remembers that
self points to
main and prints out
main. Now lets try something a little different. Add the following method and then think about what the output of the new method should be before typing it in and seeing the result.
The output of the above code should give you hint about what
instance_eval changes what
self points to so that when you pass in a block of code the block gets evaluated with
self pointing to the receiver of
instance_eval. This is an extremely useful trick and when designing a DSL one of the things people do is create an object that has the required methods and instance variables and then use
instance_eval to evaluate a piece of code in the context of that object. Here’s a non-trivial example The above code is part of pure Ruby PEG interpreter DSL that I wrote to learn about PEGs. I took inspiration from peg.js and the above method uses the trick I just mentioned to evaluate blocks of code during the parsing process. It’s hard to tell what’s going on but if you look at lines 4-12 you can see that I’m creating an object and then defining a whole bunch of methods on that object. Then I use that object as the context in which to evaluate the block.
The above presentation was probably a little terse but it should have given you a taste of the context manipulation facilities that are available in Ruby. There are tons of resources available on the web about Ruby’s metaprogramming facilities of which context manipulation is a small part of. If you just google “ruby block context” then you should get a nice set of articles that explore blocks and their uses in DSL design in a bit more detail.