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/