Mridang Agarwalla
Mridang Agarwalla

Reputation: 44968

Writing a method that takes parameters on different lines in Ruby

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

Answers (3)

Phrogz
Phrogz

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

Simone Carletti
Simone Carletti

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

shingara
shingara

Reputation: 46914

You need pass a block in your method.

def initialize(&block)
  yield self
end

Upvotes: 0

Related Questions