3

Why syntax with curly braces works as expected:

class SomeClass
  include Parser::Http.new { |agent|
    # PASSED: This block was passed to Http::new
  }
end

While one with do...end passed to wrong target method?

class OtherClass
  include Parser::Http.new do |agent|
    # FAILED: This block was passed to Module::include
  end
end

How to make this both syntaxes work the same?

Eyeslandic
  • 14,553
  • 13
  • 41
  • 54
Molfar
  • 1,411
  • 3
  • 18
  • 49

2 Answers2

4

TL;DR do end has lower precedence than { }.

Actually, those syntaxes are not intended to work in the same way.

Here is a snippet from the official docs:

The block argument sends a closure from the calling scope to the method.

The block argument is always last when sending a message to a method. A block is sent to a method using do ... end or { ... }:

my_method do
  # ...
end

or:

my_method {
  # ...
}

do end has lower precedence than { } so:

method_1 method_2 {
  # ...
}

Sends the block to method_2 while:

method_1 method_2 do
  # ...
end

Sends the block to method_1. Note that in the first case if parentheses are used the block is sent to method_1.

Hope this helps.

Community
  • 1
  • 1
Marian13
  • 7,740
  • 2
  • 47
  • 51
4

There is little to add to @Marian13's answer, except that you can circumvent the precedence problem when using bracketed blocks by wrapping the first method arguments with parenthesis.

class SomeClass
  include(Parser::Http.new) { |agent|
    # ...
  }
end

This is particularly useful when you want a one-liner to look good.

ichigolas
  • 7,595
  • 27
  • 50