为什么`each do`会在带注释的方法定义中导致语法错误?

时间:2015-01-20 01:08:11

标签: ruby syntax-error

此代码:

private def not_ok
  collection.each do |x|
    puts x
  end
end

导致语法错误:

syntax error, unexpected keyword_do_block, expecting keyword_end

更新:这是使用MRI Ruby 2.1.0 。显然,此行为是特定于版本的,并已在更高版本中修复,包括2.1.1(!)。 (感谢@Amadan和@JörgWMittag指出这一点。)

为什么会引发语法错误,如何在不将do块更改为{}块的情况下不提出语法错误?

为了进行比较,这些变体不会导致语法错误:

def ok
  collection.each do |x|
    puts x
  end
end

private def ok
  collection.each { |x|
    puts x
  }
end

private def ok
  each do |x|
    puts x
  end
end

由于我知道def表达式会返回一个可以传递给其他方法的符号,因此我开始使用private单独注释我的更多方法,而不是单独使用public和{ {1}}类中的部分(我发现它不易维护),并且多次遇到此问题 - 只要该方法包含private块。

1 个答案:

答案 0 :(得分:3)

似乎在旧版本的Ruby上,do / end块存在优先问题。

您可以通过将def表达式的返回值赋给变量,然后将该变量传递给Module#private的调用来解决这个问题:

var = def not_ok
  collection.each do |x|
    puts x
  end
end

private var

但请注意,在旧版本的Ruby中,方法定义表达式的返回值是实现定义的,因此您不知道上面的代码将执行什么操作。 MRI,YARV,MacRuby,MagLev,JRuby和IronRuby将返回nil作为def表达式的结果,raise表示TypeError Module#privateSymbol只需要StringCompiledMethod s。 Rubinius将返回一个raise对象,表示该方法的已编译代码,但同样,TypeError来自Module#private的{​​{1}}。

只有在最新版本的Ruby上,def表达式才会计算为Symbol,但是,在这些最新版本的Ruby上,优先级问题也已修复,因此您的代码将只是工作

它适用于YARV 2.2.0和JRuby-9.0.0.0-dev,但不适用于JRuby 1.7.18和Rubinius 2.2.0(最后一个可能是一个bug,因为它声称兼容Ruby 2.1.0)。