From c7a37c10ade8372c712be01a7e4ddbe8785c5139 Mon Sep 17 00:00:00 2001 From: Todd Bealmear Date: Sun, 1 Mar 2015 17:44:36 -0800 Subject: Add Enumerable#without --- activesupport/CHANGELOG.md | 5 +++++ activesupport/lib/active_support/core_ext/array/grouping.rb | 12 ++++++++++++ activesupport/lib/active_support/core_ext/enumerable.rb | 11 +++++++++++ activesupport/test/core_ext/enumerable_test.rb | 7 +++++++ guides/source/active_support_core_extensions.md | 11 +++++++++++ 5 files changed, 46 insertions(+) diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 35be823ea1..43fb87f203 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,8 @@ +* Added `#without` on `Enumerable` and `Array` to return a copy of an + enumerable without the specified elements. + + *Todd Bealmear* + * Fixed a problem where String#truncate_words would get stuck with a complex string. diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb index 87ae052eb0..b3ada47880 100644 --- a/activesupport/lib/active_support/core_ext/array/grouping.rb +++ b/activesupport/lib/active_support/core_ext/array/grouping.rb @@ -113,4 +113,16 @@ class Array results end end + + # Returns a copy of the Array without the specified elements. + # + # people = ["David", "Rafael", "Aaron", "Todd"] + # people.without "Aaron", "Todd" + # => ["David", "Rafael"] + # + # Note: This is an optimization of `Enumerable#without` that uses `Array#-` + # instead of `Array#reject` for performance reasons. + def without(*elements) + self - elements + end end diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index 1343beb87a..d699cf4241 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -60,6 +60,17 @@ module Enumerable def exclude?(object) !include?(object) end + + # Returns a copy of the enumerable without the specified elements. + # + # ["David", "Rafael", "Aaron", "Todd"].without "Aaron", "Todd" + # => ["David", "Rafael"] + # + # {foo: 1, bar: 2, baz: 3}.without :bar + # => {foo: 1, baz: 3} + def without(*elements) + reject { |element| element.in?(elements) } + end end class Range #:nodoc: diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index 346dc3d208..e5d8ae7882 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -103,4 +103,11 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal true, GenericEnumerable.new([ 1 ]).exclude?(2) assert_equal false, GenericEnumerable.new([ 1 ]).exclude?(1) 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)) + end end diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md index 2e7f776319..66626f41d1 100644 --- a/guides/source/active_support_core_extensions.md +++ b/guides/source/active_support_core_extensions.md @@ -2182,6 +2182,17 @@ to_visit << node if visited.exclude?(node) NOTE: Defined in `active_support/core_ext/enumerable.rb`. +### `without` + +The method `without` returns a copy of an enumerable with the specified elements +removed: + +```ruby +people.without("Aaron", "Todd") +``` + +NOTE: Defined in `active_support/core_ext/enumerable.rb`. + Extensions to `Array` --------------------- -- cgit v1.2.3