I was wrapping my head around the Enumerator class while reading Pickaxe and it mentioned that the Enumerator class is how Ruby implements external iterators. Of course this caught my attention, if there is an external iterator, then there must also be an internal iterator. I did a little digging and my suspicion was confirmed.
Internal iterators are iterators that are built into the collection itself. For example, the most vanilla internal iterator in Ruby is the #each method of an Array instance. The #each method traverses over each array element and passes each element to the code block that is associated with the #each method call.
External iterators on the other hand, are objects that traverse a collection, specifically, the logic of how a collection is traversed is dictated by an external object.
Creating an internal iterator is to simply call the #each method on a collection and attach a block to the #each method call.
1 2 3 4 5
To create an external iterator, the most straight-forward way is to call #to_enum on a collection and a new enumerator object will be returned to you. What is also worth noting is when you call an internal iterator on a collection without attaching a block, it is equivalent to calling #to_enum on the collection.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Once you have an external iterator created, you have much greater control over how you can iterate over your collection.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
Benefits and Drawbacks
Internal iterators are easy to implement but lack flexibility. The behavior of an internal iterator is preset by the collection. For example, both #map and #each will always traverse each element of an array from the beginning until the end. Due to these characteristics, internal iterators are suitable for when you need to linearly traverse a collection.
But when linear traversion is not what you are after, expect to write a few more lines of code and exercise control with an external iterator.