【问题标题】:Builder throwing "wrong number of arguments" error when passed a block in Ruby 1.9在 Ruby 1.9 中传递块时生成器抛出“错误数量的参数”错误
【发布时间】:2011-11-30 02:03:13
【问题描述】:

我正在尝试将 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'
  ...

将其重写为 stabby 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

帮助?

【问题讨论】:

    标签: ruby lambda builder ruby-1.9 argument-error


    【解决方案1】:

    这实际上是因为在 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。 Procs 和 lambdas 的行为不同。
    • 即使在 1.8.7 中,proclambda 都会生成 Proc 类的对象。事实上,proc 本质上是lambda 的别名,与 ruby​​ 1.9 没有区别。我的答案中的第一段代码在所有情况下都在 Ruby 1.8.7 中成功运行,尽管当数字参数不匹配时它会打印警告(ab)。
    【解决方案2】:

    哦,想通了。在 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
    

    耶!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多