What is Enumerator?

I started programming 2 years ago and i didn’t yet come to a situation when i would really need to know. But i was always curious because words like ‘Enumerator’ and ‘Enumerable’ were present from the very beggining. So let’s find out!

Long story short:

Instances of Enumerator class are used to wrap iterations and let’s you control the whole process.

Common usage

You can get an Enumerator like this:

This Enumerator instance wraps iteration over [1, 2, 3]. We can start the actuall iteration with #each method. It yields all items to given block:

It behaves exactly same as [1, 2, 3].each { |number| puts number } call.

But you can also do this:

Like this you can manually iterate over the collection one item after another. StopIteration is raised when there are no more items. During the iteration, you can use enum#peek, enum#rewind, enum#feed or others, which greatly improves controllability. With all these you can create your own iterators with custom logic.

Enumerator.new

You can also create Enumerator with Enumerator.new { |yielder| ... }.

Most simple example:

This time enum doesn’t iterate over anything, but yields to given block all values you explicitly yield with yielder.yield something. In this example, only one value is yielded and it’s integer 1.

To yield 1 ten times to given block so enum.each { |item| puts item } will print 1 ten times on screen:

And to yield infinetely:

If you call #each on this enum, it will never stop yielding and printing. But if you call #next, it will yield only once and then stop.

It’s only the implementation of #each which calls #next in loop and goes on forever because StopIteration, is never raised.

Internally enum stops execution every time #yield is called on yielder.

Try it with putting print statements before and after yield:

This technique is also used in example from official documentation, where infinite fibonacci sequence is generated.