Давайте начнем с более простого примера.
Скажем, у нас есть массив строк, которые мы хотим иметь в прописных буквах:
['foo', 'bar', 'blah'].map { |e| e.upcase }
# => ['FOO', 'BAR', 'BLAH']
Также вы можете создавать так называемые объекты Proc (замыкания):
block = proc { |e| e.upcase }
block.call("foo") # => "FOO"
Вы можете передать такой процесс методу с синтаксисом &:
block = proc { |e| e.upcase }
['foo', 'bar', 'blah'].map(&block)
# => ['FOO', 'BAR', 'BLAH']
Для этого нужно вызвать to_proc для блока, а затем вызвать его для каждого блока:
some_object = Object.new
def some_object.to_proc
proc { |e| e.upcase }
end
['foo', 'bar', 'blah'].map(&some_object)
# => ['FOO', 'BAR', 'BLAH']
Теперь Rails сначала добавил метод to_proc в Symbol, который позже был добавлен в библиотеку ядра ruby:
:whatever.to_proc # => proc { |e| e.whatever }
Поэтому вы можете сделать это:
['foo', 'bar', 'blah'].map(&:upcase)
# => ['FOO', 'BAR', 'BLAH']
Кроме того, Symbol # to_proc еще умнее, поскольку фактически выполняет следующее:
:whatever.to_proc # => proc { |obj, *args| obj.send(:whatever, *args) }
Это означает, что
[1, 2, 3].inject(&:+)
равно
[1, 2, 3].inject { |a, b| a + b }