Welcome back to the world of Enumerable my friend. As Rubyists we are used to
spend a lot of time looking at and working with this module (even if you're not
entirely aware). This time we will be looking at a somewhat hidden feature of
most of its methods, they can be used without a block and have a return value
that is itself an enumerator.
Here's how you're probably used to iterating over an Array in Ruby:
[1, 2, 3].each do |num|
puts num * 2
end
## => 2
## => 4
## => 6This is great and definitely should be your first solution for this problem, but in some situation you might find it useful to break this process apart. You might want to do part of iteration and continue it later, or have the array in one place and the method that operates on it somewhere else.
Regardless of your reasons, you can also iterate over an Array like so:
iter = [1, 2, 3].each
def double(num)
num * 2
end
puts double(iter.next) # => 2
puts double(iter.next) # => 4
puts double(iter.next) # => 6
puts double(iter.next)
# => StopIteration: iteration reached an endStopIteration is an exception that gets raised when there is nothing else in
the enumerator. This is something that gets hidden away by the block syntax, so
that you don't have to deal with it every time.
Other enumerators
What we did with each is applicable to many other methods on Enumerable,
such as map, find, max_by and sort_by. I feel that this is a feature in
the language that you may never use, but it is good to be aware of.
Real World™ example
In Ruby map is a method that can be used to go over each element of an
Enumerable, perform some operation on it and return a new Array with the
results of performing that operation. It sounds more complicated that it really
is. Here's an example:
result = [1, 2, 3].map do |num|
num * 2
end
p result # => [2, 4, 6]The difference between map and each is that each always returns the object
in its initial state, but map returns a new Array with the modifications we
wanted done to it.
Now, what if we wanted to do something similar to what we've just done but
instead of always multiplying the number by 2, we wanted to multiply it by its
index in the Array?
We know there's a method called each_with_index, we could try to use that with
an auxiliary Array to store the result of each of the steps. On the other
hand, that sound a lot like map, I bet there's a map_with_index we can use!
Well, unfortunately there isn't... What if we create our own "map_with_index"
by composing map and with_index (another Enumerable method)?
result = [1, 2, 3].map.with_index do |num, index|
num * index
end
p result # => [0, 2, 6]Wow, it worked! And it reads pretty well, but how come we can do this? If we
open irb and run this:
> [1, 2, 3].map.class.ancestors
## => [Enumerator, Enumerable, Object, Kernel, BasicObject]We can see that Enumerator is itself Enumerable, which means it has the with_index method, but
more importantly than that, it means we can compose this methods at will. And
that my friends is why there's no way not to love the Enumerable module.
More Ruby Bits
If you've enjoyed this Ruby Bit you should really subscribe to our newsletter, where other Ruby Bits and more great articles are shared every week.

