Skip to content

Instantly share code, notes, and snippets.

@TayKangSheng
Last active April 16, 2020 15:44
Show Gist options
  • Save TayKangSheng/70a1574175dade1d6c84d918693dabe5 to your computer and use it in GitHub Desktop.
Save TayKangSheng/70a1574175dade1d6c84d918693dabe5 to your computer and use it in GitHub Desktop.
How to create your own Ruby Enumerator
# Enumerator is a very powerful feature if you know how to use it. The most
# powerful part of Enumerator is the possibility of chaining them. Take some
# time to understand the intricacies of it because it is not very well
# documented. Some awesome references that I found are listed below. Note that
# I didn't understand when reading any of them right off the bat. Read a few,
# dig some documentation and experiment for yourself to get the "fuller"
# picture.
#
# [1]: https://blog.arkency.com/2014/01/ruby-to-enum-for-enumerator/
# [2]: https://stackoverflow.com/a/9194052
# [3]: https://ruby-doc.org/core-2.7.1/Enumerator.html
class MyClass
def an_iterator
# enum_for and to_enum is the same. [1]
return enum_for(:an_iterator) if not block_given?
# Use of yield here is of utmost importance, any code from here on will be
# executed by the enumerator over and over again.
index = 0
while index <= 10
yield(index += 2)
end
end
def an_iterator_but_doesnt_have_yield
return enum_for(:an_iterator_but_doesnt_have_yield) if not block_given?
end
end
my_class = MyClass.new
################
#### Example of using an enumerator
################
## Without block
iterator1 = my_class.an_iterator # returns you an iterator.
puts iterator1.take(5)
# => [2, 4, 6, 8, 10]
puts iterator1.next
# => 12
## With block
iterator2 = my_class.an_iterator # returns you an iterator.
iterator2.each do |x|
# #each returns another enumerator enumerating #an_iterator method. x is what
# is yielded when calling #next on iterator 2.
puts x
end
# 2
# 4
# 6
# 8
# 10
# => nil
################
#### Example of using an iterator that does not have yield
################
## Without block
missing_yield_iterator1 = my_class.an_iterator_but_doesnt_have_yield
puts missing_yield_iterator1.take(10)
# []
puts missing_yield_iterator1.next
# StopIteration: iteration reached an end
## With block
missing_yield_iterator2 = my_class.an_iterator_but_doesnt_have_yield
missing_yield_iterator2.each do |x|
puts x
end
# => nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment