I'm learning ruby and while studding modules I found that for making Enumerable module methods accessible inside a class you should also provide a each method inside your class. I don't really understand why doing this is making enumerable methods work.
Also, i don't understand why i don't need to call the each method please be kind I'm just beginning to learn
class List
include Enumerable
def initialize (*list)
@list = *list
end
def each(&block)
@list.each(&block)
end
end
Mylist = List.new(1,2,3,4,5)
puts Mylist.any? {|num| num>2}
I'm planning to create my own Enumerable module whit some of the Enumerable methods and I think understanding this concept will help me on doing it.
CodePudding user response:
Module Enumerable
is designed such way
Every Enumerable
method uses each
method which yields successive members of the collection. That's why you just need implement it and include Enumerable
in your class
If you will use max
, min
, or sort
methods, you also need to implement <=>
method
CodePudding user response:
Think of each enumerable method as having as its first line enum = each
, which is the same as enum = self.each
.
For example, suppose an enumerable method is defined as follows.
module Enumerable
def reverse_em
enum = each
a = []
loop do
a.unshift(enum.next)
end
a
end
end
As each
in enum = each
has no explicit receiver the implicit receiver is used. In [1, 2, 3].reverse_em
, for example, the implicit receiver is [1, 2, 3]
so enum = each
evaluates to enum = [1, 2, 3].each #=> #<Enumerator: [1, 2, 3]:each>
, each
being an instance method of the class [1, 2, 3].class #=> Array
. Here enum.next #=> 1
, enum.next #=> 2
, enum.next #=> 3
, enum.next #=> StopIteration (an exception)
.
We may then write, for example:
[1, 2, 3].reverse_em
#=> [3, 2, 1]
{ a: 1, b: 2, c: 3 }.reverse_em
#=> [[:c, 3], [:b, 2], [:a, 1]]
(1..3).reverse_em
#=> [3, 2, 1]
require 'set'
st = [1, 2, 3].to_set
st.reverse_em
#=> [3, 2, 1]
As you see, a single Enumerable
method is used by instances of four different classes. This obviously is a superior design construct to defining reverse_em
for each of the four classes.
To implement this functionality each of the class definitions for Array
, Hash
, Range
and Set
(and other core classes) must have a statement include Enumerable
and must contain an instance method each
that returns an enumerator (Array#each, Hash#each, Range#each and Set#each).
Note that my method reverse_em
returns an array regardless of the receiver's class. That is the case with many if not all Emumerable
methods.
If follows that a user's custom class can make use of all of the methods in the Enumerable
module by including in the class definition the statement include Enumerable
and an instance method each
that returns an enumerator. Note that a few Enumerable
methods depend on methods other than each
that are to be provided by the class.