Change Hash#compact to keep default values and compare_by_identity flag

The documentation states it returns a copy of self with nil value
entries removed.  However, the previous behavior was creating a
plain new hash with non-nil values copied into it.  This change
aligns the behavior with the documentation.

Fixes [Bug #19113]
This commit is contained in:
Jeremy Evans 2022-11-09 09:59:25 -08:00
Родитель 1b13db25d8
Коммит 5d6579bd91
2 изменённых файлов: 29 добавлений и 11 удалений

16
hash.c
Просмотреть файл

@ -4307,15 +4307,6 @@ delete_if_nil(VALUE key, VALUE value, VALUE hash)
return ST_CONTINUE;
}
static int
set_if_not_nil(VALUE key, VALUE value, VALUE hash)
{
if (!NIL_P(value)) {
rb_hash_aset(hash, key, value);
}
return ST_CONTINUE;
}
/*
* call-seq:
* hash.compact -> new_hash
@ -4329,9 +4320,12 @@ set_if_not_nil(VALUE key, VALUE value, VALUE hash)
static VALUE
rb_hash_compact(VALUE hash)
{
VALUE result = rb_hash_new();
VALUE result = rb_hash_dup(hash);
if (!RHASH_EMPTY_P(hash)) {
rb_hash_foreach(hash, set_if_not_nil, result);
rb_hash_foreach(result, delete_if_nil, result);
}
else if (rb_hash_compare_by_id_p(hash)) {
result = rb_hash_compare_by_id(result);
}
return result;
}

Просмотреть файл

@ -18,6 +18,30 @@ describe "Hash#compact" do
@hash.compact
@hash.should == @initial_pairs
end
ruby_version_is '3.3' do
it "retains the default value" do
hash = Hash.new(1)
hash.compact.default.should == 1
hash[:a] = 1
hash.compact.default.should == 1
end
it "retains the default_proc" do
pr = proc { |h, k| h[k] = [] }
hash = Hash.new(&pr)
hash.compact.default_proc.should == pr
hash[:a] = 1
hash.compact.default_proc.should == pr
end
it "retains compare_by_identity_flag" do
hash = {}.compare_by_identity
hash.compact.compare_by_identity?.should == true
hash[:a] = 1
hash.compact.compare_by_identity?.should == true
end
end
end
describe "Hash#compact!" do