diff options
author | Rafael França <rafaelmfranca@gmail.com> | 2017-04-18 15:52:53 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-18 15:52:53 -0400 |
commit | c30eddb81a87ba5c4f68c3309b9ae4d2e02386aa (patch) | |
tree | f86a8ce64641ad773c7b452b2648fba538437f69 /activesupport/lib/active_support/core_ext/enumerable.rb | |
parent | 5e2b419779fdb5f0c5566648e2e0fb07429b3540 (diff) | |
parent | 3adbf14d65e6e883ae1d6f8478c9ee858586e758 (diff) | |
download | rails-c30eddb81a87ba5c4f68c3309b9ae4d2e02386aa.tar.gz rails-c30eddb81a87ba5c4f68c3309b9ae4d2e02386aa.tar.bz2 rails-c30eddb81a87ba5c4f68c3309b9ae4d2e02386aa.zip |
Merge pull request #28781 from mtsmfm/sum
Fix Enumerable#sum redefined warning
Diffstat (limited to 'activesupport/lib/active_support/core_ext/enumerable.rb')
-rw-r--r-- | activesupport/lib/active_support/core_ext/enumerable.rb | 68 |
1 files changed, 45 insertions, 23 deletions
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index 90d7d2947f..4f120d4b45 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -1,28 +1,50 @@ module Enumerable - # Calculates a sum from the elements. + # Enumerable#sum was added in Ruby 2.4 but it only works with Numeric elements + # when we omit an identity. # - # payments.sum { |p| p.price * p.tax_rate } - # payments.sum(&:price) - # - # The latter is a shortcut for: - # - # payments.inject(0) { |sum, p| sum + p.price } - # - # It can also calculate the sum without the use of a block. - # - # [5, 15, 10].sum # => 30 - # ['foo', 'bar'].sum # => "foobar" - # [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5] - # - # The default sum of an empty list is zero. You can override this default: - # - # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0) - def sum(identity = nil, &block) - if block_given? - map(&block).sum(identity) - else - sum = identity ? inject(identity, :+) : inject(:+) - sum || identity || 0 + # We tried shimming it to attempt the fast native method, rescue TypeError, + # and fall back to the compatible implementation, but that's much slower than + # just calling the compat method in the first place. + if Enumerable.instance_methods(false).include?(:sum) && !((?a..?b).sum rescue false) + # We can't use Refinements here because Refinements with Module which will be prepended + # doesn't work well https://bugs.ruby-lang.org/issues/13446 + alias :_original_sum_with_required_identity :sum + private :_original_sum_with_required_identity + # Calculates a sum from the elements. + # + # payments.sum { |p| p.price * p.tax_rate } + # payments.sum(&:price) + # + # The latter is a shortcut for: + # + # payments.inject(0) { |sum, p| sum + p.price } + # + # It can also calculate the sum without the use of a block. + # + # [5, 15, 10].sum # => 30 + # ['foo', 'bar'].sum # => "foobar" + # [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5] + # + # The default sum of an empty list is zero. You can override this default: + # + # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0) + def sum(identity = nil, &block) + if identity + _original_sum_with_required_identity(identity, &block) + elsif block_given? + map(&block).sum(identity) + else + inject(:+) || 0 + end + end + else + def sum(identity = nil, &block) + if block_given? + map(&block).sum(identity) + else + sum = identity ? inject(identity, :+) : inject(:+) + sum || identity || 0 + end end end |