module Enumerable

Public Instance Methods

compact_blank() click to toggle source

Returns a new Array without the blank items. Uses Object#blank? for determining if an item is blank.

[1, "", nil, 2, " ", [], {}, false, true].compact_blank
# =>  [1, 2, true]

Set.new([nil, "", 1, false]).compact_blank
# => [1]

When called on a Hash, returns a new Hash without the blank values.

{ a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
# => { b: 1, f: true }
# File lib/active_support/core_ext/enumerable.rb, line 240
def compact_blank
  reject(&:blank?)
end
exclude?(object) click to toggle source

The negative of the Enumerable#include?. Returns true if the collection does not include the object.

# File lib/active_support/core_ext/enumerable.rb, line 174
def exclude?(object)
  !include?(object)
end
excluding(*elements) click to toggle source

Returns a copy of the enumerable excluding the specified elements.

["David", "Rafael", "Aaron", "Todd"].excluding "Aaron", "Todd"
# => ["David", "Rafael"]

["David", "Rafael", "Aaron", "Todd"].excluding %w[ Aaron Todd ]
# => ["David", "Rafael"]

{foo: 1, bar: 2, baz: 3}.excluding :bar
# => {foo: 1, baz: 3}
# File lib/active_support/core_ext/enumerable.rb, line 188
def excluding(*elements)
  elements.flatten!(1)
  reject { |element| elements.include?(element) }
end
Also aliased as: without
in_order_of(key, series) click to toggle source

Returns a new Array where the order has been set to that provided in the series, based on the key of the objects in the original enumerable.

[ Person.find(5), Person.find(3), Person.find(1) ].in_order_of(:id, [ 1, 5, 3 ])
# => [ Person.find(1), Person.find(5), Person.find(3) ]

If the series include keys that have no corresponding element in the Enumerable, these are ignored. If the Enumerable has additional elements that aren't named in the series, these are not included in the result.

# File lib/active_support/core_ext/enumerable.rb, line 252
def in_order_of(key, series)
  group_by(&key).values_at(*series).flatten(1).compact
end
including(*elements) click to toggle source

Returns a new array that includes the passed elements.

[ 1, 2, 3 ].including(4, 5)
# => [ 1, 2, 3, 4, 5 ]

["David", "Rafael"].including %w[ Aaron Todd ]
# => ["David", "Rafael", "Aaron", "Todd"]
# File lib/active_support/core_ext/enumerable.rb, line 168
def including(*elements)
  to_a.including(*elements)
end
index_by() { |elem| ... } click to toggle source

Convert an enumerable to a hash, using the block result as the key and the element as the value.

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 ...>, ...}
# File lib/active_support/core_ext/enumerable.rb, line 108
def index_by
  if block_given?
    result = {}
    each { |elem| result[yield(elem)] = elem }
    result
  else
    to_enum(:index_by) { size if respond_to?(:size) }
  end
end
index_with(default = (no_default = true)) { |elem| ... } click to toggle source

Convert an enumerable to a hash, using the element as the key and the block result as the value.

post = Post.new(title: "hey there", body: "what's up?")

%i( title body ).index_with { |attr_name| post.public_send(attr_name) }
# => { title: "hey there", body: "what's up?" }

If an argument is passed instead of a block, it will be used as the value for all elements:

%i( created_at updated_at ).index_with(Time.now)
# => { created_at: 2020-03-09 22:31:47, updated_at: 2020-03-09 22:31:47 }
# File lib/active_support/core_ext/enumerable.rb, line 131
def index_with(default = (no_default = true))
  if block_given?
    result = {}
    each { |elem| result[elem] = yield(elem) }
    result
  elsif no_default
    to_enum(:index_with) { size if respond_to?(:size) }
  else
    result = {}
    each { |elem| result[elem] = default }
    result
  end
end
many?() { |*args| ... } click to toggle source

Returns true if the enumerable has more than 1 element. Functionally equivalent to enum.to_a.size > 1. Can be called with a block too, much like any?, so people.many? { |p| p.age > 26 } returns true if more than one person is over 26.

# File lib/active_support/core_ext/enumerable.rb, line 149
def many?
  cnt = 0
  if block_given?
    any? do |*args|
      cnt += 1 if yield(*args)
      cnt > 1
    end
  else
    any? { (cnt += 1) > 1 }
  end
end
maximum(key) click to toggle source

Calculates the maximum from the extracted elements.

payments = [Payment.new(5), Payment.new(15), Payment.new(10)]
payments.maximum(:price) # => 15
# File lib/active_support/core_ext/enumerable.rb, line 52
def maximum(key)
  map(&key).max
end
minimum(key) click to toggle source

Calculates the minimum from the extracted elements.

payments = [Payment.new(5), Payment.new(15), Payment.new(10)]
payments.minimum(:price) # => 5
# File lib/active_support/core_ext/enumerable.rb, line 44
def minimum(key)
  map(&key).min
end
pick(*keys) click to toggle source

Extract the given key from the first element in the enumerable.

[{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pick(:name)
# => "David"

[{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pick(:id, :name)
# => [1, "David"]
# File lib/active_support/core_ext/enumerable.rb, line 217
def pick(*keys)
  return if none?

  if keys.many?
    keys.map { |key| first[key] }
  else
    first[keys.first]
  end
end
pluck(*keys) click to toggle source

Extract the given key from each element in the enumerable.

[{ 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"]]
# File lib/active_support/core_ext/enumerable.rb, line 201
def pluck(*keys)
  if keys.many?
    map { |element| keys.map { |key| element[key] } }
  else
    key = keys.first
    map { |element| element[key] }
  end
end
sole() click to toggle source

Returns the sole item in the enumerable. If there are no items, or more than one item, raises Enumerable::SoleItemExpectedError.

["x"].sole          # => "x"
Set.new.sole        # => Enumerable::SoleItemExpectedError: no item found
{ a: 1, b: 2 }.sole # => Enumerable::SoleItemExpectedError: multiple items found
# File lib/active_support/core_ext/enumerable.rb, line 262
def sole
  case count
  when 1   then return first # rubocop:disable Style/RedundantReturn
  when 0   then raise ActiveSupport::EnumerableCoreExt::SoleItemExpectedError, "no item found"
  when 2.. then raise ActiveSupport::EnumerableCoreExt::SoleItemExpectedError, "multiple items found"
  end
end
sum(identity = nil, &block) click to toggle source

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)
# File lib/active_support/core_ext/enumerable.rb, line 74
  def sum(identity = nil, &block)
    if identity
      _original_sum_with_required_identity(identity, &block)
    elsif block_given?
      map(&block).sum
    else
      first = true

      reduce(nil) do |sum, value|
        if first
          first = false

          unless value.is_a?(Numeric) || value.respond_to?(:coerce)
            ActiveSupport::Deprecation.warn(<<-MSG.squish)
              Rails 7.0 has deprecated Enumerable.sum in favor of Ruby's native implementation available since 2.4.
              Sum of non-numeric elements requires an initial argument.
            MSG
          end
          value
        else
          sum + value
        end
      end || 0
    end
  end
without(*elements)
Alias for: excluding