What does map(&:name) mean in Ruby?

Viewed 145770

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?

17 Answers

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

It's shorthand for tags.map { |tag| tag.name }.join(' ')

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" }

Related