I found this code in a RailsCast:
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
What does the (&:name)
in map(&:name)
mean?
I found this code in a RailsCast:
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
What does the (&:name)
in map(&:name)
mean?
It is same as below:
It's equivalent to
It's shorthand for
tags.map { |tag| tag.name }.join(' ')
It's shorthand for
tags.map(&:name.to_proc).join(' ')
If
foo
is an object with ato_proc
method, then you can pass it to a method as&foo
, which will callfoo.to_proc
and use that as the method's block.The
Symbol#to_proc
method was originally added by ActiveSupport but has been integrated into Ruby 1.8.7. This is its implementation:Josh Lee's answer is almost correct except that the equivalent Ruby code should have been as follows.
not
With this code, when
print [[1,'a'],[2,'b'],[3,'c']].map(&:first)
is executed, Ruby splits the first input[1,'a']
into 1 and 'a' to giveobj
1 andargs*
'a' to cause an error as Fixnum object 1 does not have the method self (which is :first).When
[[1,'a'],[2,'b'],[3,'c']].map(&:first)
is executed;:first
is a Symbol object, so when&:first
is given to a map method as a parameter, Symbol#to_proc is invoked.map sends call message to :first.to_proc with parameter
[1,'a']
, e.g.,:first.to_proc.call([1,'a'])
is executed.to_proc procedure in Symbol class sends a send message to an array object (
[1,'a']
) with parameter (:first), e.g.,[1,'a'].send(:first)
is executed.iterates over the rest of the elements in
[[1,'a'],[2,'b'],[3,'c']]
object.This is the same as executing
[[1,'a'],[2,'b'],[3,'c']].map(|e| e.first)
expression.Two things are happening here, and it's important to understand both.
As described in other answers, the
Symbol#to_proc
method is being called.But the reason
to_proc
is being called on the symbol is because it's being passed tomap
as a block argument. Placing&
in front of an argument in a method call causes it to be passed this way. This is true for any Ruby method, not justmap
with symbols.The
Symbol
gets converted to aProc
because it's passed in as a block. We can show this by trying to pass a proc to.map
without the ampersand:Even though it doesn't need to be converted, the method won't know how to use it because it expects a block argument. Passing it with
&
gives.map
the block it expects.