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

ruby-changes:65498

From: Kenichi <ko1@a...>
Date: Sat, 20 Mar 2021 20:46:28 +0900 (JST)
Subject: [ruby-changes:65498] 7954bb056b (master): Some Hash destructive methods ensure the receiver modifiable [Bug #17736]

https://git.ruby-lang.org/ruby.git/commit/?id=7954bb056b

From 7954bb056be30e86c419fe3792064d28990a4999 Mon Sep 17 00:00:00 2001
From: Kenichi Kamiya <kachick1@g...>
Date: Sat, 20 Mar 2021 19:35:36 +0900
Subject: Some Hash destructive methods ensure the receiver modifiable [Bug
 #17736]

refs:

* https://bugs.ruby-lang.org/issues/17736
* https://github.com/ruby/ruby/pull/4296

This commit aims to cover following methods

* Hash#select!
* Hash#filter!
* Hash#keep_if
* Hash#reject!
* Hash#delete_if

I think these are not all.

---

* Ensure the receiver is modifiable or not
* Assert the receiver is not modified
---
 hash.c                 |  2 ++
 test/ruby/test_hash.rb | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/hash.c b/hash.c
index e9a3ca9..8f51f46 100644
--- a/hash.c
+++ b/hash.c
@@ -2476,6 +2476,7 @@ static int https://github.com/ruby/ruby/blob/trunk/hash.c#L2476
 delete_if_i(VALUE key, VALUE value, VALUE hash)
 {
     if (RTEST(rb_yield_values(2, key, value))) {
+	rb_hash_modify(hash);
 	return ST_DELETE;
     }
     return ST_CONTINUE;
@@ -2705,6 +2706,7 @@ static int https://github.com/ruby/ruby/blob/trunk/hash.c#L2706
 keep_if_i(VALUE key, VALUE value, VALUE hash)
 {
     if (!RTEST(rb_yield_values(2, key, value))) {
+	rb_hash_modify(hash);
 	return ST_DELETE;
     }
     return ST_CONTINUE;
diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb
index 3458053..849fd3a 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -439,6 +439,15 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L439
       true
     }
     assert_equal(base.size, n)
+
+    h = base.dup
+    assert_raise(FrozenError) do
+      h.delete_if do
+        h.freeze
+        true
+      end
+    end
+    assert_equal(base.dup, h)
   end
 
   def test_keep_if
@@ -446,6 +455,14 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L455
     assert_equal({3=>4,5=>6}, h.keep_if {|k, v| k + v >= 7 })
     h = @cls[1=>2,3=>4,5=>6]
     assert_equal({1=>2,3=>4,5=>6}, h.keep_if{true})
+    h = @cls[1=>2,3=>4,5=>6]
+    assert_raise(FrozenError) do
+      h.keep_if do
+        h.freeze
+        false
+      end
+    end
+    assert_equal(@cls[1=>2,3=>4,5=>6], h)
   end
 
   def test_compact
@@ -743,6 +760,15 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L760
     h = base.dup
     assert_equal(h3, h.reject! {|k,v| v })
     assert_equal(h3, h)
+
+    h = base.dup
+    assert_raise(FrozenError) do
+      h.reject! do
+        h.freeze
+        true
+      end
+    end
+    assert_equal(base.dup, h)
   end
 
   def test_replace
@@ -1046,6 +1072,14 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L1072
     assert_equal({3=>4,5=>6}, h)
     h = @cls[1=>2,3=>4,5=>6]
     assert_equal(nil, h.select!{true})
+    h = @cls[1=>2,3=>4,5=>6]
+    assert_raise(FrozenError) do
+      h.select! do
+        h.freeze
+        false
+      end
+    end
+    assert_equal(@cls[1=>2,3=>4,5=>6], h)
   end
 
   def test_slice
@@ -1098,6 +1132,14 @@ class TestHash < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_hash.rb#L1132
     assert_equal({3=>4,5=>6}, h)
     h = @cls[1=>2,3=>4,5=>6]
     assert_equal(nil, h.filter!{true})
+    h = @cls[1=>2,3=>4,5=>6]
+    assert_raise(FrozenError) do
+      h.filter! do
+        h.freeze
+        false
+      end
+    end
+    assert_equal(@cls[1=>2,3=>4,5=>6], h)
   end
 
   def test_clear2
-- 
cgit v1.1


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

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