Let's define a simple Array and call each on it:
enumerator = [1,2,3].each # => #<Enumerator: [1, 2, 3]:each>
We get an instance of Enumerator class. We can use the next method on it and if we use it more than 3 times we get a StopIteration exception.
irb(main):003:0> 10.times { puts enumerator.next }
1
2
3
StopIteration: iteration reached an end
from (irb):3:in `next'
from (irb):3:in `block in irb_binding'
from (irb):3:in `times'
from (irb):3
from /home/b/.rvm/rubies/ruby-2.3.3/bin/irb:11:in `<main>'
So what we can do to create a cyclic enumerator to repeat our collection?
We can cover our next method using some metaprogramming magic, like this:
enumerator = [1,2,3].each
original_next = enumerator.method(:next)
enumerator.define_singleton_method(:next) do
begin
original_next.call
rescue StopIteration
rewind
original_next.call
end
end
10.times { puts enumerator.next }
and the response is as expected:
1
2
3
1
2
3
1
2
3
1
This is a dirty trick, because next is a special keyword in Ruby and covering it with our own method is not a good idea.
Unfortunately, I couldn't find a way to use all of the Enumerable API magic with this approach. I have to dig deeper into this. :)