diff options
-rw-r--r-- | hash.c | 20 | ||||
-rw-r--r-- | spec/ruby/core/hash/constructor_spec.rb | 18 |
2 files changed, 34 insertions, 4 deletions
@@ -1801,6 +1801,8 @@ rb_hash_initialize(int argc, VALUE *argv, VALUE hash) return hash; } +static VALUE rb_hash_to_a(VALUE hash); + /* * call-seq: * Hash[] -> new_empty_hash @@ -1844,12 +1846,22 @@ rb_hash_s_create(int argc, VALUE *argv, VALUE klass) if (argc == 1) { tmp = rb_hash_s_try_convert(Qnil, argv[0]); if (!NIL_P(tmp)) { - hash = hash_alloc(klass); - hash_copy(hash, tmp); - return hash; + if (!RHASH_EMPTY_P(tmp) && rb_hash_compare_by_id_p(tmp)) { + /* hash_copy for non-empty hash will copy compare_by_identity + flag, but we don't want it copied. Work around by + converting hash to flattened array and using that. */ + tmp = rb_hash_to_a(tmp); + } + else { + hash = hash_alloc(klass); + hash_copy(hash, tmp); + return hash; + } + } + else { + tmp = rb_check_array_type(argv[0]); } - tmp = rb_check_array_type(argv[0]); if (!NIL_P(tmp)) { long i; diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb index 8fba47958f..8d29773909 100644 --- a/spec/ruby/core/hash/constructor_spec.rb +++ b/spec/ruby/core/hash/constructor_spec.rb @@ -103,8 +103,26 @@ describe "Hash.[]" do HashSpecs::MyInitializerHash[Hash[1, 2]].should be_an_instance_of(HashSpecs::MyInitializerHash) end + it "removes the default value" do + hash = Hash.new(1) + Hash[hash].default.should be_nil + hash[:a] = 1 + Hash[hash].default.should be_nil + end + it "removes the default_proc" do hash = Hash.new { |h, k| h[k] = [] } Hash[hash].default_proc.should be_nil + hash[:a] = 1 + Hash[hash].default_proc.should be_nil + end + + ruby_version_is '3.3' do + it "does not retain compare_by_identity_flag" do + hash = {}.compare_by_identity + Hash[hash].compare_by_identity?.should == false + hash[:a] = 1 + Hash[hash].compare_by_identity?.should == false + end end end |