Learn Ruby and rails from rails guru
Posts tagged blocks
Learn Ruby – Procs, Blocks, Lambda
Mar 12th
Procs and Blocs is the part of Ruby which is not clear to many. This post should help you clear your doubts about Procs and Blocks.
Procs
Like variables hold data, procs hold the code itself.
Procs are first class objects of ruby with class Proc
We define a Proc as follows:
#or
my_proc = Proc.new do
puts “I am a Proc”
end
The first syntax is generally used for one liner Procs and the second one for multiline procs. Though there will be no errors if you do the other way, it is a good convention to follow.
Executing a Proc
To execute the Proc we do
Procs can accept parameters:
#single parameter, single line proc
print_name = Proc.new{|name| puts “my name is #{name}”}
print_name.call(“pankaj”) # “my name is pankaj”
#multiple parameters, single line proc
print_full_name = Proc.new{|first_name,last_name| puts "My name is #{first_name} #{last_name}"}
print_full_name.call("Pankaj","Bhageria") # My name is Pankaj Bhageria
#single parameter, multiple line proc
display_mult_table = Proc.new do |number|
for i in 1..5
puts "#{number} * #{i} = #{number*i}"
end
end
display_mult_table.call(2)
# 2 * 1 = 2
# 2 * 2 = 4
# 2 * 3 = 6
# 2 * 4 = 8
# 2 * 5 = 10
#multiple parameter, multiple line proc
for i in 1..limit
puts "#{number} * #{limit} = #{number*i}"
end
end
display_mult_table.call(2,3)
# 2 * 1 = 2
# 2 * 2 = 4
# 2 * 3 = 6
Note how the parameters are passed to the Proc definition in between the two vertical bars.
Passing a Proc to a method
As a proc is just another object, it can be passed around in methods, returned by methods etc. Suppose we want a block of code to be executed a certain number of times.
for i in 1..times # note the use of range here
code.call(i)
end
end
my_proc = Proc.new{|x| puts “I have been called #{x} times”}
run_code(5,my_proc)
#output:
# I have been called 1 times
# I have been called 2 times
# I have been called 3 times
# I have been called 4 times
# I have been called 5 times
Blocks
Blocks like procs are used to pass code to methods, but they are like undefined procs. ie they are not assigned to any variable, they are just passed to the methods. It will be more clearer when you see the examples.
They can be passed to any method, the method may or may not use them.
Then how does the method execute the block, as there is no parameter to reference it. The method can call the block, by giving the command “yield” which executes the code in the block.
# body of the method
end
some_method(){puts "I am passing a block"}
some_method{puts "I am passing a block"}
#Let us define a method which uses a block
def run_my_code
yield
end
run_my_code{puts "I am passing a block"}
# I am passing a block
#passing multiline blocks
run_my_code do
puts "I am passing a multiline block"
puts "This is the second line of the block"
end
#I am passing a multiline block
#This is the second line of the block
Blocks can be passed along with the other parameters of the method.
for i in 1..times
yield
end
end
run_my_code(2) { puts "passing a block along with params"}
#passing a block along with params
#passing a block along with params
run_my_code(2) do
puts "line1: passing a multi-line block along with params"
puts "line2: passing a multi-line block along with params"
end
#line1: passing a multi-line block along with params
#line2: passing a multi-line block along with params
#line1: passing a multi-line block along with params
#line2: passing a multi-line block along with params
Blocks can accept parameters like methods
for user in users
name = user[:first_name] + " " + user[:last_name]
yield(name)
end
end
#Name is Pankaj Bhageria
#Name is David Jones
Note that in the above example you can change the format of printing anytime by just changing the call to the method. You donot need to modify the method.
So this seperates the 2 things -
Working on the data: Here we are simply calculating the full name of the user, in real life it could have been more complex -
Using the result: Here we are passing the result to the output stream. We can store it to a database/file system or something.
If we need to store the result in a database/file we just need to modify the block passing along with the method.
Use of Ampersand(&)
Ampersand is used to convert a proc to a block and a block to a proc.
If a method want to accept a block but wants to use it as a proc, then add an & in front of the last parameter(the parameter which will receive the block.
my_code.call
end
run_my_code { puts "passing a block, accepting a proc"}
#passing a block, accepting a proc
Note above that we are using “my_code.call” and not yield.
If you have a proc and you want to pass it to a method which accepts block, then when passing use a ampersand before the proc parameter.
yield
end
my_proc = Proc.new { puts "passing a proc instead of block"}
run_my_code my_proc #error, wrong number of arguments
run_my_code &my_proc # passing a proc instead of block
So we have successfully passed a proc to a method which accepts a block
Important points
Only one block can be accepted by a method.
A block can be passed to any method, no need to define it.
To pass a proc instead of a block append an “&” in front of the Proc.
Lambda
my_lambda.call("Ruby")
#Ruby
Lambda is exactly same as a Proc with some minor difference, which we will take up in another post.
Share

