Repository: rails/rails
File: activesupport/lib/active_support/core_ext/enumerable.rb (Ruby)

Code before:
  #   # => [ 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, unless
  # the +filter+ option is set to +false+.
  def in_order_of(key, series, filter: true)
    if filter
      group_by(&key).values_at(*series).flatten(1).compact
    else
      sort_by { |v| series.index(v.public_send(key)) || series.size }.compact
    end
  end

  # 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
  def sole
    first_two = first(2)

    case first_two.count
    when 1   then first_two.first
    when 0   then raise ActiveSupport::EnumerableCoreExt::SoleItemExpectedError, "no item found"
    when 2   then raise ActiveSupport::EnumerableCoreExt::SoleItemExpectedError, "multiple items found"
    end
  end
end

class Hash
  # Hash#reject has its own definition, so this needs one too.
  def compact_blank # :nodoc:
    reject { |_k, v| v.blank? }
  end

  # Removes all blank values from the +Hash+ in place and returns self.
  # Uses Object#blank? for determining if a value is blank.
  #
  #   h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
  #   h.compact_blank!
  #   # => { b: 1, f: true }
  def compact_blank!
    # use delete_if rather than reject! because it always returns self even if nothing changed
    delete_if { |_k, v| v.blank? }
  end
end

class Range # :nodoc:
  # Optimize range sum to use arithmetic progression if a block is not given and
  # we have a range of numeric values.

Review comment (suggestion):
This causes array allocation on `first(2)`. Maybe a better implementation memory wise would be:

``` ruby
result = none = Object.new
each do |element|
  if result == none
    result = element
  else
    raise ActiveSupport::EnumerableCoreExt::SoleItemExpectedError, "multiple items found"
  end
end
if result == none
  raise ActiveSupport::EnumerableCoreExt::SoleItemExpectedError, "no item found"
else
  result
end
```

Code after:
  #   # => [ 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, unless
  # the +filter+ option is set to +false+.
  def in_order_of(key, series, filter: true)
    if filter
      group_by(&key).values_at(*series).flatten(1).compact
    else
      sort_by { |v| series.index(v.public_send(key)) || series.size }.compact
    end
  end

  # 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
  def sole
    result = nil
    found = false

    each do |element|
      if found
        raise SoleItemExpectedError, "multiple items found"
      end

      result = element
      found = true
    end

    if found
      result
    else
      raise SoleItemExpectedError, "no item found"
    end
  end
end

class Hash
  # Hash#reject has its own definition, so this needs one too.
  def compact_blank # :nodoc:
    reject { |_k, v| v.blank? }
  end

  # Removes all blank values from the +Hash+ in place and returns self.
  # Uses Object#blank? for determining if a value is blank.
  #
  #   h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
  #   h.compact_blank!