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

Last time, on “Back to Basics: Enumerable”, we learned about how each works, and how by including Enumerable on a class with each we now have access to dozens of new methods.

First, check out the six new versions of each!:



A “cons cell” is a list primitive from languages like lisp which is a fixed number of items (2 in lisp).

each_cons(n) { |cons_cell| ... } yields a series of these cons cells, each of length n. If n is larger than the full list, nothing is yielded.

You can think of this as a “sliding window” down the enumerable, which is n items wide.

%w(a b c d e f g).each_cons(3) do |notes|
  p notes
end
["a", "b", "c"]
["b", "c", "d"]
["c", "d", "e"]
["d", "e", "f"]
["e", "f", "g"]


Remember poor Gollum and his PocketContentsGuesses from last time?

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

Notice how "nothing" is missing from the output? This is because of how block arguments work in Ruby. If you don’t provide enough slots in a block definition for all the items yielded, Ruby just fills in the ones it can.

You can use the splat operator to wrap all the arguments in a list

PocketContentGuesses.new.each { |*items| p items }
["handses"]
["knife"]
["string", "nothing"]

You can also use that to just slurp up the remainder.

PocketContentGuesses.new.each do |first, *rest| 
p first, rest
end
"handses"
[]
"knife"
[]
"string"
["nothing"]

But we can’t quite get it right for this use case, can we?

each_entry { |entry| ... } solves this by only wrapping multiple yielded values into a list, while leaving the single yielded values alone.

PocketContentGuesses.new.each_entry { |entry| p entry } 
"handses"
"knife"
["string", "nothing"]

Again, never actually write an enumerable like Gollum’s, but this each_entry can be useful when processing unusual streams of data, or when trying to debug the values being yielded to you.



each_with_index { |obj, index| ... } should feel like an old friend after the ArrayWithOrdinals examples at the top.

Note that it is an index, which means zero-based.

%w(a b c).each_with_index do |note, index|
  puts "##{index + 1}: #{note}"
end
#1: a
#2: b
#3: c

Out of the flavors of each that Enumerable adds, each_with_index is one of my favorites, especially when chained with other enumerable methods.



Have you ever found yourself writing methods like this?

def interesting_data
  arr = []
  data.each do |item|
    arr << item if item.interesting?
  end
  arr
end
# Returns: an array of interesting items.

Well, there are several things wrong with that example (and we will revisit this later), but the first is that useless local variable.

each_with_object(obj) { |item, obj| ... } takes an object and yields it along with each item.

It may seem obvious, but you will normally want a mutable object of some kind, though there are other use cases for this pattern.

def interesting_data
  data.each_with_object([]) do |item|
    arr << item if item.interesting?
  end
end
# Returns: the same array of interesting items as before.


The last each variation is reverse_each { |item| ... }, which is well labeled.

Keep in mind: the default implementation creates an array and then walks backward through the array yielding each item. This can be a little wasteful in terms of time/memory for large Enumerable objects. However, most common Enumerable classes like Array have an optimized version of this method that directly traverses the data structure.

%w(a b c).reverse_each { |item| puts item }
c
b
a


To read the rest of the series: click here