&:foo
may erroneously be seen as &:
plus foo
(terms like "pretzel colon" reinforce this mistaken view). But no method foo
is being called here. &:foo
is actually &
plus :foo
, the latter being a plain symbol.
When calling a method, &object
(without :
) invokes object.to_proc
(which is supposed to return a Proc
) and passes the returned proc as a block argument to the method.
object
often happens to be a symbol and Symbol#to_proc
's implementation would look somehow like this in Ruby: (it's actually written in C)
class Symbol
def to_proc
proc { |object, *args| object.public_send(self, *args) }
end
end
So this:
method(&:symbol)
effectively becomes this:
method { |object, *args| object.public_send(:symbol, *args) }
or, if method
doesn't yield multiple values (like map
), it's simply:
method { |object| object.public_send(:symbol) }
Obviously, you can't pass additional arguments via a symbol.
But ... object
doesn't have to be a symbol. You could use another class with a custom to_proc
implementation. Let's abuse Array
for demonstration purposes:
class Array
def to_proc
method, *args = self
proc { |obj| obj.public_send(method, *args) }
end
end
This hack would allow you to write:
["foo\nbar", "baz\nqux"].map(&[:gsub, "\n", '-'])
#=> ["foo-bar", "baz-qux"]