Greg Elizondo


navigation
home
github
twitter
about
MBA, marketer, Rubyist in training

Custom Iterators and yield

27 May 2014

Iterators are a crucial component of the programming world. Ruby make iterators easy to use and read.

Iterating over a simple array may look something like this:

> plain_numbers = [2, 3, 4]
=> squared_values = []

> plain_numbers.each do |n|
>   squared_values << n**2
> end

> squared_values
=> [4, 9, 16]

This snippet of code should be simple enough to understand. First, we created an array called plain_numbers. We also created an empty array named squared_values.

The next section of code is called a block in Ruby. The each method signifies that we'll be going through each element in the object (in this case it's the plain_numbers array) and interacting with it. The element gets passed in to the block of code as the n variable. We take this n variable, square it, and then add it to the squared_values array. Simple enough.

Ruby comes with a bunch of iterators built-in, like each, times, upto, andeach_index`. These iterators are simple but powerful and you'll see them being used all over Ruby code.

Rolling your own iterator

Sometimes a situation might arise when the built-in Ruby iterators just won't cut it. What then? Luckily, Ruby makes it pretty easy to write your own custom iterator.

Here is a simple case of writing our own custom iterator:

def simple_block
    puts "This is in the method"
    yield
    puts "This is still in the method"
    yield
end

simple_block {puts "This is in the block"}

Would result in:

This is in the method
This is in the block
This is still in the method
This is in the block

As you can see, the block is being invoked by calling the method of the same name, simple_block. When we first call simple_block, the method starts and puts "This is in the method" is called. yield then hands off responsibility to the block (which is denoted by the curly brackets). Once this block is done running, we're back in the original method again. This process happens one more time when yield is called yet again.

When I first encountered the yield statement, I found it incredibly confusing. I still can't claim mastery over it, but simple examples like the one above helped me to better understand it.

Here's another simple example of a custom iterator in use. Let's pretend we're building a game that needs to check whether or not a character's name is valid. For whatever reason, we only want character names that are greater than 3 characters.

character_names = ['Jon', 'Ricky', 'Andrew']

def valid_character_checker(names)
  names.each do |name|
    puts "Is #{name} a valid charcter?"
    yield(name)
  end
end

valid_character_checker(character_names) do |name|
  if name.length > 3
    puts "This is a valid character name!"
  else
    puts "This is an invalid character name :("
  end
end

Once again, this example is pretty simple if you work through it step-by-step. It's also pretty verbose and probably not the best example of what real code would look like in the wild.

Do you have a better example of how yield and custom iterators should be used in Ruby? Comment below and let me know.

comments powered by Disqus