# File activesupport/lib/active_support/core_ext/enumerable.rb, line 218 def compact_blank reject(&:blank?) end
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, 2]) # => [2, 1] (or [1, 2])
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 activesupport/lib/active_support/core_ext/enumerable.rb, line 152 def exclude?(object) !include?(object) end
The negative of the Enumerable#include?
. Returns true
if the collection does not include the object.
# File activesupport/lib/active_support/core_ext/enumerable.rb, line 166 def excluding(*elements) elements.flatten!(1) reject { |element| elements.include?(element) } end
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 activesupport/lib/active_support/core_ext/enumerable.rb, line 230 def in_order_of(key, series) index_by(&key).values_at(*series).compact end
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 activesupport/lib/active_support/core_ext/enumerable.rb, line 146 def including(*elements) to_a.including(*elements) end
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 activesupport/lib/active_support/core_ext/enumerable.rb, line 86 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
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 activesupport/lib/active_support/core_ext/enumerable.rb, line 109 def index_with(default = INDEX_WITH_DEFAULT) if block_given? result = {} each { |elem| result[elem] = yield(elem) } result elsif default != INDEX_WITH_DEFAULT result = {} each { |elem| result[elem] = default } result else to_enum(:index_with) { size if respond_to?(:size) } end end
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 activesupport/lib/active_support/core_ext/enumerable.rb, line 127 def many? cnt = 0 if block_given? any? do |element| cnt += 1 if yield element cnt > 1 end else any? { (cnt += 1) > 1 } end end
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 activesupport/lib/active_support/core_ext/enumerable.rb, line 35 def maximum(key) map(&key).max end
Calculates the maximum from the extracted elements.
payments = [Payment.new(5), Payment.new(15), Payment.new(10)] payments.maximum(:price) # => 15
# File activesupport/lib/active_support/core_ext/enumerable.rb, line 27 def minimum(key) map(&key).min end
Calculates the minimum from the extracted elements.
payments = [Payment.new(5), Payment.new(15), Payment.new(10)] payments.minimum(:price) # => 5
# File activesupport/lib/active_support/core_ext/enumerable.rb, line 195 def pick(*keys) return if none? if keys.many? keys.map { |key| first[key] } else first[keys.first] end end
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 activesupport/lib/active_support/core_ext/enumerable.rb, line 179 def pluck(*keys) if keys.many? map { |element| keys.map { |key| element[key] } } else key = keys.first map { |element| element[key] } end end
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 activesupport/lib/active_support/core_ext/enumerable.rb, line 240 def sole case count when 1 then return first # rubocop:disable Style/RedundantReturn when 0 then raise SoleItemExpectedError, "no item found" when 2.. then raise SoleItemExpectedError, "multiple items found" 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
# File activesupport/lib/active_support/core_ext/enumerable.rb, line 57 def sum(identity = nil, &block) if identity _original_sum_with_required_identity(identity, &block) elsif block_given? map(&block).sum # we check `first(1) == []` to check if we have an # empty Enumerable; checking `empty?` would return # true for `[nil]`, which we want to deprecate to # keep consistent with Ruby elsif first.is_a?(Numeric) || first(1) == [] identity ||= 0 _original_sum_with_required_identity(identity, &block) else 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 inject(:+) || 0 end end
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)
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.