Feature #12719 ยป struct_merge.patch
| ChangeLog | ||
|---|---|---|
| 
     Fri Sep  2 17:27:31 2016  Matthew Mongeau <halogenandtoast@gmail.com> 
   | 
||
| 
     	* struct.c (rb_struct_update): Add Struct#merge and Struct#merge! 
   | 
||
| 
     	for updating structs 
   | 
||
| 
     Fri Sep  2 16:06:59 2016  Nobuyoshi Nakada  <nobu@ruby-lang.org> 
   | 
||
| 
     	* internal.h (MEMO_V1_SET, MEMO_V2_SET): fix typos.  use the macro 
   | 
||
| struct.c | ||
|---|---|---|
| 
         return RSTRUCT_GET(s, i); 
   | 
||
| 
     } 
   | 
||
| 
     static int 
   | 
||
| 
     value_update(VALUE key, VALUE value, VALUE s) 
   | 
||
| 
     { 
   | 
||
| 
         rb_struct_aset(s, key, value); 
   | 
||
| 
         return ST_CONTINUE; 
   | 
||
| 
     } 
   | 
||
| 
     /* 
   | 
||
| 
      *  call-seq: 
   | 
||
| 
      *     struct.merge!(hash)    -> struct 
   | 
||
| 
      * 
   | 
||
| 
      *  Updates the values of the struct using the keys and values of the hash 
   | 
||
| 
      * 
   | 
||
| 
      *     Point = Struct.new(:x, :y) 
   | 
||
| 
      *     hash = { "x" => 5 } 
   | 
||
| 
      *     point = Point.new(1, 2) 
   | 
||
| 
      *     point.merge!(hash) 
   | 
||
| 
      * 
   | 
||
| 
      *     point.x    #=> 5 
   | 
||
| 
      */ 
   | 
||
| 
     VALUE 
   | 
||
| 
     rb_struct_update(VALUE self, VALUE hash) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE converted_hash = rb_convert_type(hash, T_HASH, "Hash", "to_hash"); 
   | 
||
| 
         rb_hash_foreach(converted_hash, value_update, self); 
   | 
||
| 
         return self; 
   | 
||
| 
     } 
   | 
||
| 
     /* 
   | 
||
| 
      *  call-seq: 
   | 
||
| 
      *     struct.merge(hash)    -> new_struct 
   | 
||
| 
      * 
   | 
||
| 
      *  Returns a new struct with updated values using the keys and values of 
   | 
||
| 
      *  the hash 
   | 
||
| 
      * 
   | 
||
| 
      *     Point = Struct.new(:x, :y) 
   | 
||
| 
      *     p = Point.new(1, 2) 
   | 
||
| 
      *     p2 = p.merge(y: 20) 
   | 
||
| 
      * 
   | 
||
| 
      *     p.y   #=> 2 
   | 
||
| 
      *     p2.y    #=> 20 
   | 
||
| 
      */ 
   | 
||
| 
     VALUE 
   | 
||
| 
     rb_struct_merge(VALUE self, VALUE hash) 
   | 
||
| 
     { 
   | 
||
| 
         VALUE dup = rb_obj_dup(self); 
   | 
||
| 
         return rb_struct_update(dup, hash); 
   | 
||
| 
     } 
   | 
||
| 
     /* 
   | 
||
| 
      *  call-seq: 
   | 
||
| 
      *     struct[member] = obj    -> obj 
   | 
||
| ... | ... | |
| 
         rb_define_method(rb_cStruct, "members", rb_struct_members_m, 0); 
   | 
||
| 
         rb_define_method(rb_cStruct, "dig", rb_struct_dig, -1); 
   | 
||
| 
         rb_define_method(rb_cStruct, "merge", rb_struct_merge, 1); 
   | 
||
| 
         rb_define_method(rb_cStruct, "merge!", rb_struct_update, 1); 
   | 
||
| 
     } 
   | 
||
| 
     #undef rb_intern 
   | 
||
| test/ruby/test_struct.rb | ||
|---|---|---|
| 
         assert_nil(o.dig(:b, 0)) 
   | 
||
| 
       end 
   | 
||
| 
       def test_merge! 
   | 
||
| 
         klass = @Struct.new(:a, :b) 
   | 
||
| 
         o = klass.new(1, 2) 
   | 
||
| 
         o.merge!(a: 10) 
   | 
||
| 
         assert_equal(o.a, 10) 
   | 
||
| 
         assert_equal(o.b, 2) 
   | 
||
| 
         o.merge!("b" => 5) 
   | 
||
| 
         assert_equal(o.b, 5) 
   | 
||
| 
         assert_raise(TypeError) { 
   | 
||
| 
           o.merge(0) 
   | 
||
| 
         } 
   | 
||
| 
       end 
   | 
||
| 
       def test_merge 
   | 
||
| 
         klass = @Struct.new(:a, :b) 
   | 
||
| 
         o = klass.new(1, 2) 
   | 
||
| 
         p = o.merge(a: 10) 
   | 
||
| 
         assert_equal(p.a, 10) 
   | 
||
| 
         assert_equal(p.b, 2) 
   | 
||
| 
         assert_equal(o.a, 1) 
   | 
||
| 
         assert_equal(o.b, 2) 
   | 
||
| 
         assert_raise(TypeError) { 
   | 
||
| 
           o.merge(0) 
   | 
||
| 
         } 
   | 
||
| 
       end 
   | 
||
| 
       def test_new_dupilicate 
   | 
||
| 
         bug12291 = '[ruby-core:74971] [Bug #12291]' 
   | 
||
| 
         assert_raise_with_message(ArgumentError, /duplicate member/, bug12291) { 
   | 
||