Reputation: 43
I found this sample code that realizes custom Symbol#to_proc in Ruby:
class Symbol
def to_proc
puts "In the new Symbol#to_proc!"
Proc.new { |obj| obj.send(self) }
end
end
It includes additional "puts ..." string to ensure it is not built-in method. When I execute code
p %w{ david black }.map(&:capitalize)
the result is:
In the new Symbol#to_proc!
["David", "Black"]
But why it is not something like this?
In the new Symbol#to_proc!
["David"]
In the new Symbol#to_proc!
["Black"]
My logic is like this: map yields elements one by one to block. Block takes first element and executes .to_proc, than second. But why puts executes once only?
Upvotes: 3
Views: 91
Reputation: 3197
In Ruby, map works with a block. The &
operator calls to_proc
on object following it and passes the value returned from calling to_proc
to map as a block
. With this information, let's look at your example again. In your example, &:capitalize
will result in a call to to_proc
method on :capitalize
. Since, :capitalize
is a Symbol, it will call to_proc
on Symbol class, re-defined by you.
:capitalize.to_proc
will return:
In the new Symbol#to_proc!
=> #<Proc:0x007fa08183df28@(irb):4>
The &
operator will use the returned Proc object, and pass that proc object to map as a block. In your re-defined to_proc
method definition, puts
is just getting executed and since puts
prints to the console (assuming you are running this in console), you will see it printed. It's never passed to map, so you never see it printed twice.
However, if you would like the behaviour that you expect, use the first answer. Hope it helps.
Upvotes: 3
Reputation: 211610
The to_proc
method is called once to return a Proc object that is then used repeatedly, so you're seeing the correct behavior.
If you moved the puts inside, you'd see what you're expecting:
class Symbol
def to_proc
Proc.new { |obj|
puts "In the new Symbol#to_proc!"
obj.send(self)
}
end
end
Upvotes: 6