A class which provides a method `each’ to be used as an Enumerable object.

An enumerator can be created by following methods.

Also, most iteration methods without a block returns an enumerator. For example, Array#map returns an enumerator if a block is not given. The enumerator has the with_index method. So ary.map.with_index works as follows.

p %w[foo bar baz].map.with_index {|w,i| "#{i}:#{w}" }
#=> ["0:foo", "1:bar", "2:baz"]

An enumerator object can be used as an external iterator. I.e. Enumerator#next returns the next value of the iterator. Enumerator#next raises StopIteration at end.

e = [1,2,3].each   # returns an enumerator object.
p e.next   #=> 1
p e.next   #=> 2
p e.next   #=> 3
p e.next   #raises StopIteration

An external iterator can be used to implement an internal iterator as follows.

def ext_each(e)
  while true
    begin
      vs = e.next_values
    rescue StopIteration
      return $!.result
    end
    y = yield(*vs)
    e.feed y
  end
end

o = Object.new
def o.each
  p yield
  p yield(1)
  p yield(1, 2)
  3
end

# use o.each as an internal iterator directly.
p o.each {|*x| p x; [:b, *x] }
#=> [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3

# convert o.each to an external iterator for
# implementing an internal iterator.
p ext_each(o.to_enum) {|*x| p x; [:b, *x] }
#=> [], [:b], [1], [:b, 1], [1, 2], [:b, 1, 2], 3
Show files where this class is defined (1 file)
Register or log in to add new notes.
September 14, 2015 - (v1_9_1_378 - v1_9_3_392)
0 thanks

Getting the return value from the underlying method of an Enumerator

This is documented in the example code, but easy to miss.

When you get an Enumerator using #to_enum(:method_name, …), you can get all of the yielded values using #next, but not the value that is finally returned.

That value can be retrieved via the #result attribute of the StopIteration exception object that is raised when calling #next after the underlying method has returned.