Ответ 1
Начнем с более простого примера. Скажем, у нас есть массив строк, которые мы хотим иметь в шапках:
['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']
Кроме того, символ # to_proc еще более умный, поскольку он на самом деле делает следующее:
:whatever.to_proc # => proc { |obj, *args| obj.send(:whatever, *args) }
Это означает, что
[1, 2, 3].inject(&:+)
равно
[1, 2, 3].inject { |a, b| a + b }