Ruby for Newbies: Iterators and Blocks

Ruby is a one of the most popular languages used on the web. We've started a new screencast series here on Nettuts+ that will introduce you to Ruby, as well as the great frameworks and tools that go along with Ruby development. In this chapter, we’ll talk about in blocks and iterators.

Catch Up

View Screencast

Blocks

In the last lesson, we talked about loops. You actually won’t use loops too often in Ruby, because of a feature called blocks (and—as a result of blocks—iterators). To refresh your memory, look at the two following method calls (you can try this in IRB):

In this case, the array sites is the receiver; the method is map!. Next we have the block. If the block is on multiple lines, you can use the keywords do and end to delimit it. If you’re putting it on a single line, you can use curly braces (these work for multi-line blocks, too).

After the opening of the block, we have the block parameters, within pipes ( | ). What this is really depends on the method you’re executing. The most common use of blocks are in iterator methods, so the block parameter will be the current item in the looping. If this sounds rather abstract, we’ll do a few examples.

Iterators

We’ll start by looking at the iterators of arrays, because they’re the most commonly looped over thing.

This is just like doing a for loop; one by one, each item in sites will be assigned to the block parameter site; then, the code inside the block will be executed.

In case you’re curious, the each method returns the original array.

Sometimes, you’ll want to return a value from the block. That’s not hard to do, if you use the right method.

# assume sites above
sites = sites.map do |s|
"#{s}.tutsplus.com"
end

The map method collects whatever values are returned from each iteration of the block. Then, an array of those values is returned from the method. In this case, we’re reassigning the sites variable to the new array.

There’s a better way to do this, though. Several Ruby methods have duplicates with the exclamation mark (or bang); this means they are destructive: they replace the value they are working on. So the above could be done this way:

sites.map! { |site_prefix| "#{site_prefix}.tutsplus.com" }

Now, sites will be the array of values returned from the block.

More than just arrays have iterator methods, though. Numbers have a pretty cool times method:

As you continue coding Ruby, you’ll find a lot of useful methods that use blocks. Now, let’s see how to create our own blocks.

Building Blocks

Now that you’re familiar with using blocks, let’s see how to write methods that take advantage of them. Here are two other block tidbits that you haven’t learned yet:

Block parameters are not required; you can write a block that doesn’t use them.

Blocks themselves can be optional. You can write a function that works with or without blocks.

Here’s what happens you call a method that takes a block. Behind the scenes, Ruby is executing some method code, then, yielding to the block code. After that, control is returned to the method. Let’s check it out.

Since most of the simple iterator functions are built into Ruby, we’ll “rewrite” one of those. Let’s do the each method on arrays:

class Array
def each2
i = 0;
while self[i]
yield self[i]
i += 1
end
self
end
end

As you can see, this is just a normal method. Remember that within an instance method, the self keyword refers to the instance of the class, in this case, Array. Inside the method, we’re using a while loop to loop over the items in the array. Then, inside the loop, we use the yield keyword. We’re passing it self[i]; that will end up being the block parameter. After that, we increment i for the loop and continue.

If we wanted this method to return the array of values that the block returned, we could just capture the returned value of yield and return that, instead of self, we return that array.

Methods, revisited

Let’s finish up by talking about methods. We know that using parentheses is optional … most of the time. Here’s when you need to use the parenthesis when method calling.

Sometimes, you’ll have both method parameters and a block.

obj.some_method "param" { |x|
#block code here
}

What I’ve just done won’t work; we need to use parentheses in this case, because otherwise the block is associated with the last parameter. This is only the case if you use the curly braces to delimit the block; if you use do - end, the parentheses aren’t required.

The other time parenthesis are required is when you’re passing a literal hash (not a variable that points to a hash) as the first parameter of the method. Ruby will think it’s a block, because of the curly brace

Hi! I'm Andrew Burgess, a Staff Writer here on Tuts+. I've been hanging around the Tuts+ since early 2009; I discovered the site when I was looking for an introduction to jQuery. Since discovering the site, my web development skills have skyrocketed; I think that's the default experience! Now, I've been writing for Tuts+ regularly since late 2009.
I've been working with the computers since I was pretty young, and with the web since 2006. I've dabbled with over a dozen programming languages, but I'm most comfortable in JavaScript and Ruby. Currently, I'm a university student, studying computer science.