When iterating over arrays, there's one piece of shorthand that I find myself using again and again. It's the &: trick, aka the "ampersand colon" or "pretzel colon". In case you're not familiar with it, here's how it works:
words = ["would", "you", "like", "to", "play", "a", "game?"]
# this...
words.map &:length
# ..is equivalent to this:
words.map { |w| w.length }
Until recently, I had assumed that the &: syntax was an operator. But it's not. It's a clever hack that started out in ActiveSupport and became an official feature in Ruby 1.8.7.
The & operator
In addition to being used for AND logic operations, the "&" character has another use in Ruby. When added to the beginning of a method argument, it calls to_proc on its operand and passes it in as a block. That's a mouthful. It's much simpler to see the example:
def my_method(&block)
block.call
end
class Greeter
def self.to_proc
Proc.new { "hello" }
end
end
my_method(&Greeter) # returns "hello"
Symbol#to_proc
You can add a to_proc method to any object, including Symbol. That's exactly what ruby does to allow for the &: shortcut. It looks something like this:
class Symbol
def to_proc
Proc.new do |item|
item.send self
end
end
end
Clear as mud? The important part is item.send(self). Self, in this case refers to the symbol.
Putting it all together
Enumberable methods like each and map accept a block. For each item they call the block and pass it a reference to the item. The block in this case is generated by calling to_proc on the symbol.
# &:name evaluates to a Proc, which does item.send(:name)
items.map(&:name)
The interesting thing about this is that map doesn't know any of this is going on! The bulk of the work is being done by the :name symbol. It's definitely clever...almost too clever for my taste. But it's been a part of Ruby's standard library for years at this point, and it's so handy I doubt I'll stop using it for now. :)