Ruby Blocks
You have seen how Ruby defines methods where you can place a number of statements and then you call that method. Similarly Ruby has a concept of Block.
Understanding Blocks:
blocks must follow a method invocation, either enclosed within braces ({ }) or within a do..end pair.
def method
...
end
method do ... end
method { ... }
Blocks are chunks of code.
Blocks remember their variable context, and are full closures
Blocks are invoked via yield and may be passed arguments.
Brace form has higher precedence and will bind to the last parameter if invocation made w/o parens.
do/end form has lower precedence and will bind to the invocation even without parens.
You can say blocks have names. Block names are the same of the associated method.
Here you will learn to invoke a block by using a simple yield statement. You will also learn to use a yield statement with parameters for invoking a block. You will check the sample code with both types of yield statements.
The yield Statement:
Let's look at an example of the yield statement:
def test
puts "You are in the method"
yield
puts "You are again back to the method"
yield
end
test {puts "You are in the block"}
This will produce following result:
You are in the method
You are in the block
You are again back to the method
You are in the block
You also can pass parameters with the yield statement. Here is an example:
def test
yield 5
puts "You are in the method test"
yield 100
end
test {|i| puts "You are in the block #{i}"}
This will produce following result:
You are in the block 5
You are in the method test
You are in the block 100
Here the yield statement is written followed by parameters. You can even pass more than one parameter. In the block, you place a variable between two vertical lines (||) to accept the parameters. Therefore, in the preceding code, the yield 5 statement passes the value 5 as a parameter to the test block.
Now look at the following statement:
test {|i| puts "You are in the block #{i}"}
Here the value 5 is received in the variable i. Now observe the following puts statement:
puts "You are in the block #{i}"
The output of this puts statement is:
You are in the block 5
If you want to pass more than one parameters, then the yield statement becomes:
yield a, b
and the block is:
test {|a, b| statement}
The parameters will be separated by commas.
Blocks and Methods:
You have seen how how a block and a method can be associated with each other.You normally invoke a block by using the yield statement from a method that has the same name as that of the block. Therefore, you write:
def test
yield
end
test{ puts "Hello world"}
Notice: There is a loose association here. Methods don't have to have the same block passed to them each time.
This example is the simplest way to implement a block.You call the test block by using the yield statement.
But if the last argument of a method is preceded by &, then you can pass a block to this method and this block will be assigned to the last parameter. The &block annotation is optional, but if it is there, it should be the last argument listed in the method definition.
def test(&block)
block.call
end
test { puts "Hello World!"}
This will produce following result:
Hello World!
Putting it all together:
Let's see a final example:
def gang
yield "Gorana"
yield "Michael"
yield "Victor"
end
gang {|a|
puts "Hello, #{a}!"
}
This will produce following result:
Hello, Gorana!
Hello, Michael!
Hello, Victor!
Ruby Procs:
There is another kind of Ruby blocks: a Proc (short for procedure) is also a chunk of code, bound to a variable. As always in Ruby, a Proc is an object, and so can be created with the new method.
The code in the Proc object can be invoked by using the call method.
# A Proc can have one, none or many arguments
times7 = Proc.new {|n| n * 7 }
puts times7.call(3)
statement = Proc.new { 'from statement' }
puts statement.call
multiply3 = Proc.new {|x, y| x * y }
puts multiply3.call(3,5)
This will produce following result:
21
from statement
15
Another way to invoke a Proc is using the square brackets notation.
# Here are the equivalents:
puts times7[3]
puts statement[]
puts multiply3[3,5]
Another and generally preferable way to create a Proc is using the lambda method.
multiple = lambda {|x, y| x * y }
puts multiple[6,5]
This will produce following result:
30


