As a Ruby programmer, you probably know the &:
shortcut to call a method on each item in an array. For example, this snippet will call the to_s
method on :foo
and :bar
.
[:foo, :bar].each(&:to_s)
The above code is similar to:
[:foo, :bar].each do |item|
item.to_s
end
However, instead of calling a method on the array item, you want to call a method and pass the array item to that method. Is there a one-liner for that?
[:foo, :bar].each do |item|
puts(item)
end
It turns out, Ruby has a corresponding &method
shortcut to accomplish precisely this.
[:foo, :bar].each(&method(:puts))
Two things are going on here.
First, the method(:puts)
finds the method named puts
. As per the documentation, you can access the instance variables and self
method on whichever object you called method
on.
Looks up the named method as a receiver in obj, returning a
Method
object (or raisingNameError
). TheMethod
object acts as a closure in obj's object instance, so instance variables and the value ofself
remain available.
Second, the Method
object returned by the method
method (wow, that's one too many methods) implements the to_proc
method, so you can use it after &
, which is to say:
If
foo
is an object with ato_proc
method, then you can pass it to a method as&foo
, which will callfoo.to_proc
and use that as the method's block.
&method(:puts) # is equivalent to
{ |e| puts(e) }
&:name # is equivalent to
{ |e| e.name }
When you say &method(:puts)
, it finds the Method
object and calls .to_proc
on it.
array.each(&method(:foo))
is equivalent to,
array.each { |e| foo(e) }
Is It Worth It?
Now, does that mean you go ahead and replace the explicit method calls in each
loops with this one-liner? Probably not.
Sometimes, that explicit method call is just what you need to keep the code readable and easier to understand. Not just for your colleagues, but for the future you. Using this one-liner adds an extra mental overhead for your brain to translate and understand what it's doing, which is not worth in many cases.
However, sometimes this shortcut is precisely what you need to express what you meant. That's why I love Ruby. The freedom to choose, do, and say whatever you want, however you want, to write software, well.
Anyway, hope that helps.
Top comments (2)
Had no idea you could do this. Will definitely have to try it.
thank very much
array.each(&method(:foo))
didn´t know that one