Feature #11286 » 0001-enum.c-add-case-equality-arity-to-sequence-predicates.patch
| ChangeLog | ||
|---|---|---|
| 
     Fri Jun 19 16:10:22 2015  D.E. Akers  <0x0dea@gmail.com> 
   | 
||
| 
     	* enum.c: add case equality arity to sequence predicates. 
   | 
||
| 
     	* test/ruby/test_enum.rb: add tests for above. 
   | 
||
| 
     Fri Jun 19 14:53:35 2015  Nobuyoshi Nakada  <nobu@ruby-lang.org> 
   | 
||
| 
     	* proc.c (rb_mod_define_method): now requires a block direct to 
   | 
||
| enum.c | ||
|---|---|---|
| 
         return ary; 
   | 
||
| 
     } 
   | 
||
| 
     #define ENUMFUNC(name) rb_block_given_p() ? name##_iter_i : name##_i 
   | 
||
| 
     #define ENUMFUNC(name, argc) argc ? name##_eqq : rb_block_given_p() ? name##_iter_i : name##_i 
   | 
||
| 
     #define DEFINE_ENUMFUNCS(name) \ 
   | 
||
| 
     static VALUE enum_##name##_func(VALUE result, struct MEMO *memo); \ 
   | 
||
| ... | ... | |
| 
     } \ 
   | 
||
| 
     \ 
   | 
||
| 
     static VALUE \ 
   | 
||
| 
     name##_eqq(RB_BLOCK_CALL_FUNC_ARGLIST(i, memo)) \ 
   | 
||
| 
     { \ 
   | 
||
| 
         return enum_##name##_func(rb_funcall(MEMO_CAST(memo)->v2, id_eqq, 1, i), MEMO_CAST(memo)); \ 
   | 
||
| 
     } \ 
   | 
||
| 
     \ 
   | 
||
| 
     static VALUE \ 
   | 
||
| 
     enum_##name##_func(VALUE result, struct MEMO *memo) 
   | 
||
| 
     DEFINE_ENUMFUNCS(all) 
   | 
||
| ... | ... | |
| 
     /* 
   | 
||
| 
      *  call-seq: 
   | 
||
| 
      *     enum.all? [{ |obj| block } ]   -> true or false 
   | 
||
| 
      *     enum.all?(pattern)             -> true or false 
   | 
||
| 
      * 
   | 
||
| 
      *  Passes each element of the collection to the given block. The method 
   | 
||
| 
      *  returns <code>true</code> if the block never returns 
   | 
||
| ... | ... | |
| 
      *  cause #all? to return +true+ when none of the collection members are 
   | 
||
| 
      *  +false+ or +nil+. 
   | 
||
| 
      * 
   | 
||
| 
      *  If instead a pattern is supplied, the method returns whether 
   | 
||
| 
      *  <code>pattern === element</code> for every element of <i>enum</i>. 
   | 
||
| 
      * 
   | 
||
| 
      *     %w[ant bear cat].all? { |word| word.length >= 3 } #=> true 
   | 
||
| 
      *     %w[ant bear cat].all? { |word| word.length >= 4 } #=> false 
   | 
||
| 
      *     %w[ant bear cat].all?(/t/)                        #=> false 
   | 
||
| 
      *     [1, 2i, 3.14].all?(Numeric)                       #=> true 
   | 
||
| 
      *     [nil, true, 99].all?                              #=> false 
   | 
||
| 
      * 
   | 
||
| 
      */ 
   | 
||
| 
     static VALUE 
   | 
||
| 
     enum_all(VALUE obj) 
   | 
||
| 
     enum_all(int argc, VALUE *argv, VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         struct MEMO *memo = MEMO_NEW(Qtrue, 0, 0); 
   | 
||
| 
         rb_block_call(obj, id_each, 0, 0, ENUMFUNC(all), (VALUE)memo); 
   | 
||
| 
         struct MEMO *memo = MEMO_NEW(Qtrue, *argv, 0); 
   | 
||
| 
         rb_check_arity(argc, 0, 1); 
   | 
||
| 
         rb_block_call(obj, id_each, 0, 0, ENUMFUNC(all, argc), (VALUE)memo); 
   | 
||
| 
         return memo->v1; 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     /* 
   | 
||
| 
      *  call-seq: 
   | 
||
| 
      *     enum.any? [{ |obj| block }]   -> true or false 
   | 
||
| 
      *     enum.any?(pattern)            -> true or false 
   | 
||
| 
      * 
   | 
||
| 
      *  Passes each element of the collection to the given block. The method 
   | 
||
| 
      *  returns <code>true</code> if the block ever returns a value other 
   | 
||
| ... | ... | |
| 
      *  will cause #any? to return +true+ if at least one of the collection 
   | 
||
| 
      *  members is not +false+ or +nil+. 
   | 
||
| 
      * 
   | 
||
| 
      *  If instead a pattern is supplied, the method returns whether 
   | 
||
| 
      *  <code>pattern === element</code> for any element of <i>enum</i>. 
   | 
||
| 
      * 
   | 
||
| 
      *     %w[ant bear cat].any? { |word| word.length >= 3 } #=> true 
   | 
||
| 
      *     %w[ant bear cat].any? { |word| word.length >= 4 } #=> true 
   | 
||
| 
      *     %w[ant bear cat].any?(/d/)                        #=> false 
   | 
||
| 
      *     [nil, true, 99].any?                              #=> true 
   | 
||
| 
      *     [nil, true, 99].any?(Float)                       #=> false 
   | 
||
| 
      * 
   | 
||
| 
      */ 
   | 
||
| 
     static VALUE 
   | 
||
| 
     enum_any(VALUE obj) 
   | 
||
| 
     enum_any(int argc, VALUE *argv, VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         struct MEMO *memo = MEMO_NEW(Qfalse, 0, 0); 
   | 
||
| 
         rb_block_call(obj, id_each, 0, 0, ENUMFUNC(any), (VALUE)memo); 
   | 
||
| 
         struct MEMO *memo = MEMO_NEW(Qfalse, *argv, 0); 
   | 
||
| 
         rb_check_arity(argc, 0, 1); 
   | 
||
| 
         rb_block_call(obj, id_each, 0, 0, ENUMFUNC(any, argc), (VALUE)memo); 
   | 
||
| 
         return memo->v1; 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
     /* 
   | 
||
| 
      *  call-seq: 
   | 
||
| 
      *     enum.one? [{ |obj| block }]   -> true or false 
   | 
||
| 
      *     enum.one?(pattern)            -> true or false 
   | 
||
| 
      * 
   | 
||
| 
      *  Passes each element of the collection to the given block. The method 
   | 
||
| 
      *  returns <code>true</code> if the block returns <code>true</code> 
   | 
||
| ... | ... | |
| 
      *  <code>true</code> only if exactly one of the collection members is 
   | 
||
| 
      *  true. 
   | 
||
| 
      * 
   | 
||
| 
      *  If instead a pattern is supplied, the method returns whether 
   | 
||
| 
      *  <code>pattern === element</code> for exactly one element of <i>enum</i>. 
   | 
||
| 
      * 
   | 
||
| 
      *     %w{ant bear cat}.one? { |word| word.length == 4 }  #=> true 
   | 
||
| 
      *     %w{ant bear cat}.one? { |word| word.length > 4 }   #=> false 
   | 
||
| 
      *     %w{ant bear cat}.one? { |word| word.length < 4 }   #=> false 
   | 
||
| 
      *     %w{ant bear cat}.one?(/t/)                         #=> false 
   | 
||
| 
      *     [ nil, true, 99 ].one?                             #=> false 
   | 
||
| 
      *     [ nil, true, false ].one?                          #=> true 
   | 
||
| 
      *     [ nil, true, 99 ].one?(Fixnum)                     #=> true 
   | 
||
| 
      * 
   | 
||
| 
      */ 
   | 
||
| 
     static VALUE 
   | 
||
| 
     enum_one(VALUE obj) 
   | 
||
| 
     enum_one(int argc, VALUE *argv, VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         struct MEMO *memo = MEMO_NEW(Qundef, 0, 0); 
   | 
||
| 
         struct MEMO *memo = MEMO_NEW(Qundef, *argv, 0); 
   | 
||
| 
         VALUE result; 
   | 
||
| 
         rb_block_call(obj, id_each, 0, 0, ENUMFUNC(one), (VALUE)memo); 
   | 
||
| 
         rb_check_arity(argc, 0, 1); 
   | 
||
| 
         rb_block_call(obj, id_each, 0, 0, ENUMFUNC(one, argc), (VALUE)memo); 
   | 
||
| 
         result = memo->v1; 
   | 
||
| 
         if (result == Qundef) return Qfalse; 
   | 
||
| 
         return result; 
   | 
||
| ... | ... | |
| 
     /* 
   | 
||
| 
      *  call-seq: 
   | 
||
| 
      *     enum.none? [{ |obj| block }]   -> true or false 
   | 
||
| 
      *     enum.none?(pattern)            -> true or false 
   | 
||
| 
      * 
   | 
||
| 
      *  Passes each element of the collection to the given block. The method 
   | 
||
| 
      *  returns <code>true</code> if the block never returns <code>true</code> 
   | 
||
| 
      *  for all elements. If the block is not given, <code>none?</code> will return 
   | 
||
| 
      *  <code>true</code> only if none of the collection members is true. 
   | 
||
| 
      * 
   | 
||
| 
      *  If instead a pattern is supplied, the method returns whether 
   | 
||
| 
      *  <code>pattern === element</code> for none of the elements of <i>enum</i>. 
   | 
||
| 
      * 
   | 
||
| 
      *     %w{ant bear cat}.none? { |word| word.length == 5 } #=> true 
   | 
||
| 
      *     %w{ant bear cat}.none? { |word| word.length >= 4 } #=> false 
   | 
||
| 
      *     %w{ant bear cat}.none?(/d/)                        #=> true 
   | 
||
| 
      *     [].none?                                           #=> true 
   | 
||
| 
      *     [nil].none?                                        #=> true 
   | 
||
| 
      *     [nil, false].none?                                 #=> true 
   | 
||
| 
      *     [nil, false].none?(NilClass)                       #=> false 
   | 
||
| 
      */ 
   | 
||
| 
     static VALUE 
   | 
||
| 
     enum_none(VALUE obj) 
   | 
||
| 
     enum_none(int argc, VALUE *argv, VALUE obj) 
   | 
||
| 
     { 
   | 
||
| 
         struct MEMO *memo = MEMO_NEW(Qtrue, 0, 0); 
   | 
||
| 
         rb_block_call(obj, id_each, 0, 0, ENUMFUNC(none), (VALUE)memo); 
   | 
||
| 
         struct MEMO *memo = MEMO_NEW(Qtrue, *argv, 0); 
   | 
||
| 
         rb_check_arity(argc, 0, 1); 
   | 
||
| 
         rb_block_call(obj, id_each, 0, 0, ENUMFUNC(none, argc), (VALUE)memo); 
   | 
||
| 
         return memo->v1; 
   | 
||
| 
     } 
   | 
||
| ... | ... | |
| 
         rb_define_method(rb_mEnumerable, "partition", enum_partition, 0); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "group_by", enum_group_by, 0); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "first", enum_first, -1); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "all?", enum_all, 0); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "any?", enum_any, 0); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "one?", enum_one, 0); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "none?", enum_none, 0); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "all?", enum_all, -1); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "any?", enum_any, -1); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "one?", enum_one, -1); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "none?", enum_none, -1); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "min", enum_min, -1); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "max", enum_max, -1); 
   | 
||
| 
         rb_define_method(rb_mEnumerable, "minmax", enum_minmax, 0); 
   | 
||
| test/ruby/test_enum.rb | ||
|---|---|---|
| 
         assert_equal(false, @obj.all? {|x| x < 3 }) 
   | 
||
| 
         assert_equal(true, @obj.all?) 
   | 
||
| 
         assert_equal(false, [true, true, false].all?) 
   | 
||
| 
         assert_equal(true, @obj.all?(Fixnum)) 
   | 
||
| 
         assert_equal(false, @obj.all?(1..2)) 
   | 
||
| 
       end 
   | 
||
| 
       def test_any 
   | 
||
| ... | ... | |
| 
         assert_equal(false, @obj.any? {|x| x > 3 }) 
   | 
||
| 
         assert_equal(true, @obj.any?) 
   | 
||
| 
         assert_equal(false, [false, false, false].any?) 
   | 
||
| 
         assert_equal(true, @obj.any?(1..2)) 
   | 
||
| 
         assert_equal(false, @obj.any?(Float)) 
   | 
||
| 
       end 
   | 
||
| 
       def test_one 
   | 
||
| 
         assert(@obj.one? {|x| x == 3 }) 
   | 
||
| 
         assert(!(@obj.one? {|x| x == 1 })) 
   | 
||
| 
         assert(!(@obj.one? {|x| x == 4 })) 
   | 
||
| 
         assert(@obj.one?(3..4)) 
   | 
||
| 
         assert(!(@obj.one?(1..2))) 
   | 
||
| 
         assert(!(@obj.one?(4..5))) 
   | 
||
| 
         assert(%w{ant bear cat}.one? {|word| word.length == 4}) 
   | 
||
| 
         assert(!(%w{ant bear cat}.one? {|word| word.length > 4})) 
   | 
||
| 
         assert(!(%w{ant bear cat}.one? {|word| word.length < 4})) 
   | 
||
| 
         assert(%w{ant bear cat}.one?(/b/)) 
   | 
||
| 
         assert(!(%w{ant bear cat}.one?(/t/))) 
   | 
||
| 
         assert(!([ nil, true, 99 ].one?)) 
   | 
||
| 
         assert([ nil, true, false ].one?) 
   | 
||
| 
         assert([nil, true, 99].one?(NilClass)) 
   | 
||
| 
       end 
   | 
||
| 
       def test_none 
   | 
||
| 
         assert(@obj.none? {|x| x == 4 }) 
   | 
||
| 
         assert(!(@obj.none? {|x| x == 1 })) 
   | 
||
| 
         assert(!(@obj.none? {|x| x == 3 })) 
   | 
||
| 
         assert(@obj.none?(4..5)) 
   | 
||
| 
         assert(!(@obj.none?(1..3))) 
   | 
||
| 
         assert(%w{ant bear cat}.none? {|word| word.length == 5}) 
   | 
||
| 
         assert(!(%w{ant bear cat}.none? {|word| word.length >= 4})) 
   | 
||
| 
         assert(%w{ant bear cat}.none?(/d/)) 
   | 
||
| 
         assert(!(%w{ant bear cat}.none?(/b/))) 
   | 
||
| 
         assert([].none?) 
   | 
||
| 
         assert([nil].none?) 
   | 
||
| 
         assert([nil,false].none?) 
   | 
||