3

In Rails 5.1.4 using Ruby 2.3.5, I get this behavior:

>> [].sum
#> nil

I'd like to upgrade to Ruby 2.4, where Enumerable#sum is implemented natively. Testing this in IRB using Ruby 2.4.2, I get this result:

>> [].sum
#> 0

That's OK, and I can handle the different result. But going back to the Rails console in Rails 5.1.4 using Ruby 2.4.2, I get this:

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

However, in a newly created Rails 5.1.4 project, I don't get this error. What's going on here?

moveson
  • 5,103
  • 1
  • 15
  • 32
  • 1
    Try `[].method(:sum).source_location` in the Rails console of your existing project to see if `sum` is being overridden somewhere. Also might be some clues in the stacktrace lines that come after `undefined method \`each' for nil:NilClass` – mikej Dec 26 '17 at 18:17
  • There is no stack trace after the error. `[].method(:sum).source_location` returns `["/Users/mmo/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/activesupport-5.1.4/lib/active_support/core_ext/enumerable.rb", 148]`. It returns the same result in my newly created test project in which `[].sum` works properly. – moveson Dec 26 '17 at 18:23
  • 1
    Looking at [the source](https://github.com/rails/rails/blob/v5.1.4/activesupport/lib/active_support/core_ext/enumerable.rb) it definitely seems like something odd because you shouldn't have been getting the behaviour you described for Rails 5.1.4 using Ruby 2.3.5. (i.e. you should have been getting 0 not `nil` there too). In the source `Array#sum` will call `super` which is `Enumerable#sum` and [both implementations](https://github.com/rails/rails/blob/5-1-stable/activesupport/lib/active_support/core_ext/enumerable.rb#L8) of that have a default of 0. – mikej Dec 26 '17 at 18:45
  • So it's looking like `[].sum` is calling `Array#sum` (the `source_location`) reported, but that is calling a customised `Enumerable#sum`. So you could try this: `[].method(:sum).super_method.source_location` – mikej Dec 26 '17 at 18:49
  • Was just typing another comment as you were replying :) - that included the suggestion to check `[].method(:sum).super_method.source_location` – mikej Dec 26 '17 at 18:50
  • 4
    In my newly created project, `[].method(:sum).super_method.source_location` returns `["/Users/mmo/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/activesupport-5.1.4/lib/active_support/core_ext/enumerable.rb", 31]`. In the existing project, it returns `["/Users/mmo/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/descriptive_statistics-2.5.1/lib/descriptive_statistics/sum.rb", 2]`. Looks like the descriptive_statistics gem is the source of the problem. – moveson Dec 26 '17 at 18:50
  • 2
    @mikej Thanks for the detective work. If you'd like to rephrase this conversation as an answer, I'm happy to accept it. – moveson Dec 26 '17 at 19:44
  • Great! This could be useful for others coming across other slightly different problems too so I've written it up as an answer. – mikej Dec 26 '17 at 20:03

2 Answers2

2

Looking at the source for the Active Support enumerable extensions it definitely seems like something odd is going on because you shouldn't have been getting the behaviour you described for Rails 5.1.4 using Ruby 2.3.5 i.e. you should have been getting 0 not nil there too.

Active Support's Array#sum checks if Ruby's own sum can be used by checking first.is_a?(Numeric). This will be false for an empty array so the call to super will call Enumerable#sum and both implementations of that have a default of 0.

Try [].method(:sum).source_location in the Rails console of your existing project to see if Array#sum is being overridden somewhere.

if that returns the expected line from active_support/c‌​ore_ext/enumerable.r‌​b then the next step will be to check [].method(:sum).super_method.source_location and see if a customised Enumerable#sum is the culprit.

mikej
  • 65,295
  • 17
  • 152
  • 131
1

I think that your application have some overhidden on sum method. Look the example below with 2 new applications using the 2 different versions of ruby

/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

and the other version

/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
Max Forasteiro
  • 382
  • 2
  • 13