Blocks
From RubySpec
A code block in Ruby is an executable grouping of statements allowing you to pass code to other methods or save it for later use. They behave much like lambda, closures, and/or callbacks in other languages.
Contents |
Block Syntax
A block is a set of statements and expressions between braces or a do/end pair. The block can start with an argument list in vertical bars. A code block may appear only directly after a method invocation. The start of the block must be on the same logical line as the end of the invocation.
Braces have high precedence; do has low precedence. There's a convention on Ruby community that braces are used for one-liner blocks when do/end pairs are used for multiline blocks. If the method invocation contains parameters that are not enclosed in parentheses, the brace form of a block will bind to the last parameter, not to the overall invocation. The do form will bind to the invocation.
# do/end: invocation do | a1, a2 | end # braces: invocation { | a1, a2 | } # will bind block to param1, probably not intended invocation param1 { | a1, a2 | } # this bind to the correct invocation invocation param1 do | a1, a2 | end
Within the body of the invoked method, the code block can be called using the yield keyword. Parameters passed to the yield will be assigned to the arguments in the block. A warning will be generated if yield passes multiple parameters to a block that takes just one. The return value of the yield is the value of the last expression evaluated in the block or the value passed to a next statement executed in the block.
A block is a closure; it remembers the context in which it was defined and it uses that context whenever it is called. The context includes the value of self, the constants, class variables, local variables and any captured block.
class Holder CONST = 100 def call_block a = 101 @a = 102 @@a = 103 yield end end class Creator CONST = 0 def create_block a = 1 @a = 2 @@a = 3 proc do puts "a = #{a}" puts "@a = #@a" puts "@@a = #@@a" puts yield end end end block = Creator.new.create_block { "original" } Holder.new.call_block(&block)
This produces:
a = 1 @a = 2 @@a = 3 original
Proc Objects
Ruby blocks are not objects per se, but can be converted into objects of class Proc. There are three ways of converting a block into a Proc object.
1. By passing a block to a method whose last parameter is prefixed with an ampersand. That parameter will receive the block as a Proc object.
def meth1(p1, p2, &block) puts block.inspect end meth1(1,2) { "a block" } meth1(3,4)
produces
#<Proc:0x028e75f8@block3.rb:4> nil
2. By calling Proc.new, again associating it with a block.
block = Proc.new { "a block" } block → #<Proc:0x028e77f0@block4.rb:1>
3. By calling the method Kernel.lambda (or the equivalent, mildly deprecated method Kernel.proc), associating a block with the call.
block = lambda { "a block" }
block → #<Proc:0x028e77f0@block5.rb:1>
The first two Proc objects are identical in use. These objects can be referred to as raw procs. The objects generated by the lambda keyword adds some additional functionality, though.
break, return, and next
Executing next within a block causes it to exit. The value resulting from the block invocation is the values passed to next, or nil if no such values are passed.
Within a block, break and return have mostly the same semantics. In a raw proc they will terminate the scope that yielded to the block, provided that this scope is still valid. Otherwise either a "break from proc-closure" or "unexpected return" LocalJumpError will be raised.
Within a block created by Kernel.lambda or Kernel.proc, a break or return will simply return from the block with the values provided.
For this reason, if you should use Module#define_method, you should pass it a proc created using lambda instead of Proc.new, to get natural return-semantics.
Block parameters
The parameters to blocks works differently based on which kind of naming is used. There are several ways to set variables outside the scope of the block by using different parameter names:
$var1 = "foo" class A def initialize @var2 = "bar" end def test_block var3 = [] var4 = {} 1.upto(1) {|var0| } #local variable established 1.upto(1) {|$var1| } #sets global variable puts $var1 1.upto(1) {|@var2| } #sets instance variable puts @var2 1.upto(1) {|var3[0]| } #sets array value p var3 1.upto(1) {|var4[:test]| } #sets hash value p var4 1.upto(1) {|self.var5| } #calls method var5= end def var5=(val) puts "setting var5 to #{val}" end end A.new.test_block
This will produce:
1
1
[1]
{:test=>1}
setting var5 to 1
These versions aren't that useful since you can accomplish the same thing with an explicit assignment:
$val = 0 1.upto(1) {|v| $val = v }
and this is much more readable.
Another reason for not using these exotic versions of parameters passing is that not all Ruby implementations support them at present, and Ruby 1.9/2.0 will support only using local variables as block parameters.
Module_eval and blocks
One thing to be careful with is the scoping rules when establishing constants. There are some situations where module_eval behaves differently depending on if it's given a block or a string:
class A FOO = "baz" end class B end B.module_eval do FOO = "bar" end B.module_eval("BAS = 'bar'") p A.constants p B.constants
this results in the somewhat counterintuitive output
["FOO"] ["BAS"]
since in the first B.module_eval, the FOO-constant is created at load-time, in the scope where the block is created, which is at top-level.
Note: this behavior is due to Ruby 1.8 determining constant scoping at parse/compile time. Ruby 2.0 is supposed to fix this, so that the constants above would be scoped within the modules in which they are evaluated.

