Search code examples
rubyblock

Ruby different behavior depend of block type


Good day. I have different behavior of the same chunk of code depends on type of block syntax curly braces or do/end. The block with do/end just skipped without any error notification:

Block with curly brackets just implements and p prints one Ruby is a COOL language!:

p "rubyisacoollanguage".gsub(/(ruby)(is)(a)(cool)(language)/) {
   "one " + $1.capitalize + " %s %s %s %s!" % [$2,$3,$4.upcase,$5]
}

The 'same' snippet of code in with do/end just skipped, and p show me Enumerator <Enumerator: "rubyisacoollanguage":gsub(/(ruby)(is)(a)(cool)(language)/)>:

p "rubyisacoollanguage".gsub(/(ruby)(is)(a)(cool)(language)/) do
    "two " + $1.capitalize + " %s %s %s %s!" % [$2,$3,$4.upcase,$5]
end

I think it happens because of p in second case it's eliminates block. Things become clear when I add p inside blocks. Data from first block print 2 times, when data from second did not prited at all.

p "rubyisacoollanguage".gsub(/(ruby)(is)(a)(cool)(language)/) {
   p "one " + $1.capitalize + " %s %s %s %s!" % [$2,$3,$4.upcase,$5]
}
p "rubyisacoollanguage".gsub(/(ruby)(is)(a)(cool)(language)/) do
    p "two " + $1.capitalize + " %s %s %s %s!" % [$2,$3,$4.upcase,$5]
end

It was quite strange and unpredictable behavior for me. No error, just skip part of the code. Why it's happens?


Solution

  • Why does it happen?

    Because {} and do/end have different precedence. {} is "stronger". As in "is associated to the nearest method call". So this

    p foo {
      something
    }
    

    Is seen like this.

    p (foo {
      something
    })
    

    And do/end is like this

    p(foo) do
      something
    end
    

    No error, just skip part of the code

    Yes, due to another feature of ruby. Which is "you can pass a block to ANY method. It is then that method's responsibility to use or ignore it." Here p does not expect a block and simply ignores it.