This is part of the Back to Basics series.
See the introductory article for an explanation of why this series is important.

To Each Their Own

The word “enumerable” means “able to be counted”. In programming languages, enumerable objects are typically anything that acts as a read-only list.

In the Ruby Standard Library, Enumerable is a mixin style module based on the method .each, which is defined by the class or module where this is included.

The simplest .each method is just a hard-coded set of one or more yield statements.

class PocketContentGuesses
  def each
    yield "handses"
    yield "knife"
    yield "string", "nothing"
  end
end
PocketContentGuesses.new.each { |item| p item }
"handses"
"knife"
"string"

This isn’t a terribly common pattern, but it is the heart of more complex implementations.

Notice that there is nothing enforcing the similarity of the objects you yield (or indeed their count each time, as in the last line), except the ire of those who will try to consume your Enumerable content.

It is generally considered good form to always use the same number and same type of item for each call to yield, if you don’t want to get stabbed by irate developers later.

A more conventional each often delegates to an underlying data structure.

class ArrayWithOrdinals < SimpleDelegator
  def each
    length.times do |number|
      yield [number + 1, self[number]]
    end
  end
end

ArrayWithOrdinals.new(%w(a b c)).each do |number, item|
  puts "##{number}: #{item}"
end
#1: a
#2: b
#3: c

This is still pretty contrived, as any sane person would just delegate to the built in Array#each method.

class ArrayWithOrdinals < SimpleDelegator
  def each
    number = 1
    __getobj__.each do |item|
      yield number, item
      number += 1
    end
  end
end

ArrayWithOrdinals.new(%w(a b c)).each do |number, item|
  puts "##{number}: #{item}"
end
#1: a
#2: b
#3: c

There are actually several ways to solve this with other Enumerable methods on Array, but that would be cheating, no?

A Brief Aside on Enumerators

Now, polite each methods also return an Enumerator if no block is given. An enumerator has an each method as well (which allows chaining of Enumerable functionality), but that each method is implemented as a series of calls to next, yielding values until a StopIteration exception is raised.

class ArrayWithOrdinals < SimpleDelegator
  def each
    return to_enum unless block_given?

    number = 1
    __getobj__.each do |item|
      yield number, item
      number += 1
    end
  end
end

ArrayWithOrdinals.new(%w(a b c)).each.next 
# Returns: [1, "a"]
# No output

ArrayWithOrdinals.new(%w(a b c)).each do |number, item|
  puts "##{number}: #{item}"
end
#1: a
#2: b
#3: c




Ok, we have our .each defined, all nice and proper. Now what?

Well, by including Enumerable, we now have 58 new methods to play with (though several are aliases of each other).

Lets check these out, grouped by function. We will use simple arrays for most of the examples below, but wherever you see item you could substitute any yielded value from another each.

First: Scratching that Each

To read the rest of the series: click here