Skip to content
Permalink
Browse files

Added Array#including, Array#excluding, Enumerable#including, Enumera…

…ble#excluding
  • Loading branch information...
dhh committed Mar 6, 2019
1 parent 91ed21b commit bfaa3091c3c32b5980a614ef0f7b39cbf83f6db3
@@ -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).
@@ -29,16 +29,28 @@ def to(position)
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>.
@@ -97,23 +97,43 @@ def many?
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)
@@ -32,6 +32,16 @@ def test_specific_accessor
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
@@ -217,11 +217,17 @@ def test_exclude?
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

0 comments on commit bfaa309

Please sign in to comment.
You can’t perform that action at this time.