moduleEnumerable# Enumerable#sum was added in Ruby 2.4 but it only works with Numeric elements# when we omit an identity.## 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.ifEnumerable.instance_methods(false).include?(:sum)&&!((?a..?b).sumrescuefalse)# We can't use Refinements here because Refinements with Module which will be prepended# doesn't work well https://bugs.ruby-lang.org/issues/13446alias:_original_sum_with_required_identity:sumprivate:_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)defsum(identity=nil,&block)ifidentity_original_sum_with_required_identity(identity,&block)elsifblock_given?map(&block).sum(identity)elseinject(:+)||0endendelsedefsum(identity=nil,&block)ifblock_given?map(&block).sum(identity)elsesum=identity?inject(identity,:+):inject(:+)sum||identity||0endendend# Convert an enumerable to a hash.## people.index_by(&:login)# => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}# people.index_by { |person| "#{person.first_name} #{person.last_name}" }# => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}defindex_byifblock_given?Hash[map{|elem|[yield(elem),elem]}]elseto_enum(:index_by){sizeifrespond_to?(:size)}endend# Returns +true+ if the enumerable has more than 1 element. Functionally# equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too,# much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+# if more than one person is over 26.defmany?cnt=0ifblock_given?any?do|element|cnt+=1ifyieldelementcnt>1endelseany?{(cnt+=1)>1}endend# The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the# collection does not include the object.defexclude?(object)!include?(object)end# Returns a copy of the enumerable without the specified elements.## ["David", "Rafael", "Aaron", "Todd"].without "Aaron", "Todd"# => ["David", "Rafael"]## {foo: 1, bar: 2, baz: 3}.without :bar# => {foo: 1, baz: 3}defwithout(*elements)reject{|element|elements.include?(element)}end# Convert an enumerable to an array based on the given key.## [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)# => ["David", "Rafael", "Aaron"]## [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)# => [[1, "David"], [2, "Rafael"]]defpluck(*keys)ifkeys.many?map{|element|keys.map{|key|element[key]}}elsemap{|element|element[keys.first]}endendendclassRange#:nodoc:# Optimize range sum to use arithmetic progression if a block is not given and# we have a range of numeric values.defsum(identity=nil)ifblock_given?||!(first.is_a?(Integer)&&last.is_a?(Integer))superelseactual_last=exclude_end??(last-1):lastifactual_last>=firstsum=identity||0sum+(actual_last-first+1)*(actual_last+first)/2elseidentity||0endendendend# Array#sum was added in Ruby 2.4 but it only works with Numeric elements.## 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.ifArray.instance_methods(false).include?(:sum)&&!(%w[a].sumrescuefalse)classArrayremove_method:sumdefsum(*args)#:nodoc:# Use Enumerable#sum instead.superendendend