Reputation: 44968
While working with Rails I saw that one could call methods like so.
lot = Lot.new do |u|
u.grade_id = grade.id
u.company_id = company.id
u.type_id = type.id
u.sale_id = sale.id
u.quantity = lot[6]
u.price = lot[3]
u.info = lot[4]
u.remark = lot[5]
end
As you can see, I'm passing the parameters on different lines.
I need to write some methods that take a lot of arguments, and thought that it would be much better if I could invoke my method like this. Could someone show me how to do write methods which accept arguments in a similar fashion? A link to some guide/documentation would be great help. Is this what they call code blocks in Ruby?
Upvotes: 3
Views: 789
Reputation: 303198
Diving in deeper, I think you would benefit from a deeper understanding of "Blocks" in Ruby (which are different from the general programming terms "code block" or "block of code").
Pretend for a moment that the following (invalid) Ruby code actually worked:
def add10( n )
puts "#{n} + 10 = #{n+10}"
end
def do_something_with_digits( method )
1.upto(9) do |i|
method(i)
end
end
do_something_with_digits( add10 )
#=> "1 + 10 = 11"
#=> "2 + 10 = 12"
...
#=> "9 + 10 = 19"
While that code is invalid, its intent—passing some code to a method and having that method run the code—is possible in Ruby in a variety of ways. One of those ways is "Blocks".
A Block in Ruby is very, very much like a method: it can take some arguments and run code for those. Whenever you see foo{ |x,y,z| ... }
or foo do |x,y,z| ... end
, those are blocks that take three parameters and run the ...
on them. (You might even see that the upto
method above is being passed a block.)
Because Blocks are a special part of the Ruby syntax, every method is allowed to be passed a block. Whether or not the method uses the block is up to the method. For example:
def say_hi( name )
puts "Hi, #{name}!"
end
say_hi("Mom") do
puts "YOU SUCK!"
end
#=> Hi, Mom!
The method above is passed a block that is ready to issue an insult, but since the method never calls the block, only the nice message is printed. Here's how we call the block from a method:
def say_hi( name )
puts "Hi, #{name}!"
if block_given?
yield( name )
end
end
say_hi("Mridang") do |str|
puts "Your name has #{str.length} letters."
end
#=> Hi, Mridang!
#=> Your name has 7 letters.
We use block_given?
to see whether or not a block was passed along or not. In this case we passed an argument back to the block; it's up to your method to decide what to pass to the block. For example:
def say_hi( name )
puts "Hi, #{name}!"
yield( name, name.reverse ) if block_given?
end
say_hi("Mridang"){ |str1, str2| puts "Is your name #{str1} or #{str2}?" }
#=> Hi, Mridang!
#=> Is your name Mridang or gnadirM?
It's just a convention (and a good one, and one you want to support) for some classes to pass the instance just created to the block.
Hopefully this helps you understand @SimoneCarletti's answer better, and will help you use blocks throughout your future programming.
Upvotes: 0
Reputation: 176372
The example above doesn't pass any argument. You are simply calling a method and using a block to yield on the new created instance.
This code
lot = Lot.new do |u|
u.grade_id = grade.id
u.company_id = company.id
end
can be written as
lot = Lot.new
lot.grade_id = grade.id
lot.company_id = company.id
The second example doesn't use a block.
If you want your object to accept blocks on initialization, add the following line of code in your initialize
file.
yield self if block_given?
Here's an example
class MyObject
def initialize
# ...
yield self if block_given?
end
end
Upvotes: 4
Reputation: 46914
You need pass a block in your method.
def initialize(&block)
yield self
end
Upvotes: 0