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's shorthand for tags.map(&:name.to_proc).join(' ')
If foo is an object with a to_proc method, then you can pass it to a method as &foo, which will call foo.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:
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
Another cool shorthand, unknown to many, is
array.each(&method(:foo))
which is a shorthand for
array.each { |element| foo(element) }
By calling method(:foo) we took a Method object from self that represents its foo method, and used the & to signify that it has a to_proc method that converts it into a Proc.
This is very useful when you want to do things point-free style. An example is to check if there is any string in an array that is equal to the string "foo". There is the conventional way:
["bar", "baz", "foo"].any? { |str| str == "foo" }
And there is the point-free way:
["bar", "baz", "foo"].any?(&"foo".method(:==))
The preferred way should be the most readable one.
It's equivalent to
def tag_names
@tag_names || tags.map { |tag| tag.name }.join(' ')
end
First, &:name is a shortcut for &:name.to_proc, where :name.to_proc returns a Proc (something that is similar, but not identical to a lambda) that when called with an object as (first) argument, calls the name method on that object.
Second, while & in def foo(&block) ... end converts a block passed to foo to a Proc, it does the opposite when applied to a Proc.
Thus, &:name.to_proc is a block that takes an object as argument and calls the name method on it, i. e. { |o| o.name }.
map(&:name) takes an enumerable object (tags in your case) and runs the name method for each element/tag, outputting each returned value from the method.
It is a shorthand for
array.map { |element| element.name }
which returns the array of element(tag) names
It basically execute the method call tag.name on each tags in the array.
It is a simplified ruby shorthand.
There isn't a &: operator in Ruby. What you are seeing is the & operator applied to a :symbol.
In a method argument list, the & operator takes its operand, converts it to a Proc object if it isn't already (by calling to_proc on it) and passes it to the method as if a block had been used.
my_proc = Proc.new { puts "foo" }
my_method_call(&my_proc) # is identical to: my_method_call { puts "foo" }