---
title: 'The `Enumerable` Module'
source: 'https://academia.sh/en/courses/ruby-fundamentals/the-enumerable-module'
course: 'Ruby Fundamentals'
language: en
updated: '2026-10-21T05:03:43+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Measures the owner of Enumerable methods with owner'
    - 'Gives your own class iteration methods with include Enumerable and a single each'
    - 'Reads the results of sort_by, group_by, min_by and tally'
    - 'Measures that a method of the same name can have different owners on an array, a range and a module'
---

# The `Enumerable` Module

The iteration methods an array does not define itself are measured as coming from the Enumerable module, your own class is given the same ability with a single each, and the module is shown not to take over every job.

The previous lesson showed that `map` on a hash is defined not in `Hash` but in the `Enumerable` module. This lesson looks at that module. A **module** is a collection of methods that is **mixed into** (`include`) a class; it does not produce objects by itself. M08 built the object-oriented foundations; here only the messages this module answers are measured.

This lesson's responder is the **module**. Arrays, ranges and hashes are different classes, but a shared module answers many of their iteration messages.

## The Messages the Module Answers

The first measurement sends the `each_slice` message to a range. The core classifies the result by looking at the method's owner: if the owner is a `Class`, the responder is a class; otherwise it is a module.

```ruby
# reply.rb — helpers that classify who answers a message

# Classification asks in order: is the expression a message at all (defined?),
# then do two different blocks give two different results, then who owns the method.
def responder(definition, owner: nil, result: nil, with_blocks: nil)
  return ["syntax", "defined? #{definition}"] unless definition == "method"

  if with_blocks
    first, second = with_blocks.call
    return ["block", "#{first.inspect} / #{second.inspect}"] unless first == second
  end

  kind = owner.instance_of?(Class) ? "class" : "module"
  [kind, "#{owner}, result #{result.inspect}"]
end
```

```ruby
# slice.rb — who answers the each_slice message
require_relative "reply"

range = (1..5)
owner = range.method(:each_slice).owner
result = range.each_slice(2).to_a
kind, evidence = responder(defined?(range.each_slice(2)), owner: owner, result: result)
puts "#{kind}  #{evidence}"
```
```
module  Enumerable, result [[1, 2], [3, 4], [5]]
```

This is the core's `slicing` observation: the **responder** is a **module**, and the owner is `Enumerable`. The `Range` class does not define `each_slice` itself; it is enough for a range to know how to hand out its elements with `each`. The module's other methods are in this lesson's second measurement.

```ruby
# tools.rb — Enumerable methods
fruits = %w[plum peach grape fig]
puts fruits.sort_by { |f| f.size }.first
puts fruits.group_by { |f| f.size }.inspect
puts fruits.min_by { |f| f.size }
puts %w[a b a].tally.inspect
puts (1..6).select(&:even?).inspect
```
```
fig
{4 => ["plum"], 5 => ["peach", "grape"], 3 => ["fig"]}
fig
{"a" => 2, "b" => 1}
[2, 4, 6]
```

`sort_by` put the shortest name first, `group_by` built a hash that groups the names by length, and `min_by` gave the shortest name. `tally` counted how many times each element appears. `select(&:even?)` picked the even numbers from the range.

## Mixing It into Your Own Class

The module's ability becomes a class's ability only once it is mixed into the class. The smallest form: the class defines only `each` and says `include Enumerable`. Class design is the subject of M08; here the class is built in its smallest form just for the measurement.

```ruby
# numbers.rb — mixing Enumerable into our own class
class Numbers
  include Enumerable

  def each
    yield 3
    yield 1
    yield 2
  end
end

numbers = Numbers.new
puts numbers.map { |n| n * 2 }.inspect
puts numbers.sort.inspect
puts numbers.min_by { |n| -n }
puts "map=#{numbers.method(:map).owner} each=#{numbers.method(:each).owner}"
puts numbers.to_a.inspect
puts numbers.include?(2)
puts numbers.first
puts numbers.reduce(:+)
puts numbers.each_with_index.to_a.inspect
puts numbers.is_a?(Enumerable)
```
```
[6, 2, 4]
[1, 2, 3]
3
map=Enumerable each=Numbers
[3, 1, 2]
true
3
6
[[3, 0], [1, 1], [2, 2]]
true
```

The class wrote only `each`; `map`, `sort` and `min_by` arrived without any extra definition. `min_by { -n }` gave the largest number, because the one with the smallest negative value is `3`. The fourth line shows the sharing: the owner of `map` is `Enumerable`, and the owner of `each` is the `Numbers` class. `to_a` collected the elements in the order `each` yielded them: `[3, 1, 2]`. `include?`, `first` and `reduce` also rested on the same single `each`; `reduce(:+)` summed the elements and gave `6`. `each_with_index` attached an index to each element. The last line confirms that instances of the class are recognized as `Enumerable`. The class did not define `<=>`, because `sort` here compares numbers with the numbers' own comparison; comparing the class's instances with each other is a separate job. **CB8.** This class yields three values with `each`; if `each` produced an endless sequence, methods that read everything, such as `sort`, would never finish, but that behavior is not measured here.

## The Types the Module Returns

The module's methods return particular types regardless of the receiver's type. This is a contract the module gives its users: when you send the same message to a range, an array or your own class, you know the result type without looking at the receiver.

```ruby
# types.rb — types returned by Enumerable methods
range = (1..3)
puts range.map { |n| n }.class
puts range.select { |n| n > 1 }.class
puts range.group_by { |n| n.odd? }.class
puts range.tally.class
puts range.each_slice(2).class
puts range.min_by { |n| -n }.class
```
```
Array
Array
Hash
Hash
Enumerator
Integer
```

`map` and `select` returned arrays, `group_by` and `tally` returned hashes; `each_slice` without a block gave an iterator, and `min_by` gave a single element. The range was the receiver here, but the result types depend on the module's definition, not on the range. The `Hash#select` example in the Arrays and Hashes lesson shows the limit of this: there the class's own definition had returned a hash. **CB9.** This table was measured only with a range receiver; that the same methods return the same types on your own class has been seen for `map` in the `Numbers` measurement above, and is not assumed for the others.

## Chained Methods

The real strength of `Enumerable` is that small methods connect to each other. The measurement below runs five methods on a range and prints the owner of each next to it.

```ruby
# chain.rb — the result and owner of each method
s = (1..4)
puts "each_with_object=#{s.each_with_object([]) { |n, a| a << n * n }.inspect} owner=#{s.method(:each_with_object).owner}"
puts "inject=#{s.inject(:+)} reduce=#{s.reduce(1) { |a, n| a * n }} owner=#{s.method(:inject).owner}"
puts "zip=#{s.zip(%w[a b c d]).inspect} owner=#{s.method(:zip).owner}"
puts "partition=#{s.partition(&:even?).inspect} owner=#{s.method(:partition).owner}"
puts "each_cons=#{s.each_cons(2).to_a.inspect} owner=#{s.method(:each_cons).owner}"
```
```
each_with_object=[1, 4, 9, 16] owner=Enumerable
inject=10 reduce=24 owner=Enumerable
zip=[[1, "a"], [2, "b"], [3, "c"], [4, "d"]] owner=Enumerable
partition=[[2, 4], [1, 3]] owner=Enumerable
each_cons=[[1, 2], [2, 3], [3, 4]] owner=Enumerable
```

`each_with_object` carried an empty array along and collected the squares. `inject(:+)` gave the sum and `reduce(1) { ... }` gave the product; the owner of `inject` was printed as `Enumerable`. `zip` paired two sequences, `partition` split the elements into two arrays by whether the block was true, and `each_cons(2)` gave consecutive pairs. In all five, the printed owner was `Enumerable`: even though `Range` defines its own `each`, the responder for this chain is the module. **CB27.** The owner measurement was made only with a `Range` receiver; the owner of `reduce` was not printed separately.

## The Lazy Chain

A `lazy` chain does not run immediately; it produces only as many elements as the result asks for. That is why `select` and `first(3)` can finish on an endless range. `with_index` attaches an index to the elements, and the first index can be given.

```ruby
# lazy.rb — a lazy chain and with_index
puts (1..Float::INFINITY).lazy.select(&:even?).first(3).inspect
puts (1..3).lazy.class
puts "lazy owner=#{(1..3).method(:lazy).owner}"
puts %w[a b].each.with_index(1).to_a.inspect
puts %w[a b].map.with_index { |h, i| "#{i}#{h}" }.inspect
```
```
[2, 4, 6]
Enumerator::Lazy
lazy owner=Enumerable
[["a", 1], ["b", 2]]
["0a", "1b"]
```

On the endless range, `first(3)` stopped after finding the first three even numbers and gave `[2, 4, 6]`. `Enumerable` answered the `lazy` message, and the class of the returned object was `Enumerator::Lazy`. `each.with_index(1)` started the index at one; `map.with_index` handed the index to the block along with the element and produced the transformed array. **CB28.** Only these three chains were measured.

## An External Iterator

`each` called without a block returns an iterator; `next` advances it by hand. When the elements run out, `StopIteration` is raised.

```ruby
# external_iterator.rb — advancing by hand with next
e = [1, 2, 3].each
puts e.next
puts e.next
puts e.next
result = begin
  e.next
rescue StopIteration
  "done"
end
puts result
puts e.size
```
```
1
2
3
done
3
```

Three `next` calls gave the elements in order. The fourth call raised `StopIteration`, `rescue` caught it and `done` was printed. `size` returned `3`. **CB29.** `size` was measured only in this example; iterators whose size is not known in advance were not measured.

## Methods Coming from the Mixin

When your own class defines only `each` and mixes in `Enumerable`, it gains dozens of methods. The `Box` class below keeps its elements in an array and delegates to the array's `each` inside its own `each`. Then nine different methods are called.

```ruby
# box.rb — a class that defines only each
class Box
  include Enumerable

  def initialize(*items)
    @items = items
  end

  def each(&block)
    @items.each(&block)
    self
  end
end

k = Box.new(3, 1, 2)
puts "sort=#{k.sort.inspect} owner=#{k.method(:sort).owner}"
puts "min=#{k.min} max=#{k.max} sum=#{k.sum}"
puts "map=#{k.map { |n| n * 2 }.inspect}"
puts "each_slice=#{k.each_slice(2).to_a.inspect}"
puts "first=#{k.first} count=#{k.count} sort_by=#{k.sort_by { |n| -n }.inspect}"
puts "each owner=#{k.method(:each).owner}"
```
```
sort=[1, 2, 3] owner=Enumerable
min=1 max=3 sum=6
map=[6, 2, 4]
each_slice=[[3, 1], [2]]
first=3 count=3 sort_by=[3, 2, 1]
each owner=Box
```

`Box` defined only `each`; the owner of `sort` was printed as `Enumerable`. `min`, `max`, `sum`, `map`, `each_slice`, `first`, `count` and `sort_by` all worked through `each` and gave the expected results. The responder is the module; the owner of `each` is `Box`. The module learns how to reach the elements from the class. **CB42.** Only these nine methods were tried; it is not assumed that every method of the mixin works.

## Without an each

The module does not provide `each` itself; the class must define it. A class that does not define `each` accepts the mixin, but the methods do not work.

```ruby
# empty.rb — a class that does not define each
class Empty
  include Enumerable
end

result = begin
  Empty.new.map { |x| x }
rescue NoMethodError => error
  error.class
end
puts result
puts Empty.new.respond_to?(:each)
```
```
NoMethodError
false
```

The `Empty` class mixed in `Enumerable` but did not define `each`. The `map` call raised `NoMethodError` and `respond_to?(:each)` gave `false`. The contract runs one way: `Enumerable` methods assume that the class's `each` method can be called. **CB43.** The error message was not printed; only its class was measured.

## Query Methods and Their Owners

`any?`, `all?`, `none?`, `find` and `take_while` query the collection. On an array, do all of these methods come from `Enumerable`? The owner line measures this.

```ruby
# queries.rb — query methods and their owners
s = [1, 2, 3, 4]
puts "any=#{s.any? { |n| n > 3 }} all=#{s.all?(Integer)} none=#{s.none?(&:zero?)}"
puts "find=#{s.find { |n| n > 2 }} take_while=#{s.take_while { |n| n < 3 }.inspect}"
puts "owner=#{s.method(:take_while).owner} #{s.method(:find).owner} #{s.method(:any?).owner}"
```
```
any=true all=true none=true
find=3 take_while=[1, 2]
owner=Array Array Array
```

The query results are as expected: `any?`, `all?(Integer)` and `none?(&:zero?)` were true, `find` gave `3` and `take_while` gave `[1, 2]`. The owner of all three methods was printed as `Array`: the array defines these methods itself instead of leaving them to `Enumerable`. In the previous section the owner of `sort` for `Box` was `Enumerable`; so the responder depends on the receiver's class. **CB44.** The measurement was made on Ruby 4.0.7 and only with an `Array` receiver.

## Other Methods from the Mixin

The methods that come with the mixin are not limited to summing and sorting. `minmax`, which gives the smallest and the largest together, `min(2)`, which gives the first `n` smallest, `each_with_index`, which passes the index along, lazy chains and reverse traversal all rest on `each` too. The `Shelf` class below again defines only `each`.

```ruby
# shelf.rb — a second class that defines each, and more methods
class Shelf
  include Enumerable

  def initialize(*items)
    @items = items
  end

  def each(&block) = @items.each(&block)
end

r = Shelf.new(4, 2, 9)
puts r.minmax.inspect
puts r.min(2).inspect
puts r.each_with_index.map { |n, i| n * i }.inspect
puts r.lazy.map { |n| n + 1 }.first(2).inspect
puts r.entries.inspect
puts r.reverse_each.to_a.inspect
```
```
[2, 9]
[2, 4]
[0, 2, 18]
[5, 3]
[4, 2, 9]
[9, 2, 4]
```

`minmax` gave `[2, 9]` and `min(2)` gave `[2, 4]`. `each_with_index.map` multiplied each element by its index: `[0, 2, 18]`. `lazy.map { ... }.first(2)` transformed only the first two elements: `[5, 3]`. `entries` gave the elements in insertion order and `reverse_each` in reverse. In none of the six calls did `Shelf` define a new method; all derived from `each`. **CB52.** The owners of these methods were not printed; only their results were measured.

## Comparable for Sorting

`sort` compares elements with `<=>`. Objects that do not know this comparison cannot be sorted. A class that defines `<=>` and mixes in `Comparable` gains `sort`, `min` and operators such as `<`.

```ruby
# compare.rb — comparable and sort
class Thing; end
result = begin
  [Thing.new, Thing.new].sort
rescue ArgumentError => error
  error.class
end
puts result

class Label
  include Comparable
  attr_reader :length

  def initialize(length)
    @length = length
  end

  def <=>(other) = length <=> other.length
end

puts [Label.new(3), Label.new(1)].sort.map(&:length).inspect
puts [Label.new(3), Label.new(1)].min.length
puts Label.new(1) < Label.new(2)
puts "owner=#{Label.new(1).method(:<).owner}"
```
```
ArgumentError
[1, 3]
1
true
owner=Comparable
```

Two `Thing` objects without a `<=>` definition could not be sorted: `sort` raised `ArgumentError`. `Label` defined only `<=>` and mixed in `Comparable`; `sort` gave `[1, 3]` and `min` gave `1`. The `<` operator worked too, and the owner of `<` was printed as `Comparable`. The module answers the operator; the class only supplied the comparison rule. **CB53.** The measurement was made with a single field.

## The Bounding Measurement

The module does not take over every job. A method of the same name can come from a different owner on different receivers: if the class wrote its own definition, that definition answers.

```ruby
# owners.rb — the same name, different owners
puts "(1..3).sum   #{(1..3).method(:sum).owner}"
puts "[3, 1].sum   #{[3, 1].method(:sum).owner}"
puts "[1].sort_by  #{[1].method(:sort_by).owner}"
puts "[3, 1].sort  #{[3, 1].method(:sort).owner}"
puts "[3, 1].min   #{[3, 1].method(:min).owner}"
puts "(1..3).min   #{(1..3).method(:min).owner}"
```
```
(1..3).sum   Enumerable
[3, 1].sum   Array
[1].sort_by  Enumerable
[3, 1].sort  Array
[3, 1].min   Array
(1..3).min   Range
```

`sum` comes from `Enumerable` on a range and from `Array` on an array. `sort_by` belongs to `Enumerable` on an array too, but `sort` and `min` are `Array`'s own methods on an array. For a range, `min` is `Range`'s own method. The results belong to Ruby 4.0.7. The six lines gave three different owners: `Enumerable`, `Array` and `Range`. The names `sum` and `min` work on both receivers and the caller sees no difference, but a class or a module answers the message depending on the receiver. So the `owner` question starts from the receiver's type, not from the method's name. **CB10.** None of the six lines compares the value of the result; only the owner is asked, so this measurement does not say whether the module and the class give the same result. In other words, the same name is the module's answer or the class's answer depending on the receiver; the reason for this is the subject of a later course and is not explained here.

## Summary

- `Enumerable` is a module that gives every class defining `each` methods such as `map`, `sort`, `min_by`, `group_by` and `tally`.
- This lesson's responder is the **module**: the `(1..5).each_slice(2)` message is answered by `Enumerable`, not by `Range`.
- Adding `include Enumerable` and a single `each` to your own class is enough; the owner of `map` turns out to be the module and the owner of `each` the class.
- The bounding measurement: the same name comes from a different owner depending on the receiver; `sum` comes from the module on a range and from `Array` on an array.

## Next Step

In this lesson a method's body called the block with `yield`. The next lesson turns the block into an object: `Proc` and lambda are two ways of keeping the same code in a variable, and the owner of the `call` message is the same for both.
