Using do block vs braces {}

Ruby cookbook says bracket syntax has higher precedence order than do..end

Keep in mind that the bracket syntax has a higher precedence than the do..end syntax. Consider the following two snippets of code:

1.upto 3 do |x|
  puts x
end

1.upto 3 { |x| puts x }
# SyntaxError: compile error

Second example only works when parentheses is used, 1.upto(3) { |x| puts x }


This is a bit old question but I would like to try explain a bit more about {} and do .. end

like it is said before

bracket syntax has higher precedence order than do..end

but how this one makes difference:

method1 method2 do
  puts "hi"
end

in this case, method1 will be called with the block of do..end and method2 will be passed to method1 as an argument! which is equivalent to method1(method2){ puts "hi" }

but if you say

method1 method2{
  puts "hi"
}

then method2 will be called with the block then the returned value will be passed to method1 as an argument. Which is equivalent to method1(method2 do puts "hi" end)

def method1(var)
    puts "inside method1"
    puts "method1 arg = #{var}"
    if block_given?
        puts "Block passed to method1"
        yield "method1 block is running"
    else
        puts "No block passed to method1"
    end
end

def method2
    puts"inside method2"
    if block_given?
        puts "Block passed to method2"
        return yield("method2 block is running")
    else
        puts "no block passed to method2"
        return "method2 returned without block"
    end
end

#### test ####

method1 method2 do 
    |x| puts x
end

method1 method2{ 
    |x| puts x
}

#### output ####

#inside method2
#no block passed to method2
#inside method1
#method1 arg = method2 returned without block
#Block passed to method1
#method1 block is running

#inside method2
#Block passed to method2
#method2 block is running
#inside method1
#method1 arg = 
#No block passed to method1

Generally, the convention is to use {} when you are doing a small operation, for example, a method call or a comparison, etc. so this makes perfect sense:

some_collection.each { |element| puts element }

But if you have slightly complex logic that goes to multiple lines then use do .. end like:

1.upto(10) do |x|
  add_some_num = x + rand(10)
  puts '*' * add_some_num
end

Basically, it comes down to, if your block logic goes to multiple lines and cannot be fitted on the same line then use do .. end and if your block logic is simple and just a simple/single line of code then use {}.