Unlike the language named after a certain serpent, Ruby embraces TMTOWTDI (pronounced as Tim Toady), or There’s more than one way to do it. The calling of Procs is a wonderful example. In fact, Ruby gives you four different ways:
Proc#call(args)
.(args)
Threequals
Lambdas
Fire up irb. Let’s begin by creating a very simple Proc:
| >> p = proc { |x, y| x + y } |
| => #<Proc:0x007ffb12907940@(irb):1> |
There are two things to notice here. First, the return value tells you that a Proc has been created. Second, Ruby provides a shorthand to create Procs. This is really a method in the Kernel class:
| >> p = Kernel.proc { |x, y| x + y } |
| => #<Proc:0x007ffb12907940@(irb):1> |
Of course, since Proc is just like any other class, you can create an instance of it the usual way:
| >> p = Proc.new { |x, y| x + y } |
| => #<Proc:0x007ffb12907940@(irb):1> |
Now you know how to create a Proc. Time to make it do some work. The first way is to use Proc#call(args):
| >> p = proc { |x,y| x + y } |
| |
| >> p.call("oh", "ai") |
| => "ohai" |
| |
| >> p.call(4, 2) |
| => 6 |
In fact, this is my preferred way of invoking Procs because it conveys the intent of invocation much better than the alternatives, which are presented next.
Ruby provides a shorthand for the call(args) method: .(args). Therefore, the previous example could have been rewritten as such:
| >> p = proc { |x,y| x + y } |
| >> p.("oh", "ai") |
| >> p.(4, 2) |
Here’s an interesting Ruby tidbit. Turns out, the .() syntax works across any class that implements the call method. For example, here’s a class with only the call method:
| class Carly |
| def call(who) |
| "call #{who}, maybe" |
| end |
| end |
| |
| c = Carly.new |
| c.("me") # => "call me, maybe" |
You should avoid using .() if you can, because this could potentially confuse other people who might not be familiar with the syntax.
Ruby has an even quirkier syntax for invoking Procs:
| p = proc { |x,y| x + y } |
| p === ["oh", "ai"] |
The === operator is also known as the threequals operator. This operator makes it possible to use a Proc in a case statement. Look at the following code:
| even = proc { |x| x % 2 == 0 } |
| case 11 |
| when even |
| "number is even" |
| else |
| "number is odd" |
| end |
Here, even, when given a number, returns true or false depending on the case statement. For example:
| >> even = proc { |x| x % 2 == 0 } |
| >> even === 11 |
| => false |
| >> even === 10 |
| => true |
Note that invoking a Proc that expects a single argument this way is incorrect and results in a confusing error message:
| >> even = proc { |x| x % 2 == 0 } |
| >> even === [11] |
| NoMethodError: undefined method `%' for [11]:Array |
| from (irb):1:in `block in irb_binding' |
Next, let’s look at lambdas and how they relate to Procs.
18.118.163.250