No, it doesn't. As a general rule of Ruby, if two things look alike, you can bet that there is a subtle difference between them, which makes each of them unique and necessary.
{
and }
do not always stand in the role of block delimiters. When they do not stand in the role of block delimiters (such as when constructing hashes, { a: 1, b: 2 }
), they cannot be replaced by do
... end
. But when the curly braces do delimit a block, they can almost always be replaced by do
... end
. But beware, because sometimes this can change the meaning of your statement. This is because {
... }
have higher precedence, they bind tighter than do
... end
:
puts [ 1, 2, 3 ].map { |e| e + 1 } # { ... } bind with #map method
2
3
4
#=> nil
puts [ 1, 2, 3 ].map do |e| e + 1 end # do ... end bind with #puts method
#<Enumerator:0x0000010a06d140>
#=> nil
As for the opposite situation, do
... end
in the role of block delimiters cannot always be replaced by curly braces.
[ 1, 2, 3 ].each_with_object [] do |e, obj| obj << e.to_s end # is possible
[ 1, 2, 3 ].each_with_object [] { |e, obj| obj << e.to_s } # invalid syntax
In this case, you would have to parenthesize the ordered argument:
[ 1, 2, 3 ].each_with_object( [] ) { |e, obj| obj << e.to_s } # valid with ( )
The consequence of these syntactic rules is that you can write this:
[ 1, 2, 3 ].each_with_object [ nil ].map { 42 } do |e, o| o << e end
#=> [ 42, 1, 2, 3 ]
And the above also demonstrates the case where {}
are not replaceable by do
/end
:
[ 1, 2, 3 ].each_with_object [ nil ].map do 42 end do |e, o| o << e end
#=> SyntaxError
Lambda syntax with ->
differs slightly in that it equally accepts both:
foo = -> x do x + 42 end # valid
foo = -> x { x + 42 } # also valid
Furthermore, do
and end
themselves do not always delimit a block. In particular, this
for x in [ 1, 2, 3 ] do
puts x
end
and this
x = 3
while x > 0 do
x -= 1
end
and this
x = 3
until x == 0 do
x -= 1
end
superficially contains do
... end
keywords, but there is no real block between them. The code inside them does not introduce a new scope, it is just syntax used to repeat a few statements. Curly braces cannot be used here, and the syntax could be written without do
, such as:
for x in [ 1, 2, 3 ]
puts x
end
# same for while and until
For the cases where {
...}
and do
...end
delimiters are interchangeable, the choice which ones to use is a matter of programming style, and is extensively discussed in another question (from whose accepted answer I took one of my examples here). My personal preference in such case is to emphasize readability over rigid rules.