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 {}
.
There are two common styles for choosing do end
vs. { }
for blocks in Ruby:
The first and very common style was popularized by Ruby on Rails, and is based on a simple rule of single vs. multi-line:
{ }
for single-line blocksdo end
for multi-line blocksThis makes sense because do/end reads badly in a one-liner, but for multi-line blocks, leaving a closing }
hanging on its own line is inconsistent with everything else that uses end
in ruby, such as module, class & method definitions (def
etc.) and control structures (if
, while
, case
, etc.)
The second, less-frequently seen style is known as semantic, or "Weirich Braces", proposed by the late, great rubyist Jim Weirich:
do end
for procedural blocks{ }
for functional blocksThis means that when the block is evaluated for its return value, it should be chainable, and the {}
braces make more sense for method chaining.
On the other hand, when the block is evaluated for its side-effects, then the return value is of no consequence, and the block is just "doing" something, so it does not make sense to be chained.
This distinction in the syntax conveys visual meaning about the evaluation of the block, and whether or not you should care about its return value.
For example, here the return value of the block is applied to every item:
items.map { |i| i.upcase }
However, here it's not using the block's return value. It's operating procedurally, and doing a side-effect with it:
items.each do |item|
puts item
end
Another benefit of the semantic style is that you don't need to change braces to do/end just because a line was added to the block.
As an observation, coincidentally functional blocks are frequently a one-liner, and procedural blocks (e.g. config) are multi-line. So, following the Weirich style ends up looking almost the same as the Rails style.
I used the Weirich style for years, but just moved away from this to always use braces. I don't remember to ever have used the info from the block style, and the definition is kinda vague. For example:
date = Timecop.freeze(1.year.ago) { format_date(Time.now) }
customer = Timecop.freeze(1.year.ago) { create(:customer) }
Are these procudual or functional?
And the line count thing is just useless in my opinion. I know, whether there are 1 or more lines, and why exactly should I change the style just because I've added or removed lines?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With