diff --git a/NEWS b/NEWS index ab27497082..272b9ba475 100644 --- a/NEWS +++ b/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) diff --git a/array.c b/array.c index f97447f7ea..1d536284d5 100644 --- a/array.c +++ b/array.c @@ -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); diff --git a/enum.c b/enum.c index 0df4461430..b9b9ca7b7a 100644 --- a/enum.c +++ b/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); diff --git a/enumerator.c b/enumerator.c index 0c2ce19502..ba470a4492 100644 --- a/enumerator.c +++ b/enumerator.c @@ -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); diff --git a/hash.c b/hash.c index d2ca057e33..3a499872ad 100644 --- a/hash.c +++ b/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); diff --git a/lib/set.rb b/lib/set.rb index 9642e74af4..e639636c97 100644 --- a/lib/set.rb +++ b/lib/set.rb @@ -424,6 +424,9 @@ class Set 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) diff --git a/spec/ruby/core/array/filter_spec.rb b/spec/ruby/core/array/filter_spec.rb new file mode 100644 index 0000000000..d7c722e44c --- /dev/null +++ b/spec/ruby/core/array/filter_spec.rb @@ -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 diff --git a/spec/ruby/core/array/select_spec.rb b/spec/ruby/core/array/select_spec.rb index 8b83acaa5f..b7531c967d 100644 --- a/spec/ruby/core/array/select_spec.rb +++ b/spec/ruby/core/array/select_spec.rb @@ -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 diff --git a/spec/ruby/core/array/shared/select.rb b/spec/ruby/core/array/shared/select.rb new file mode 100644 index 0000000000..e09231415d --- /dev/null +++ b/spec/ruby/core/array/shared/select.rb @@ -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 diff --git a/spec/ruby/core/enumerable/filter_spec.rb b/spec/ruby/core/enumerable/filter_spec.rb new file mode 100644 index 0000000000..7f4bdd6d59 --- /dev/null +++ b/spec/ruby/core/enumerable/filter_spec.rb @@ -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 diff --git a/spec/ruby/core/hash/filter_spec.rb b/spec/ruby/core/hash/filter_spec.rb new file mode 100644 index 0000000000..46c7bea8e8 --- /dev/null +++ b/spec/ruby/core/hash/filter_spec.rb @@ -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 diff --git a/spec/ruby/core/hash/select_spec.rb b/spec/ruby/core/hash/select_spec.rb index 9348cc4c39..f8d66d09fd 100644 --- a/spec/ruby/core/hash/select_spec.rb +++ b/spec/ruby/core/hash/select_spec.rb @@ -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 diff --git a/spec/ruby/core/hash/shared/select.rb b/spec/ruby/core/hash/shared/select.rb new file mode 100644 index 0000000000..3ffd901cea --- /dev/null +++ b/spec/ruby/core/hash/shared/select.rb @@ -0,0 +1,91 @@ +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__) + +describe :hash_select, shared: true 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 }.send(@method) { |*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 }.send(@method) { |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.send(@method) { |*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.send(@method).should be_an_instance_of(Enumerator) + end + + it "returns an Enumerator when called on an empty hash without a block" do + @empty.send(@method).should be_an_instance_of(Enumerator) + end + + it_should_behave_like :hash_iteration_no_block + + before :each do + @object = { 1 => 2, 3 => 4, 5 => 6 } + end + it_should_behave_like :enumeratorized_with_origin_size +end + +describe :hash_select!, shared: true 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.send(@method) { |k,v| v <= 1 }.should equal h + + h = { 1 => 2, 3 => 4 } + all_args_select = [] + h.dup.send(@method) { |*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.send(@method) { |k,v| false }.should equal(h) + h.should == {} + end + + it "returns nil if no changes were made" do + { a: 1 }.send(@method) { |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.send(@method) { 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.send(@method) { true } }.should raise_error(frozen_error_class) + end + + it_should_behave_like :hash_iteration_no_block + + before :each do + @object = { 1 => 2, 3 => 4, 5 => 6 } + end + it_should_behave_like :enumeratorized_with_origin_size +end diff --git a/spec/ruby/library/set/filter_spec.rb b/spec/ruby/library/set/filter_spec.rb new file mode 100644 index 0000000000..3ac0c660b2 --- /dev/null +++ b/spec/ruby/library/set/filter_spec.rb @@ -0,0 +1,6 @@ +require File.expand_path('../../../spec_helper', __FILE__) +require File.expand_path('../shared/select', __FILE__) + +describe "Set#filter!" do + it_behaves_like :set_select_bang, :filter! +end diff --git a/spec/ruby/library/set/select_spec.rb b/spec/ruby/library/set/select_spec.rb index 34274a7c46..433fbb4617 100644 --- a/spec/ruby/library/set/select_spec.rb +++ b/spec/ruby/library/set/select_spec.rb @@ -1,42 +1,6 @@ require File.expand_path('../../../spec_helper', __FILE__) -require 'set' +require File.expand_path('../shared/select', __FILE__) describe "Set#select!" do - before :each do - @set = Set["one", "two", "three"] - end - - it "yields every element of self" do - ret = [] - @set.select! { |x| ret << x } - ret.sort.should == ["one", "two", "three"].sort - end - - it "keeps every element from self for which the passed block returns true" do - @set.select! { |x| x.size != 3 } - @set.size.should eql(1) - - @set.should_not include("one") - @set.should_not include("two") - @set.should include("three") - end - - it "returns self when self was modified" do - @set.select! { false }.should equal(@set) - end - - it "returns nil when self was not modified" do - @set.select! { true }.should be_nil - end - - it "returns an Enumerator when passed no block" do - enum = @set.select! - enum.should be_an_instance_of(Enumerator) - - enum.each { |x| x.size != 3 } - - @set.should_not include("one") - @set.should_not include("two") - @set.should include("three") - end + it_behaves_like :set_select_bang, :select! end diff --git a/spec/ruby/library/set/shared/select.rb b/spec/ruby/library/set/shared/select.rb new file mode 100644 index 0000000000..c9f01b8a25 --- /dev/null +++ b/spec/ruby/library/set/shared/select.rb @@ -0,0 +1,42 @@ +require File.expand_path('../../../../spec_helper', __FILE__) +require 'set' + +describe :set_select_bang, shared: true do + before :each do + @set = Set["one", "two", "three"] + end + + it "yields every element of self" do + ret = [] + @set.send(@method) { |x| ret << x } + ret.sort.should == ["one", "two", "three"].sort + end + + it "keeps every element from self for which the passed block returns true" do + @set.send(@method) { |x| x.size != 3 } + @set.size.should eql(1) + + @set.should_not include("one") + @set.should_not include("two") + @set.should include("three") + end + + it "returns self when self was modified" do + @set.send(@method) { false }.should equal(@set) + end + + it "returns nil when self was not modified" do + @set.send(@method) { true }.should be_nil + end + + it "returns an Enumerator when passed no block" do + enum = @set.send(@method) + enum.should be_an_instance_of(Enumerator) + + enum.each { |x| x.size != 3 } + + @set.should_not include("one") + @set.should_not include("two") + @set.should include("three") + end +end diff --git a/spec/ruby/library/set/sortedset/filter_spec.rb b/spec/ruby/library/set/sortedset/filter_spec.rb new file mode 100644 index 0000000000..59e264ed84 --- /dev/null +++ b/spec/ruby/library/set/sortedset/filter_spec.rb @@ -0,0 +1,7 @@ +require File.expand_path('../../../../spec_helper', __FILE__) +require File.expand_path('../shared/select', __FILE__) +require 'set' + +describe "SortedSet#filter!" do + it_behaves_like :sorted_set_select_bang, :filter! +end diff --git a/spec/ruby/library/set/sortedset/select_spec.rb b/spec/ruby/library/set/sortedset/select_spec.rb index 3ca748350a..b00525346c 100644 --- a/spec/ruby/library/set/sortedset/select_spec.rb +++ b/spec/ruby/library/set/sortedset/select_spec.rb @@ -1,35 +1,7 @@ require File.expand_path('../../../../spec_helper', __FILE__) +require File.expand_path('../shared/select', __FILE__) require 'set' describe "SortedSet#select!" do - before :each do - @set = SortedSet["one", "two", "three"] - end - - it "yields each Object in self in sorted order" do - res = [] - @set.select! { |x| res << x } - res.should == ["one", "two", "three"].sort - end - - it "keeps every element from self for which the passed block returns true" do - @set.select! { |x| x.size != 3 } - @set.to_a.should == ["three"] - end - - it "returns self when self was modified" do - @set.select! { false }.should equal(@set) - end - - it "returns nil when self was not modified" do - @set.select! { true }.should be_nil - end - - it "returns an Enumerator when passed no block" do - enum = @set.select! - enum.should be_an_instance_of(Enumerator) - - enum.each { |x| x.size != 3 } - @set.to_a.should == ["three"] - end + it_behaves_like :sorted_set_select_bang, :select! end diff --git a/spec/ruby/library/set/sortedset/shared/select.rb b/spec/ruby/library/set/sortedset/shared/select.rb new file mode 100644 index 0000000000..d3ce4ed33a --- /dev/null +++ b/spec/ruby/library/set/sortedset/shared/select.rb @@ -0,0 +1,35 @@ +require File.expand_path('../../../../../spec_helper', __FILE__) +require 'set' + +describe :sorted_set_select_bang, shared: true do + before :each do + @set = SortedSet["one", "two", "three"] + end + + it "yields each Object in self in sorted order" do + res = [] + @set.send(@method) { |x| res << x } + res.should == ["one", "two", "three"].sort + end + + it "keeps every element from self for which the passed block returns true" do + @set.send(@method) { |x| x.size != 3 } + @set.to_a.should == ["three"] + end + + it "returns self when self was modified" do + @set.send(@method) { false }.should equal(@set) + end + + it "returns nil when self was not modified" do + @set.send(@method) { true }.should be_nil + end + + it "returns an Enumerator when passed no block" do + enum = @set.send(@method) + enum.should be_an_instance_of(Enumerator) + + enum.each { |x| x.size != 3 } + @set.to_a.should == ["three"] + end +end diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index 955121c0f0..39bf635079 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -170,6 +170,7 @@ class TestArray < Test::Unit::TestCase def test_find_all_0 assert_respond_to([], :find_all) assert_respond_to([], :select) # Alias + assert_respond_to([], :filter) # Alias assert_equal([], [].find_all{ |obj| obj == "foo"}) x = ["foo", "bar", "baz", "baz", 1, 2, 3, 3, 4] @@ -2301,6 +2302,25 @@ class TestArray < Test::Unit::TestCase assert_equal(@cls[4, 5], a) end + def test_filter + assert_equal([0, 2], [0, 1, 2, 3].filter {|x| x % 2 == 0 }) + end + + # alias for select! + def test_filter! + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(nil, a.filter! { true }) + assert_equal(@cls[1, 2, 3, 4, 5], a) + + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(a, a.filter! { false }) + assert_equal(@cls[], a) + + a = @cls[ 1, 2, 3, 4, 5 ] + assert_equal(a, a.filter! { |i| i > 3 }) + assert_equal(@cls[4, 5], a) + end + def test_delete2 a = [0] * 1024 + [1] + [0] * 1024 a.delete(0) diff --git a/test/ruby/test_enumerator.rb b/test/ruby/test_enumerator.rb index 235dfbfc9b..86cab539ab 100644 --- a/test/ruby/test_enumerator.rb +++ b/test/ruby/test_enumerator.rb @@ -505,7 +505,7 @@ class TestEnumerator < Test::Unit::TestCase def test_size_for_enum_created_from_array arr = %w[hello world] %i[each each_with_index reverse_each sort_by! sort_by map map! - keep_if reject! reject select! select delete_if].each do |method| + keep_if reject! reject select! select filter! filter delete_if].each do |method| assert_equal arr.size, arr.send(method).size end end @@ -522,7 +522,7 @@ class TestEnumerator < Test::Unit::TestCase def test_size_for_enum_created_from_hash h = {a: 1, b: 2, c: 3} - methods = %i[delete_if reject reject! select select! keep_if each each_key each_pair] + methods = %i[delete_if reject reject! select select! filter filter! keep_if each each_key each_pair] enums = methods.map {|method| h.send(method)} s = enums.group_by(&:size) assert_equal([3], s.keys, ->{s.reject!{|k| k==3}.inspect}) @@ -532,7 +532,7 @@ class TestEnumerator < Test::Unit::TestCase end def test_size_for_enum_created_from_env - %i[each_pair reject! delete_if select select! keep_if].each do |method| + %i[each_pair reject! delete_if select select! filter filter! keep_if].each do |method| assert_equal ENV.size, ENV.send(method).size end end diff --git a/test/ruby/test_env.rb b/test/ruby/test_env.rb index ffed94efa6..699f7db084 100644 --- a/test/ruby/test_env.rb +++ b/test/ruby/test_env.rb @@ -222,6 +222,18 @@ class TestEnv < Test::Unit::TestCase assert_nil(ENV.select! {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" }) end + def test_filter_bang + h1 = {} + ENV.each_pair {|k, v| h1[k] = v } + ENV["test"] = "foo" + ENV.filter! {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" } + h2 = {} + ENV.each_pair {|k, v| h2[k] = v } + assert_equal(h1, h2) + + assert_nil(ENV.filter! {|k, v| IGNORE_CASE ? k.upcase != "TEST" : k != "test" }) + end + def test_keep_if h1 = {} ENV.each_pair {|k, v| h1[k] = v } @@ -254,6 +266,21 @@ class TestEnv < Test::Unit::TestCase end end + def test_filter + ENV["test"] = "foo" + h = ENV.filter {|k| IGNORE_CASE ? k.upcase == "TEST" : k == "test" } + assert_equal(1, h.size) + k = h.keys.first + v = h.values.first + if IGNORE_CASE + assert_equal("TEST", k.upcase) + assert_equal("FOO", v.upcase) + else + assert_equal("test", k) + assert_equal("foo", v) + end + end + def test_clear ENV.clear assert_equal(0, ENV.size) diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index 55e46584b4..088178defa 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -1017,6 +1017,44 @@ class TestHash < Test::Unit::TestCase assert_equal({}, {}.slice) end + def test_filter + assert_equal({3=>4,5=>6}, @cls[1=>2,3=>4,5=>6].filter {|k, v| k + v >= 7 }) + + base = @cls[ 1 => 'one', '2' => false, true => 'true', 'cat' => 99 ] + h1 = @cls[ '2' => false, 'cat' => 99 ] + h2 = @cls[ 1 => 'one', true => 'true' ] + h3 = @cls[ 1 => 'one', true => 'true', 'cat' => 99 ] + + h = base.dup + assert_equal(h, h.filter { true }) + assert_equal(@cls[], h.filter { false }) + + h = base.dup + assert_equal(h1, h.filter {|k,v| k.instance_of?(String) }) + + assert_equal(h2, h.filter {|k,v| v.instance_of?(String) }) + + assert_equal(h3, h.filter {|k,v| v }) + assert_equal(base, h) + + h.instance_variable_set(:@foo, :foo) + h.default = 42 + h.taint + h = h.filter {true} + assert_instance_of(Hash, h) + assert_not_predicate(h, :tainted?) + assert_nil(h.default) + assert_not_send([h, :instance_variable_defined?, :@foo]) + end + + def test_filter! + h = @cls[1=>2,3=>4,5=>6] + assert_equal(h, h.filter! {|k, v| k + v >= 7 }) + assert_equal({3=>4,5=>6}, h) + h = @cls[1=>2,3=>4,5=>6] + assert_equal(nil, h.filter!{true}) + end + def test_clear2 assert_equal({}, @cls[1=>2,3=>4,5=>6].clear) h = @cls[1=>2,3=>4,5=>6] diff --git a/test/test_set.rb b/test/test_set.rb index 4c6730d141..b20920e63e 100644 --- a/test/test_set.rb +++ b/test/test_set.rb @@ -545,6 +545,24 @@ class TC_Set < Test::Unit::TestCase assert_equal(Set.new(1..10), set) end + def test_filter! + set = Set.new(1..10) + ret = set.filter! { |i| i <= 10 } + assert_equal(nil, ret) + assert_equal(Set.new(1..10), set) + + set = Set.new(1..10) + ret = set.filter! { |i| i % 3 != 0 } + assert_same(set, ret) + assert_equal(Set[1,2,4,5,7,8,10], set) + + set = Set.new(1..10) + enum = set.filter! + assert_equal(set.size, enum.size) + assert_equal(nil, enum.each { |i| i <= 10 }) + assert_equal(Set.new(1..10), set) + end + def test_merge set = Set[1,2,3]