the beginning of a beautiful friendship

written by sam on September 12th, 2008 @ 06:45 PM

Ruby, with ActiveSupport

1
2
3
4
5

my_various_objects = [ "My", 3, { :assertions => 'are' }, true ]

my_various_objects.collect(&:class)
# => [ String, Fixnum, Hash, TrueClass ]

Read it as : "Collect the class of my various objects please", beautiful he :)

Now let's get back to standard Ruby

collect in Ruby takes a block and returns the array made with the results of the block call on each entry in the Enumerable object. However, Ruby distinguish arguments and block in a method call. This means the following is wrong :

1
2
3
4
5

my_proc = lambda { |x| x.class }

my_various_objects.collect(my_proc)
# => ArgumentError: wrong number of arguments (1 for 0)
Because collect doesn't expect an argument but a block. What we wanted to do is :
1
2
3
4
5
6
7
8
9

my_various_objects.collect { |x| x.class }
# => [ String, Fixnum, Hash, TrueClass ]

# or
my_various_objects.collect do |x| 
  x.class 
end
# which is the same...
But what we have in Ruby is & :
1
2
3

my_various_objects.collect(&my_proc)
# => [ String, Fixnum, Hash, TrueClass ]

The ampersand prefix I used in the first snippet is a way to give a Proc object (made with lambda or Proc.new, even if they are differences) as a block in a method call.
Well, not exactly a Proc objet, in fact & sends to_proc on any object, which should convert this object to a Proc (if someone as implemented it in the object's class of course) and then give it as a block to the method.
Calling to_proc on an instance of Proc simply returns the instance, so anything special happens, but what happens in the first example ?
:class is a symbol, so &:class will send to_proc to the symbol, and give the block to collect.

Javascript, with Prototype

1
2
3

[ "My", 3, { assertions: 'are' }, true ].pluck('constructor');
// => [ String(), Number(), Object(), Boolean() ]

Read it as : "Collect the class of my various objects please", beautiful he :)

Post a comment

Options:

Size

Colors