TLDR
- In Ruby, blocks in braces, { ... }, bind stronger than indo ... enddo
- Rule of thumb
- Use { ... }for single-line blocks
- do ... endfor multi-liners
 
- Use 
Try Guess the Output
Answers in section "Precedence in Execution"
arr = [1, 2, 3]
a = arr.map { |num| num * 2 }
b = arr.map do
  |num| num * 2
end
 
puts a # => ???
puts b # => ???arr = [1, 2, 3]
puts arr.map { |num| num * 2 } # => ???
puts arr.map do
  |num| num * 2
end # => ???What is Block in Ruby
In Ruby, a (code) block is a piece of code that takes arguments. A block can NOT "survive" on its own, UNLESS it is attached to methods, or in the form of proc or lambda.
# Two ways to wrap a block in Ruby
# They will cause errors if put like these
# 1. { ... }
{ puts 1 } # gets "SyntaxError"
# 2. do ... end
do puts 1 end # gets "SyntaxError"def some_method
  yield
end
 
# Good; these will not cause SyntaxError
some_method { puts 1 }
proc_print_one = proc { puts 1 }
lambda_print_one = lambda { puts 1 }Read more about the difference between
procandlambdain my blog post Proc & Lambda in Ruby!
Precedence in Execution
Per documentation in Ruby-Doc.org, { ... } blocks have priority below all listed operations, but do ... end blocks have even lower priority.
- 
No difference in terms of output, as all gets executed before printed arr = [1, 2, 3] a = arr.map { |num| num * 2 } b = arr.map do |num| num * 2 end puts a # => [2, 4, 6] puts b # => [2, 4, 6]
- 
The following #maps are interpreted differently in Ruby- 
puts arr.map { ... }equalsputs(arr.map { ... }), but
- 
puts arr.map do ... endare actuallyputs(arr.map) do ... endarr = [1, 2, 3] puts arr.map { |num| num * 2 } # prints the following # 2 # 4 # 6 puts arr.map do |num| num * 2 end # => #<Enumerator:0x00007fb34d8d40c0>
 
- 
See Precedence for the comprehensive list of precedence.
References
- Precedence by Ruby-Doc.org