module Enumerable

What’s Here

Module Enumerable provides methods that are useful to a collection class for:

Methods for Querying

These methods return information about the Enumerable other than the elements themselves:

Methods for Fetching

These methods return entries from the Enumerable, without modifying it:

Leading, trailing, or all elements:

Minimum and maximum value elements:

Groups, slices, and partitions:

Methods for Searching and Filtering

These methods return elements that meet a specified criterion:

Methods for Sorting

These methods return elements in sorted order:

Methods for Iterating

Other Methods

Usage

To use module Enumerable in a collection class:

Example:

class Foo
  include Enumerable
  def each
    yield 1
    yield 1, 2
    yield
  end
end
Foo.new.each_entry{ |element| p element }

Output:

1
[1, 2]
nil

Enumerable in Ruby Classes

These Ruby core classes include (or extend) Enumerable:

These Ruby standard library classes include Enumerable:

Virtually all methods in Enumerable call method #each in the including class:

About the Examples

The example code snippets for the Enumerable methods:

Extended Methods

A Enumerable class may define extended methods. This section describes the standard behavior of extension methods for reference purposes.

#size

Enumerator has a #size method. It uses the size function argument passed to Enumerator.new.

e = Enumerator.new(-> { 3 }) {|y| p y; y.yield :a; y.yield :b; y.yield :c; :z }
p e.size #=> 3
p e.next #=> :a
p e.next #=> :b
p e.next #=> :c
begin
  e.next
rescue StopIteration
  p $!.result #=> :z
end

The result of the size function should represent the number of iterations (i.e., the number of times Enumerator::Yielder#yield is called). In the above example, the block calls #yield three times, and the size function, +-> { 3 }+, returns 3 accordingly. The result of the size function can be an integer, Float::INFINITY, or nil. An integer means the exact number of times #yield will be called, as shown above. Float::INFINITY indicates an infinite number of #yield calls. nil means the number of #yield calls is difficult or impossible to determine.

Many iteration methods return an Enumerator object with an appropriate size function if no block is given.

Examples:

["a", "b", "c"].each.size #=> 3
{a: "x", b: "y", c: "z"}.each.size #=> 3
(0..20).to_a.permutation.size #=> 51090942171709440000
loop.size #=> Float::INFINITY
(1..100).drop_while.size #=> nil  # size depends on the block's behavior
STDIN.each.size #=> nil # cannot be computed without consuming input
File.open("/etc/resolv.conf").each.size #=> nil # cannot be computed without reading the file

The behavior of #size for Range-based enumerators depends on the #begin element:

Examples:

(10..42).each.size #=> 33
(10..42.9).each.size #=> 33 (the #end element may be a non-integer numeric)
(10..).each.size #=> Float::INFINITY
("a".."z").each.size #=> nil
("a"..).each.size #=> nil
(1.0..9.0).each.size # raises TypeError (Float does not have #succ)
(..10).each.size # raises TypeError (beginless range has nil as its #begin)

The Enumerable module itself does not define a #size method. A class that includes Enumerable may define its own #size method. It is recommended that such a #size method be consistent with Enumerator#size.

Array and Hash implement #size and return values consistent with Enumerator#size. IO and Dir do not define #size, which is also consistent because the corresponding enumerator’s size function returns nil.

However, it is not strictly required for a class’s #size method to match Enumerator#size. For example, File#size returns the number of bytes in the file, not the number of lines.