[前][次][番号順一覧][スレッド一覧]

ruby-changes:23401

From: nobu <ko1@a...>
Date: Tue, 24 Apr 2012 12:47:16 +0900 (JST)
Subject: [ruby-changes:23401] nobu:r35452 (trunk): * hash.c, object.c, struct.c, lib/ostruct.rb: add to_h methods.

nobu	2012-04-24 12:46:55 +0900 (Tue, 24 Apr 2012)

  New Revision: 35452

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=35452

  Log:
    * hash.c, object.c, struct.c, lib/ostruct.rb: add to_h methods.
      [Feature #6276]

  Modified files:
    trunk/ChangeLog
    trunk/NEWS
    trunk/hash.c
    trunk/lib/ostruct.rb
    trunk/object.c
    trunk/struct.c
    trunk/test/ostruct/test_ostruct.rb
    trunk/test/ruby/test_env.rb
    trunk/test/ruby/test_hash.rb
    trunk/test/ruby/test_struct.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 35451)
+++ ChangeLog	(revision 35452)
@@ -1,3 +1,8 @@
+Tue Apr 24 12:46:50 2012  Marc-Andre Lafortune  <ruby-core@m...>
+
+	* hash.c, object.c, struct.c, lib/ostruct.rb: add to_h methods.
+	  [Feature #6276]
+
 Tue Apr 24 10:54:34 2012  NAKAMURA Usaku  <usa@r...>
 
 	* test/drb/drbtest.rb ({DRbCore,DRbAry}#teardown}: cannot pass SIGTERM
Index: object.c
===================================================================
--- object.c	(revision 35451)
+++ object.c	(revision 35452)
@@ -1058,7 +1058,24 @@
 }
 
 /*
+ * Document-method: to_h
+ *
  *  call-seq:
+ *     nil.to_h    -> {}
+ *
+ *  Always returns an empty hash.
+ *
+ *     nil.to_h   #=> {}
+ */
+
+static VALUE
+nil_to_h(VALUE obj)
+{
+    return rb_hash_new();
+}
+
+/*
+ *  call-seq:
  *    nil.inspect  -> "nil"
  *
  *  Always returns the string "nil".
@@ -2896,6 +2913,7 @@
     rb_define_method(rb_cNilClass, "to_f", nil_to_f, 0);
     rb_define_method(rb_cNilClass, "to_s", nil_to_s, 0);
     rb_define_method(rb_cNilClass, "to_a", nil_to_a, 0);
+    rb_define_method(rb_cNilClass, "to_h", nil_to_h, 0);
     rb_define_method(rb_cNilClass, "inspect", nil_inspect, 0);
     rb_define_method(rb_cNilClass, "&", false_and, 1);
     rb_define_method(rb_cNilClass, "|", false_or, 1);
Index: lib/ostruct.rb
===================================================================
--- lib/ostruct.rb	(revision 35451)
+++ lib/ostruct.rb	(revision 35452)
@@ -101,6 +101,19 @@
   end
 
   #
+  # Converts the OpenStruct to a hash with keys representing
+  # each attribute (as symbols) and their corresponding values
+  # Example:
+  #
+  #   require 'ostruct'
+  #   data = OpenStruct.new("country" => "Australia", :population => 20_000_000)
+  #   data.to_h   # => {:country => "Australia", :population => 20000000 }
+  #
+  def to_h
+    @table.dup
+  end
+
+  #
   # Provides marshalling support for use by the Marshal library. Returning the
   # underlying Hash table that contains the functions defined as the keys and
   # the values assigned to them.
Index: struct.c
===================================================================
--- struct.c	(revision 35451)
+++ struct.c	(revision 35452)
@@ -586,6 +586,31 @@
     return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_PTR(s));
 }
 
+/*
+ *  call-seq:
+ *     struct.to_h     -> hash
+ *
+ *  Returns the values for this instance as a hash with keys
+ *  corresponding to the instance variable name.
+ *
+ *     Customer = Struct.new(:name, :address, :zip)
+ *     joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
+ *     joe.to_h[:address]   #=> "123 Maple, Anytown NC"
+ */
+
+static VALUE
+rb_struct_to_h(VALUE s)
+{
+    VALUE h = rb_hash_new();
+    VALUE members = rb_struct_members(s);
+    long i;
+
+    for (i=0; i<RSTRUCT_LEN(s); i++) {
+	rb_hash_aset(h, rb_ary_entry(members, i), RSTRUCT_PTR(s)[i]);
+    }
+    return h;
+}
+
 /* :nodoc: */
 VALUE
 rb_struct_init_copy(VALUE copy, VALUE s)
@@ -961,6 +986,7 @@
     rb_define_method(rb_cStruct, "inspect", rb_struct_inspect, 0);
     rb_define_alias(rb_cStruct,  "to_s", "inspect");
     rb_define_method(rb_cStruct, "to_a", rb_struct_to_a, 0);
+    rb_define_method(rb_cStruct, "to_h", rb_struct_to_h, 0);
     rb_define_method(rb_cStruct, "values", rb_struct_to_a, 0);
     rb_define_method(rb_cStruct, "size", rb_struct_size, 0);
     rb_define_method(rb_cStruct, "length", rb_struct_size, 0);
Index: hash.c
===================================================================
--- hash.c	(revision 35451)
+++ hash.c	(revision 35452)
@@ -1452,6 +1452,30 @@
     return hash;
 }
 
+/*
+ *  call-seq:
+ *     hsh.to_h     -> hsh or new_hash
+ *
+ *  Returns +self+. If called on a subclass of Hash, converts
+ *  the receiver to a Hash object.
+ */
+
+static VALUE
+rb_hash_to_h(VALUE hash)
+{
+    if (rb_obj_class(hash) != rb_cHash) {
+	VALUE ret = rb_hash_new();
+	if (!RHASH_EMPTY_P(hash))
+	    RHASH(ret)->ntbl = st_copy(RHASH(hash)->ntbl);
+	if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
+	    FL_SET(ret, HASH_PROC_DEFAULT);
+	}
+	RHASH_IFNONE(ret) = RHASH_IFNONE(hash);
+	return ret;
+    }
+    return hash;
+}
+
 static int
 keys_i(VALUE key, VALUE value, VALUE ary)
 {
@@ -3054,7 +3078,8 @@
 
 /*
  * call-seq:
- *   ENV.to_hash -> Hash
+ *   ENV.to_hash -> hash
+ *   ENV.to_h    -> hash
  *
  * Creates a hash with a copy of the environment variables.
  *
@@ -3333,6 +3358,7 @@
     rb_define_method(rb_cHash,"rehash", rb_hash_rehash, 0);
 
     rb_define_method(rb_cHash,"to_hash", rb_hash_to_hash, 0);
+    rb_define_method(rb_cHash,"to_h", rb_hash_to_h, 0);
     rb_define_method(rb_cHash,"to_a", rb_hash_to_a, 0);
     rb_define_method(rb_cHash,"inspect", rb_hash_inspect, 0);
     rb_define_alias(rb_cHash, "to_s", "inspect");
@@ -3443,6 +3469,7 @@
     rb_define_singleton_method(envtbl,"key?", env_has_key, 1);
     rb_define_singleton_method(envtbl,"value?", env_has_value, 1);
     rb_define_singleton_method(envtbl,"to_hash", env_to_hash, 0);
+    rb_define_singleton_method(envtbl,"to_h", env_to_hash, 0);
     rb_define_singleton_method(envtbl,"assoc", env_assoc, 1);
     rb_define_singleton_method(envtbl,"rassoc", env_rassoc, 1);
 
Index: NEWS
===================================================================
--- NEWS	(revision 35451)
+++ NEWS	(revision 35452)
@@ -21,7 +21,13 @@
     * added method:
       * added Enumerable#lazy method for lazy enumeration.
 
+  * ENV
+    * aliased method:
+      * ENV.to_h is a new alias for ENV.to_hash
+
   * Hash
+    * added method:
+      * added Hash#to_h as explicit conversion method, like Array#to_a.
     * extended method:
       * Hash#default_proc= can be passed nil to clear the default proc.
 
@@ -41,11 +47,20 @@
       * added LoadError#path method to return the file name that could not be
         loaded.
 
+  * NilClass
+    * added method:
+      * added nil.to_h which returns {}
+
   * Signal
     * incompatible changes:
       * Signal.trap raises ArgumentError when :SEGV, :BUS, :ILL, :FPE, :VTALRM
         are specified.
 
+  * Struct
+    * added method:
+      * added Struct#to_h returning values with keys corresponding to the
+        instance variable names.
+
   * Time
     * change return value:
       * Time#to_s returned encoding defaults to US-ASCII but automatically
@@ -63,6 +78,10 @@
     * Net::IMAP.default_ssl_port
     * Net::IMAP.default_imaps_port
 
+* ostruct
+  * new methods:
+    * OpenStruct#to_h converts the struct to a hash.
+
 * pathname
   * extended method:
     * Pathname#find returns an enumerator if no block is given.
Index: test/ruby/test_struct.rb
===================================================================
--- test/ruby/test_struct.rb	(revision 35451)
+++ test/ruby/test_struct.rb	(revision 35452)
@@ -263,4 +263,10 @@
     end
     assert_equal("Insecure: can't modify #{st}::S", error.message, bug5036)
   end
+
+  def test_to_h
+    klass = Struct.new(:a, :b, :c, :d, :e, :f)
+    o = klass.new(1, 2, 3, 4, 5, 6)
+    assert_equal({a:1, b:2, c:3, d:4, e:5, f:6}, o.to_h)
+  end
 end
Index: test/ruby/test_hash.rb
===================================================================
--- test/ruby/test_hash.rb	(revision 35451)
+++ test/ruby/test_hash.rb	(revision 35452)
@@ -77,7 +77,7 @@
   # From rubicon
 
   def setup
-    @cls = Hash
+    @cls ||= Hash
     @h = @cls[
       1 => 'one', 2 => 'two', 3 => 'three',
       self => 'self', true => 'true', nil => 'nil',
@@ -631,8 +631,22 @@
   def test_to_hash
     h = @h.to_hash
     assert_equal(@h, h)
+    assert_instance_of(@cls, h)
   end
 
+  def test_to_h
+    h = @h.to_h
+    assert_equal(@h, h)
+    assert_instance_of(Hash, h)
+  end
+
+  def test_nil_to_h
+    h = nil.to_h
+    assert_equal({}, h)
+    assert_nil(h.default)
+    assert_nil(h.default_proc)
+  end
+
   def test_to_s
     h = @cls[ 1 => 2, "cat" => "dog", 1.5 => :fred ]
     assert_equal(h.inspect, h.to_s)
@@ -932,4 +946,14 @@
       assert_not_equal(h.hash, h.invert.hash, feature4262)
     end
   end
+
+  class TestSubHash < TestHash
+    class SubHash < Hash
+    end
+
+    def setup
+      @cls = SubHash
+      super
+    end
+  end
 end
Index: test/ruby/test_env.rb
===================================================================
--- test/ruby/test_env.rb	(revision 35451)
+++ test/ruby/test_env.rb	(revision 35452)
@@ -327,6 +327,10 @@
     assert_equal(h, ENV.to_hash)
   end
 
+  def test_to_h
+    assert_equal(ENV.to_hash, ENV.to_h)
+  end
+
   def test_reject
     h1 = {}
     ENV.each_pair {|k, v| h1[k] = v }
Index: test/ostruct/test_ostruct.rb
===================================================================
--- test/ostruct/test_ostruct.rb	(revision 35451)
+++ test/ostruct/test_ostruct.rb	(revision 35452)
@@ -73,4 +73,16 @@
     assert_raise(NoMethodError) { o[:foo] }
   end
 
+  def test_to_h
+    h = {name: "John Smith", age: 70, pension: 300}
+    os = OpenStruct.new(h)
+    to_h = os.to_h
+    assert_equal(h, to_h)
+
+    to_h[:age] = 71
+    assert_equal(70, os.age)
+    assert_equal(70, h[:age])
+
+    assert_equal(h, OpenStruct.new("name" => "John Smith", "age" => 70, pension: 300).to_h)
+  end
 end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]