I found an interesting but unexplained alternative to an accepted answer. The code clearly works in the REPL. For example:
module
The first thing to know is that:
&
calls to_proc
on the object succeeding it and uses the proc produced as the methods' block.
Now you have to drill down to how exactly the to_proc
method is implemented in a specific class.
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
Or something like this. From the above code you clearly see that the proc produced calls the method (with name == the symbol) on the object and passes the arguments to the method. For a quick example:
[1,2,3].reduce(&:+)
#=> 6
which does exactly that. It executes like this:
:+.to_proc
and gets a proc object back => #
reduce
method, thus instead of calling [1,2,3].reduce { |el1, el2| el1 + el2 }
it calls[1,2,3].reduce { |el1, el2| el1.send(:+, el2) }
. class Method
def to_proc
Proc.new do |*args|
self.call(*args)
end
end
end
Which as you can see it has a different implementation of Symbol#to_proc
. To illustrate this consider again the reduce
example, but now let as see how it uses a method instead:
def add(x, y); x + y end
my_proc = method(:add)
[1,2,3].reduce(&my_proc)
#=> 6
In the above example is calling [1,2,3].reduce { |el1, el2| my_proc(el1, el2) }
.
Now on why the map
method returns an Array instead of an Enumerator is because you are passing it a block, try this instead:
[1,2,3].map.class
#=> Enumerator
Last but not least the grep
on an Array is selecting the elements that are ===
to its argument. Hope this clarifies your concerns.