“建筑商投掷”;错误的参数数量“;在Ruby 1.9中传递块时出错

“建筑商投掷”;错误的参数数量“;在Ruby 1.9中传递块时出错,ruby,lambda,builder,ruby-1.9,argument-error,Ruby,Lambda,Builder,Ruby 1.9,Argument Error,我正在尝试将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 :0

我正在尝试将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'
  ...
把它改写成一个尖刻的lambda(这只是语法上的甜点,对吧?)并没有帮助:

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

帮助?

哦,想出来了。在Builder中导致问题的行是:

block.call(self)
换句话说,它将自身作为参数传递给块。在Ruby1.8中,块可以自由忽略这一点,但在1.9中,它必须声明所有参数。因此:

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

这实际上是因为在ruby 1.9中,lambda和proc的行为微妙地不同。想象一下lambda,它在数学上是精确的,需要指定精确数量的参数,而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)

proc
在1.8中生成lambda,在1.9中生成proc。proc和lambda的行为不同。即使在1.8.7中,
proc
lambda
都会生成proc类的对象。事实上,
proc
本质上是
lambda
的别名,与ruby 1.9没有区别。我的答案中的第一块代码在所有情况下都在Ruby 1.8.7中成功运行,尽管当数字参数不匹配时,它会打印警告(针对
a
b
)。