Skip to content
Permalink
Browse files

Add a new #filter alias for #select

* In Enumerable, Enumerator::Lazy, Array, Hash and Set
  [Feature #13784] [ruby-core:82285]
* Share specs for the various #select#select! methods and
  reuse them for #filter/#filter!.
* Add corresponding filter tests for select tests.
* Update NEWS.

[Fix GH-1824]

From: Alexander Patrick <adp90@case.edu>

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62575 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information...
eregon committed Feb 25, 2018
1 parent d1ea2f9 commit b1a8c64483b5ba5e4a391aa68234e7bde6355034
32 NEWS
@@ -20,6 +20,13 @@ with all sufficient information, see the ChangeLog file or Redmine

=== Core classes updates (outstanding ones only)

* Array

* Aliased methods:

* Array#filter is a new alias for Array#select [Feature #13784]
* Array#filter! is a new alias for Array#select! [Feature #13784]

* Binding

* New methods:
@@ -40,6 +47,25 @@ with all sufficient information, see the ChangeLog file or Redmine

* added Dir#each_child and Dir#children instance methods. [Feature #13969]

* Enumerable

* Aliased methods:

* Enumerable#filter is a new alias for Enumerable#select [Feature #13784]

* Enumerator::Lazy

* Aliased methods:

* Enumerator::Lazy#filter is a new alias for Enumerator::Lazy#select [Feature #13784]

* Hash

* Aliased methods:

* Hash#filter is a new alias for Hash#select [Feature #13784]
* Hash#filter! is a new alias for Hash#select! [Feature #13784]

* Kernel

* Kernel.#system takes :exception option to raise an exception on
@@ -80,6 +106,12 @@ with all sufficient information, see the ChangeLog file or Redmine

* Matrix#antisymmetric?

* Set

* Aliased methods:

* Set#filter! is a new alias for Set#select! [Feature #13784]

=== Compatibility issues (excluding feature bug fixes)

=== Stdlib compatibility issues (excluding feature bug fixes)
@@ -6298,6 +6298,8 @@ Init_Array(void)
rb_define_method(rb_cArray, "map!", rb_ary_collect_bang, 0);
rb_define_method(rb_cArray, "select", rb_ary_select, 0);
rb_define_method(rb_cArray, "select!", rb_ary_select_bang, 0);
rb_define_method(rb_cArray, "filter", rb_ary_select, 0);
rb_define_method(rb_cArray, "filter!", rb_ary_select_bang, 0);
rb_define_method(rb_cArray, "keep_if", rb_ary_keep_if, 0);
rb_define_method(rb_cArray, "values_at", rb_ary_values_at, -1);
rb_define_method(rb_cArray, "delete", rb_ary_delete, 1);
5 enum.c
@@ -388,8 +388,10 @@ enum_size_over_p(VALUE obj, long n)
* call-seq:
* enum.find_all { |obj| block } -> array
* enum.select { |obj| block } -> array
* enum.filter { |obj| block } -> array
* enum.find_all -> an_enumerator
* enum.select -> an_enumerator
* enum.filter -> an_enumerator
*
* Returns an array containing all elements of +enum+
* for which the given +block+ returns a true value.
@@ -401,6 +403,8 @@ enum_size_over_p(VALUE obj, long n)
*
* [1,2,3,4,5].select { |num| num.even? } #=> [2, 4]
*
* [:foo, :bar].filter { |x| x == :foo } #=> [:foo]
*
* See also Enumerable#reject.
*/

@@ -3994,6 +3998,7 @@ Init_Enumerable(void)
rb_define_method(rb_mEnumerable, "find_index", enum_find_index, -1);
rb_define_method(rb_mEnumerable, "find_all", enum_find_all, 0);
rb_define_method(rb_mEnumerable, "select", enum_find_all, 0);
rb_define_method(rb_mEnumerable, "filter", enum_find_all, 0);
rb_define_method(rb_mEnumerable, "reject", enum_reject, 0);
rb_define_method(rb_mEnumerable, "collect", enum_collect, 0);
rb_define_method(rb_mEnumerable, "map", enum_collect, 0);
@@ -2377,6 +2377,7 @@ InitVM_Enumerator(void)
rb_define_method(rb_cLazy, "collect_concat", lazy_flat_map, 0);
rb_define_method(rb_cLazy, "select", lazy_select, 0);
rb_define_method(rb_cLazy, "find_all", lazy_select, 0);
rb_define_method(rb_cLazy, "filter", lazy_select, 0);
rb_define_method(rb_cLazy, "reject", lazy_reject, 0);
rb_define_method(rb_cLazy, "grep", lazy_grep, 1);
rb_define_method(rb_cLazy, "grep_v", lazy_grep_v, 1);
4 hash.c
@@ -4690,6 +4690,8 @@ Init_Hash(void)
rb_define_method(rb_cHash, "keep_if", rb_hash_keep_if, 0);
rb_define_method(rb_cHash, "select", rb_hash_select, 0);
rb_define_method(rb_cHash, "select!", rb_hash_select_bang, 0);
rb_define_method(rb_cHash, "filter", rb_hash_select, 0);
rb_define_method(rb_cHash, "filter!", rb_hash_select_bang, 0);
rb_define_method(rb_cHash, "reject", rb_hash_reject, 0);
rb_define_method(rb_cHash, "reject!", rb_hash_reject_bang, 0);
rb_define_method(rb_cHash, "slice", rb_hash_slice, -1);
@@ -4752,6 +4754,8 @@ Init_Hash(void)
rb_define_singleton_method(envtbl, "reject!", env_reject_bang, 0);
rb_define_singleton_method(envtbl, "select", env_select, 0);
rb_define_singleton_method(envtbl, "select!", env_select_bang, 0);
rb_define_singleton_method(envtbl, "filter", env_select, 0);
rb_define_singleton_method(envtbl, "filter!", env_select_bang, 0);
rb_define_singleton_method(envtbl, "shift", env_shift, 0);
rb_define_singleton_method(envtbl, "invert", env_invert, 0);
rb_define_singleton_method(envtbl, "replace", env_replace, 1);
@@ -424,6 +424,9 @@ def select!(&block)
self if size != n
end

# Equivalent to Set#select!
alias filter! select!

# Merges the elements of the given enumerable object to the set and
# returns self.
def merge(enum)
@@ -0,0 +1,14 @@
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../shared/select', __FILE__)

describe "Array#filter" do
it_behaves_like :array_select, :filter
end

describe "Array#filter!" do
it "returns nil if no changes were made in the array" do
[1, 2, 3].filter! { true }.should be_nil
end

it_behaves_like :keep_if, :filter!
end
@@ -1,30 +1,8 @@
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../fixtures/classes', __FILE__)
require File.expand_path('../shared/enumeratorize', __FILE__)
require File.expand_path('../shared/keep_if', __FILE__)
require File.expand_path('../../enumerable/shared/enumeratorized', __FILE__)
require File.expand_path('../shared/select', __FILE__)

describe "Array#select" do
it_behaves_like :enumeratorize, :select
it_behaves_like :enumeratorized_with_origin_size, :select, [1,2,3]

it "returns a new array of elements for which block is true" do
[1, 3, 4, 5, 6, 9].select { |i| i % ((i + 1) / 2) == 0}.should == [1, 4, 6]
end

it "does not return subclass instance on Array subclasses" do
ArraySpecs::MyArray[1, 2, 3].select { true }.should be_an_instance_of(Array)
end

it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
empty.select { true }.should == empty
empty.select { false }.should == []

array = ArraySpecs.recursive_array
array.select { true }.should == [1, 'two', 3.0, array, array, array, array, array]
array.select { false }.should == []
end
it_behaves_like :array_select, :select
end

describe "Array#select!" do
@@ -0,0 +1,32 @@
require File.expand_path('../../../../spec_helper', __FILE__)
require File.expand_path('../../fixtures/classes', __FILE__)
require File.expand_path('../../shared/enumeratorize', __FILE__)
require File.expand_path('../../shared/keep_if', __FILE__)
require File.expand_path('../../../enumerable/shared/enumeratorized', __FILE__)

describe :array_select, shared: true do
it_should_behave_like :enumeratorize

before :each do
@object = [1,2,3]
end
it_should_behave_like :enumeratorized_with_origin_size

it "returns a new array of elements for which block is true" do
[1, 3, 4, 5, 6, 9].send(@method) { |i| i % ((i + 1) / 2) == 0}.should == [1, 4, 6]
end

it "does not return subclass instance on Array subclasses" do
ArraySpecs::MyArray[1, 2, 3].send(@method) { true }.should be_an_instance_of(Array)
end

it "properly handles recursive arrays" do
empty = ArraySpecs.empty_recursive_array
empty.send(@method) { true }.should == empty
empty.send(@method) { false }.should == []

array = ArraySpecs.recursive_array
array.send(@method) { true }.should == [1, 'two', 3.0, array, array, array, array, array]
array.send(@method) { false }.should == []
end
end
@@ -0,0 +1,7 @@
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../fixtures/classes', __FILE__)
require File.expand_path('../shared/find_all', __FILE__)

describe "Enumerable#filter" do
it_behaves_like(:enumerable_find_all , :filter)
end
@@ -0,0 +1,10 @@
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../shared/select', __FILE__)

describe "Hash#filter" do
it_behaves_like :hash_select, :filter
end

describe "Hash#filter!" do
it_behaves_like :hash_select!, :filter!
end
@@ -1,83 +1,10 @@
require File.expand_path('../../../spec_helper', __FILE__)
require File.expand_path('../fixtures/classes', __FILE__)
require File.expand_path('../shared/iteration', __FILE__)
require File.expand_path('../../enumerable/shared/enumeratorized', __FILE__)
require File.expand_path('../shared/select', __FILE__)

describe "Hash#select" do
before :each do
@hsh = { 1 => 2, 3 => 4, 5 => 6 }
@empty = {}
end

it "yields two arguments: key and value" do
all_args = []
{ 1 => 2, 3 => 4 }.select { |*args| all_args << args }
all_args.sort.should == [[1, 2], [3, 4]]
end

it "returns a Hash of entries for which block is true" do
a_pairs = { 'a' => 9, 'c' => 4, 'b' => 5, 'd' => 2 }.select { |k,v| v % 2 == 0 }
a_pairs.should be_an_instance_of(Hash)
a_pairs.sort.should == [['c', 4], ['d', 2]]
end

it "processes entries with the same order as reject" do
h = { a: 9, c: 4, b: 5, d: 2 }

select_pairs = []
reject_pairs = []
h.dup.select { |*pair| select_pairs << pair }
h.reject { |*pair| reject_pairs << pair }

select_pairs.should == reject_pairs
end

it "returns an Enumerator when called on a non-empty hash without a block" do
@hsh.select.should be_an_instance_of(Enumerator)
end

it "returns an Enumerator when called on an empty hash without a block" do
@empty.select.should be_an_instance_of(Enumerator)
end

it_behaves_like :hash_iteration_no_block, :select
it_behaves_like :enumeratorized_with_origin_size, :select, { 1 => 2, 3 => 4, 5 => 6 }
it_behaves_like :hash_select, :select
end

describe "Hash#select!" do
before :each do
@hsh = { 1 => 2, 3 => 4, 5 => 6 }
@empty = {}
end

it "is equivalent to keep_if if changes are made" do
h = { a: 2 }
h.select! { |k,v| v <= 1 }.should equal h

h = { 1 => 2, 3 => 4 }
all_args_select = []
h.dup.select! { |*args| all_args_select << args }
all_args_select.should == [[1, 2], [3, 4]]
end

it "removes all entries if the block is false" do
h = { a: 1, b: 2, c: 3 }
h.select! { |k,v| false }.should equal(h)
h.should == {}
end

it "returns nil if no changes were made" do
{ a: 1 }.select! { |k,v| v <= 1 }.should == nil
end

it "raises a #{frozen_error_class} if called on an empty frozen instance" do
lambda { HashSpecs.empty_frozen_hash.select! { false } }.should raise_error(frozen_error_class)
end

it "raises a #{frozen_error_class} if called on a frozen instance that would not be modified" do
lambda { HashSpecs.frozen_hash.select! { true } }.should raise_error(frozen_error_class)
end

it_behaves_like :hash_iteration_no_block, :select!
it_behaves_like :enumeratorized_with_origin_size, :select!, { 1 => 2, 3 => 4, 5 => 6 }
it_behaves_like :hash_select!, :select!
end
Oops, something went wrong.

0 comments on commit b1a8c64

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.