The Ruby Pretzel Colon is one of my favorite idioms. But it's salty goodness can be an acquired taste for new Ruby programmers. There seems to be an aversion to it's apparent magic. It is an unusual syntax. But it is easy to understand if you break it down into it's parts.
Here is an example of the pretzel colon:
# general style:
[person1, person2, person3].map { |person| person.name }
# pretzel style:
[person1, person2, person3].map(&:name)
The pretzel colon style &:
is more concise and focused and makes the perfect snack at the ball game.
Let's break down what is happening here. In the general style, the map
is iterating through the array and passing each person object to the block. The block is defined to take a single argument of a person, the block then calls person.name
and returns the name of the person.
Using pretzel style, the result is the same, but the block is built for us using the &
operator. The &
operator calls #to_proc
on the object then converts the result into a block. If our object was a lambda or Proc, they return self
in their default #to_proc
method. But in this case, our object is a Symbol.
The default implementation of #to_proc
on Symbol is to return a Proc that takes the first argument and sends
itself to the argument. Example pseudo code:
class Symbol
def to_proc
Proc.new { |object| object.send self }
end
end
The third act of a magic trick is called the Prestige. Using the default #to_proc
defined in Symbol
, combining it with &
which calls #to_proc
and converts the result into a block. We are building a block that takes the person object and sends the symbol to it. Sending :name
to person is the same as calling person.name
.
# expanded pretzel
[person1, person2, person3].map { |person| person.send :name }
The combination of the Ruby &
operator's ability to convert objects into blocks and the default implementation of Symbol's #to_proc
combine into a magic pretzel. This makes our code more concise and expressive.
A bit of history on the pretzel colon. This idiom started in Rails ActiveSupport but was eventually moved to Ruby Core. It was removed after Rails 2.3. The git history of the file shows "Marcel Molina authored on Nov 20, 2005". The pretzel colon is almost 10 years old.
see https://github.com/rails/rails/blob/2-3-stable/activesupport/lib/active_support/core_ext/symbol.rb