tags:

views:

134

answers:

1

I've seen these several times but I can't figure out how to use them. The pickaxe says that these are special shortcuts but I wasn't able to find the syntactical description.

I've seen them in such contexts:

[1,2,3].inject(:+)

to calculate sum for example.

+11  A: 

Let's start with an easier example. Say we have an array of strings we want to have in caps:

['foo', 'bar', 'blah'].map { |e| e.upcase }
# => ['FOO', 'BAR', 'BLAH']

Also, you can create so called Proc objects (closures):

block = proc { |e| e.upcase }
block.call("foo") # => "FOO"

You can pass such a proc to a method with the & syntax:

block = proc { |e| e.upcase }
['foo', 'bar', 'blah'].map(&block)
# => ['FOO', 'BAR', 'BLAH']

What this does, is call to_proc on block and than calls that for every block:

some_object = Object.new
def some_object.to_proc; proc { |e| e.upcase } end
['foo', 'bar', 'blah'].map(&some_object)
# => ['FOO', 'BAR', 'BLAH']

Now, Rails first added the to_proc method to Symbol, which later has been added to the ruby core library:

:whatever.to_proc # => proc { |e| e.whatever }

Therefore you can do this:

['foo', 'bar', 'blah'].map(&:upcase)
# => ['FOO', 'BAR', 'BLAH']

Also, Symbol#to_proc is even smarter, as it actually does the following:

:whatever.to_proc # => proc { |obj, *args| obj.send(:whatever, *args) }

This means that

[1, 2, 3].inject(&:+)

equals

[1, 2, 3].inject { |a, b| a + b }
Konstantin Haase
banister
Konstantin Haase
@Konstantin: That's not ruby's definition of inject. inject does not call to_proc, it uses rb_funcall with the given symbol as the name of the method. See inject_op_i in enum.c.
sepp2k
Konstantin Haase