Builder выдает ошибку «неверное количество аргументов» при передаче блока в Ruby 1.9 - PullRequest
3 голосов
/ 30 ноября 2011

Я пытаюсь обновить приложение на Ruby 1.8 до 1.9 и преодолеть некоторые препятствия. В Ruby 1.8.7 я могу передать блок в Builder 3.0.0, и он вызывается, как и ожидалось:

1.8.7 :003 > @builder = Builder::XmlMarkup.new
1.8.7 :004 > block = lambda { puts "foo" }
1.8.7 :005 > @builder.tag(&block)
foo

Но в 1.9 я получаю эту ошибку:

1.9.3p0 :002 > @builder = Builder::XmlMarkup.new
1.9.3p0 :003 > block = lambda { puts "foo" }
1.9.3p0 :004 > @builder.content(&block)
ArgumentError: wrong number of arguments (1 for 0)
  from (irb):3:in `block in irb_binding'
  from /Users/dev/.bundle/ruby/1.9.1/gems/builder-3.0.0/lib/builder/xmlbase.rb:155:in `call'
  ...

И переписать это как «лямбда» (который просто синтаксический сахар, верно?) Не помогает

1.9.3p0 :006 > block = -> { puts "foo" }
1.9.3p0 :007 > @builder.content(&block)
ArgumentError: wrong number of arguments (1 for 0)

Передача фактического блока вместо ссылки на него работает:

1.9.3p0 :008 > @builder.content { puts "foo" }
foo

Помощь

Ответы [ 2 ]

6 голосов
/ 06 декабря 2011

Это потому, что в ruby ​​1.9 lambda и proc ведут себя немного по-разному.Подумайте о лямбде, математически точной, требующей точного числа указанных аргументов, в то время как proc демонстрирует более разрешающее поведение ruby ​​1.8.Например,

a = lambda {|v| p v }
a.call()     # ArgumentError: wrong number of arguments (0 for 1)
a.call(1)    # prints "1"
a.call(1, 2) # ArgumentError: wrong number of arguments (2 for 1)

b = proc {|v| p v }
b.call()     # prints "nil"
b.call(1)    # prints "1"
b.call(1, 2) # prints "1"

Обратите внимание, что оба объекта относятся к типу Proc, но их можно отличить .lambda?Метод.

a.class   # => Proc
a.lambda? # => true
a.arity   # => 1  (number of parameters)
b.class   # => Proc
b.lambda? # => false
b.arity   # => 1  (number of parameters)
0 голосов
/ 30 ноября 2011

Ох, разобрался. Строка, вызывающая проблему в Builder, такова:

block.call(self)

Другими словами, он передает себя в качестве аргумента блоку. В Ruby 1.8 блок может игнорировать это, но в 1.9 он должен объявлять все аргументы. Таким образом:

1.9.3p0 :023 > block = lambda { |dummy| puts "foo" }
1.9.3p0 :024 > @builder.content(&block)
foo

Ура!

...