Ruby: Blocks and Procs
Message from 2022
This post is pretty old! Opinions and technical information in it are almost certainly oudated. Commands and configurations will probably not work. Consider the age of the content before putting any of it into practice.
Ruby has two kinds of anonymous function: blocks, and procs.
- Block
-
A block is a syntactic element. The only things you can do with these are:
- pass them to methods as the “default block” argument
- in a method that’s been called with a default block,
yieldzero or more arguments to it, getting a result - in a method that’s been called with a default block, capture it into a
Procwith an ampersand in the arguments list
- Proc
-
A
Procis an object. You can do just about anything with it, including turn it back and forth from a block.</dd> </dl><h1>Developing with Blocks</h1>Using blocks with somebody else’s API is intuitive:
(1..5).map{|n| n * 3} #=> [3, 6, 9, 12, 15]Making an API that uses blocks can be easy too:
module Object def with yield self end end # calling "hello".with{|h| puts h} # prints "hello"If you
yieldmore than once, you run the block multiple times.Developing with Procs
How do you even make a
Proc?doubler = proc{|n| n * 2} #=> #<Proc:0x007f8e938d8618@(irb):1>There’s a few methods, like
proc, that turn a block into aProc.lambdais very similar. They’re easy to write:def my_proc(&block) block end tripler = my_proc{|n| n * 3} #=> #<Proc:0x007f8e9506d170@(irb):5>The ampersand in the argument list to
my_procis what transforms the block into aProc, and then we simply return it.You can use the ampersand to turn a
Procinto a block too:(1..5).map doubler # ArgumentError: wrong number of arguments(1 for 0) (1..5).map &doubler #=> [2, 4, 6, 8, 10]And you can call a
Procdirectly without having to turn it into a block too:doubler.call 4 #=> 8 doubler[5] #=> 10 doubler.(6) # the dot before the parentheses is significant #=> 12Blocks and
Procs can be confusing. I hope this helps!