3

I have a little question on passing block.

def a_method(a, b)
  a + yield(a, b)
end

This works fine.

k = a_method(1, 2) do |x, y| 
  (x + y) * 3 
end
puts k

But this won't work.

puts a_method(1, 2) do |x, y| 
  (x + y) * 3 
end
# LocalJumpError: no block given (yield)

Can anyone kindly explain this to me?

Thanks. Example taken from Metaprogramming Ruby by Paolo Perrotta. Great book.

revolver
  • 2,385
  • 5
  • 24
  • 40
  • See also: [Ruby Block Syntax Error](http://StackOverflow.Com/q/6854283/), [Code block passed to `each` works with brackets but not with `do`-`end` (ruby)](http://StackOverflow.Com/q/6718340/), [Block definition - difference between braces and `do`-`end` ?](http://StackOverflow.Com/q/6179442/), [Ruby multiline block without `do` `end`](http://StackOverflow.Com/q/3680097/), [Using `do` block vs brackets `{}`](http://StackOverflow.Com/q/2122380/), [What is the difference or value of these block coding styles in Ruby?](http://StackOverflow.Com/q/533008/), … – Jörg W Mittag Jun 06 '12 at 10:34
  • … [Ruby block and unparenthesized arguments](http://StackOverflow.Com/q/420147/), [Why aren't `do`/`end` and `{}` always equivalent?](http://StackOverflow.Com/q/7487664/) and [Wierd imperfection in Ruby blocks](http://StackOverflow.Com/q/7620804/). – Jörg W Mittag Jun 06 '12 at 10:34

2 Answers2

5

The difference between do .. end and curly braces is that the curly braces bind to the rightmost expression, while do .. end bind to the leftmost one. Observe the following examples:

def first(x=nil)
  puts "  first(#{x.inspect}): #{block_given? ? "GOT BLOCK" : "no block"}"
  "f"
end

def second(x=nil)
  puts "    second(#{x.inspect}): #{block_given? ? "GOT BLOCK" : "no block"}"
  "s"
end

first second do |x| :ok end #   second(nil): no block
                            # first("s"): GOT BLOCK

first second {|x| :ok }     #   second(nil): GOT BLOCK
                            # first("s"): no block

In the first case, the block made with do..end will be bound to the first function (leftmost). In the second case the block made with curly brackets will be bound to the second function (rightmost).

Usually it's good idea to use parentheses if you have two functions and a block - just for readability and to avoid mistakes.

It's very easy to accidentally pass a block to puts method, just as in your question.

Arsen7
  • 12,522
  • 2
  • 43
  • 60
-1

That's because the block is passed to puts and not to a_method.
This should do it:

puts (a_method(1, 2) { |x, y| (x + y) * 3 })

# if you want to keep it multilines
puts (a_method(1, 2) { |x, y|
  (x + y) * 3
})
Samy Dindane
  • 17,900
  • 3
  • 40
  • 50
  • Hi, can you give me an example with the do..end? I did try with the curly brackets before that. Was trying to figure out how to use the do..end. – revolver Jun 06 '12 at 07:13
  • I kept searching but found nothing about this issue. Maybe `puts` isn't simply supposed to have a do...end inside it (that makes sense because it's not supposed to display multiline stuff)? You can still keep using braces even for a multiline block. – Samy Dindane Jun 06 '12 at 07:25