Elsewhere > Convert a Ruby Method to a Lambda
Posted 2011-04-26 on viget.com
Last week I tweeted:
Convert a method to a lambda in Ruby: lambda(&method(:events_path)). OR JUST USE JAVASCRIPT.
It might not be clear what I was talking about or why it would be useful, so allow me to elaborate. Say you’ve got the following bit of Javascript:
var ytmnd = function() {
alert("you're the man now " + (arguments[0] || "dog"));
};
Calling ytmnd()
gets us you're the man now dog
, while
ytmnd("david")
yields you're the man now david
. Calling simply
ytmnd
gives us a reference to the function that we’re free to pass
around and call at a later time. Consider now the following Ruby code:
def ytmnd(name = "dog")
puts "you're the man now #{name}"
end
First, aren’t default argument values and string interpolation awesome?
Love you, Ruby. Just as with our Javascript function, calling ytmnd()
prints “you’re the man now dog”, and ytmnd("david")
also works as
you’d expect. But. BUT. Running ytmnd
returns not a reference to the
method, but rather calls it outright, leaving you with nothing but Sean
Connery’s timeless words.
To duplicate Javascript’s behavior, you can convert the method to a
lambda with sean = lambda(&method(:ytmnd))
. Now you’ve got something
you can call with sean.call
or sean.call("david")
and pass around
with sean
.
BUT WAIT. Everything in Ruby is an object, even methods. And as it turns
out, a method object behaves very much like a lambda. So rather than
saying sean = lambda(&method(:ytmnd))
, you can simply say
sean = method(:ytmnd)
, and then call it as if it were a lambda with
.call
or []
. Big ups to
Justin for that knowledge
bomb.
WHOOOO CARES
All contrivances aside, there are real-life instances where you’d want
to take advantage of this language feature. Imagine a Rails partial that
renders a list of filtered links for a given model. How would you tell
the partial where to send the links? You could pass in a string and use
old-school :action
and :controller
params or use eval
(yuck). You
could create the lambda the long way with something like
:base_url => lambda { |*args| articles_path(*args) }
, but using
method(:articles_path)
accomplishes the same thing with much less line
noise.
I’m not sure it would have ever occurred to me to do something like this before I got into Javascript. Just goes to show that if you want to get better as a Rubyist, a great place to start is with a different language entirely.