Friday, 04 May 2007

1: Ruby blocks and iterators

The first time I saw Ruby code, the 'blocks' stood out like a sore thumb. They were everywhere. Sometimes it was obvious what the code did, sometimes not. I was intrigued. Of course, once I started programming Ruby, I learned to love blocks. They are a really cool and expressive way of doing things that can be quite a lot less convenient in Java. I am not going to explain all the details of what blocks are and how they work (see ‘Programming Ruby’ if you want to know that). I’m simply going to show you a few examples, to give you an idea.


Consider the classic ‘for’-loop. In many C-like languages the syntax is the same as in Java:
Java for loop
Java for loop results
In Ruby there are a few ways of doing what the above code does, but using blocks you can be very concise:
Ruby Range.each
Ruby Range.each results
One important point about this is that the each method is actually called only once, not three times, but it in turn will call back into the block three times, each time passing the latest value of ‘i’.

Code injection

In java we can also pass code into a method to be called when necessary, but it requires defining specific interfaces. Here is an example based on some real code we have in a regression testing framework used to test one of our products every night:
Java code injection
Wow, that was verbose. We needed to define the interface ‘CustomTesting’, and each time the main test method ‘doTest’ is called we pass an implemetation of that interface so that it can be called in the middle of the test. This seems simply like a much more verbose way of doing what Ruby blocks do, and in this example that is true. But Ruby takes this one critical step further. The local scope available at the time the block is passed into the method is still available within the method. That is not true in Java, and is a very important difference.

Ruby method blocks

So, what does this look like in Ruby.
Ruby method blocks
Ruby method blocks results
Much simpler than in java, that’s for sure. But this example does not show anything beyond the java example. Two things ruby supports that really interest me are:

  • Local scope
  • Metaprogramming

There will be examples of local scope in laters snippets, and I have decided to devote the entire next snippet, all 15 minutes of it, to metaparogramming.

Ruby blocks and metaprogramming

Although I have decided to devote the next snippet to metaprogramming, here is a quick taster:

Ruby method blocks metaprogramming
Ruby method blocks metaprogramming results
This is very similar to the previous example, but I have actually modified the Range class to have a new method to call, and I do so instead of the ‘each’ method I used before. You can even change the ‘each’ method to do something different than before. Next week I’ll discuss this in more detail.

No comments: