Ruby 2.4 Enumerable#sum 在 Rails 5.1 中中断

Ruby 2.4 Enumerable#sum breaks in Rails 5.1

在 Rails 5.1.4 中使用 Ruby 2.3.5,我得到了这个行为:

>> [].sum
#> nil

我想升级到 Ruby 2.4,其中 Enumerable#sum 是本机实现的。使用 Ruby 2.4.2 在 IRB 中对此进行测试,我得到以下结果:

>> [].sum
#> 0

没关系,我可以处理不同的结果。但是使用 Ruby 2.4.2 回到 Rails 5.1.4 中的 Rails 控制台,我得到这个:

>> [].sum
#> NoMethodError: undefined method `each' for nil:NilClass

然而,在新创建的 Rails 5.1.4 项目中,我没有收到此错误。这里发生了什么?

我认为您的应用程序对 sum 方法有一些隐藏。查看下面的示例,其中有 2 个新应用程序使用 ruby

的 2 个不同版本
/testapp# ruby --version
ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-linux]
/testapp# rails --version
Rails 5.1.4
/testapp# rails c
irb(main):001:0> [].sum
=> 0

和另一个版本

/testapp# ruby --version
ruby 2.3.5p376 (2017-09-14 revision 59905) [x86_64-linux]
/testapp# rails --version
Rails 5.1.4
/testapp# rails c
irb(main):001:0> [].sum
=> 0

看看 source for the Active Support enumerable extensions 肯定看起来有些奇怪,因为你不应该使用 Ruby 2.3 得到你为 Rails 5.1.4 描述的行为.5 即你应该也得到 0 而不是 nil

Active Support 的 Array#sum 检查 Ruby 自己的 sum 是否可以通过检查 first.is_a?(Numeric) 使用。对于空数组,这将是错误的,因此对 super 的调用将调用 Enumerable#sum,而 both implementations of that 的默认值为 0。

在现有项目的 Rails 控制台中尝试 [].method(:sum).source_location 以查看 Array#sum 是否在某处被覆盖。

如果 returns 来自 active_support/c‌​ore_ext/enumerable.r‌​b 的预期行,那么下一步将检查 [].method(:sum).super_method.source_location 并查看自定义的 Enumerable#sum 是否是罪魁祸首。