diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2019-03-05 16:04:41 -0800 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2019-03-05 16:04:41 -0800 |
commit | bfaa3091c3c32b5980a614ef0f7b39cbf83f6db3 (patch) | |
tree | 040de4c20837ba49faf87ac9f7251f4df0afb9af | |
parent | 91ed21b304c468db8ce9fd830312c151432935d0 (diff) | |
download | rails-bfaa3091c3c32b5980a614ef0f7b39cbf83f6db3.tar.gz rails-bfaa3091c3c32b5980a614ef0f7b39cbf83f6db3.tar.bz2 rails-bfaa3091c3c32b5980a614ef0f7b39cbf83f6db3.zip |
Added Array#including, Array#excluding, Enumerable#including, Enumerable#excluding
-rw-r--r-- | activesupport/CHANGELOG.md | 18 | ||||
-rw-r--r-- | activesupport/lib/active_support/core_ext/array/access.rb | 20 | ||||
-rw-r--r-- | activesupport/lib/active_support/core_ext/enumerable.rb | 28 | ||||
-rw-r--r-- | activesupport/test/core_ext/array/access_test.rb | 10 | ||||
-rw-r--r-- | activesupport/test/core_ext/enumerable_test.rb | 12 |
5 files changed, 77 insertions, 11 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 3f0c6fbd4e..ea84b54b3f 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,21 @@ +* Allow Array#excluding and Enumerable#excluding to deal with a passed array gracefully. + + [ 1, 2, 3, 4, 5 ].excluding([4, 5]) => [ 1, 2, 3 ] + + *DHH* + +* Renamed Array#without and Enumerable#without to Array#excluding and Enumerable#excluding, to create parity with + Array#including and Enumerable#including. Retained the old names as aliases. + + *DHH* + +* Added Array#including and Enumerable#including to conveniently enlarge a collection with more members using a method rather than an operator: + + [ 1, 2, 3 ].including(4, 5) => [ 1, 2, 3, 4, 5 ] + post.authors.including(Current.person) => All the authors plus the current person! + + *DHH* + ## Rails 6.0.0.beta2 (February 25, 2019) ## * New autoloading based on [Zeitwerk](https://github.com/fxn/zeitwerk). diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb index b7ff7a3907..c9eecc55f9 100644 --- a/activesupport/lib/active_support/core_ext/array/access.rb +++ b/activesupport/lib/active_support/core_ext/array/access.rb @@ -29,16 +29,28 @@ class Array end end - # Returns a copy of the Array without the specified elements. + # Returns a new array that includes the passed elements. + # + # Example: [ 1, 2, 3 ].including(4, 5) => [ 1, 2, 3, 4, 5 ] + def including(*elements) + self + elements.flatten + end + + # Returns a copy of the Array excluding the specified elements. # # people = ["David", "Rafael", "Aaron", "Todd"] - # people.without "Aaron", "Todd" + # people.excluding "Aaron", "Todd" # # => ["David", "Rafael"] # - # Note: This is an optimization of <tt>Enumerable#without</tt> that uses <tt>Array#-</tt> + # Note: This is an optimization of <tt>Enumerable#excluding</tt> that uses <tt>Array#-</tt> # instead of <tt>Array#reject</tt> for performance reasons. + def excluding(*elements) + self - elements.flatten + end + + # Alias for #excluding. def without(*elements) - self - elements + excluding(*elements) end # Equal to <tt>self[1]</tt>. diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index d87d63f287..d6fb89e588 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -97,23 +97,43 @@ module Enumerable end 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"] + def including(*elements) + to_a.including(*elements) + end + # The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the # collection does not include the object. def exclude?(object) !include?(object) end - # Returns a copy of the enumerable without the specified elements. + # Returns a copy of the enumerable excluding the specified elements. + # + # ["David", "Rafael", "Aaron", "Todd"].excluding "Aaron", "Todd" + # # => ["David", "Rafael"] # - # ["David", "Rafael", "Aaron", "Todd"].without "Aaron", "Todd" + # ["David", "Rafael", "Aaron", "Todd"].excluding %w[ Aaron Todd ] # # => ["David", "Rafael"] # - # {foo: 1, bar: 2, baz: 3}.without :bar + # {foo: 1, bar: 2, baz: 3}.excluding :bar # # => {foo: 1, baz: 3} - def without(*elements) + def excluding(*elements) + elements.flatten! reject { |element| elements.include?(element) } end + # Alias for #excluding. + def without(*elements) + excluding(*elements) + end + # Convert an enumerable to an array based on the given key. # # [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name) diff --git a/activesupport/test/core_ext/array/access_test.rb b/activesupport/test/core_ext/array/access_test.rb index 8c217023cf..8f89c3f25c 100644 --- a/activesupport/test/core_ext/array/access_test.rb +++ b/activesupport/test/core_ext/array/access_test.rb @@ -32,6 +32,16 @@ class AccessTest < ActiveSupport::TestCase assert_equal array[-2], array.second_to_last end + def test_including + assert_equal [1, 2, 3, 4, 5], [1, 2, 4].including(3, 5).sort + assert_equal [1, 2, 3, 4, 5], [1, 2, 4].including([3, 5]).sort + end + + def test_excluding + assert_equal [1, 2, 4], [1, 2, 3, 4, 5].excluding(3, 5) + assert_equal [1, 2, 4], [1, 2, 3, 4, 5].excluding([3, 5]) + end + def test_without assert_equal [1, 2, 4], [1, 2, 3, 4, 5].without(3, 5) end diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index b63464a36a..4e9cf3848d 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -217,11 +217,17 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal false, GenericEnumerable.new([ 1 ]).exclude?(1) end + def test_excluding + assert_equal [1, 2, 4], GenericEnumerable.new((1..5).to_a).excluding(3, 5) + assert_equal [3, 4, 5], GenericEnumerable.new((1..5).to_a).excluding([1, 2]) + assert_equal [1, 2, 4], (1..5).to_a.excluding(3, 5) + assert_equal [1, 2, 4], (1..5).to_set.excluding(3, 5) + assert_equal({ foo: 1, baz: 3 }, { foo: 1, bar: 2, baz: 3 }.excluding(:bar)) + end + def test_without assert_equal [1, 2, 4], GenericEnumerable.new((1..5).to_a).without(3, 5) - assert_equal [1, 2, 4], (1..5).to_a.without(3, 5) - assert_equal [1, 2, 4], (1..5).to_set.without(3, 5) - assert_equal({ foo: 1, baz: 3 }, { foo: 1, bar: 2, baz: 3 }.without(:bar)) + assert_equal [3, 4, 5], GenericEnumerable.new((1..5).to_a).without([1, 2]) end def test_pluck |