6

In Ruby, the Enumerable module mixes into collection classes and relies on the class serving up an each method which yields each item in the collection.

Okay, so if I want to use Enumerable in my own class, I'll just implement each [1]:

class Colors
  include Enumerable

  def each
    yield "red"
    yield "green"
    yield "blue"
  end
end

> c = Colors.new
> c.map { |i| i.reverse }
#=> ["der", "neerg", "eulb"]

That works as expected.

But if I override the each method on an existing class with Enumerable, it doesn't break functions like map. Why not?

class Array
  def each
    puts "Nothing here"
  end
end

> [1,2,3].each {|num| puts num }
#=> "Nothing here"
> [1,2,3].map {|num| num**2 }
#=> [1,4,9]

[1]: from http://www.sitepoint.com/guide-ruby-collections-iii-enumerable-enumerator/

Erik Trautman
  • 5,883
  • 2
  • 27
  • 35

1 Answers1

7

Enumerable's implementation of map does use each, but there's nothing stopping an extending class from overriding it with its own implementation that does not use each.

In this case Array does provide its own implementation of map for efficiency reasons.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
  • You can confirm this by running: `Colors.public_instance_methods(false).include?(:map)` and `Array.public_instance_methods(false).include?(:map)` – Nikola Aug 25 '14 at 02:13
  • If you want to use `Enumerable`'s `map` on an `Array`, you can do `Enumerable.public_instance_method(:map).bind([1, 2, 3]).() {|num| num**2 }`. – Jörg W Mittag Aug 25 '14 at 06:04