diff --git a/hash.c b/hash.c
index d2ca057e33..a26bfeec2f 100644
--- a/hash.c
+++ b/hash.c
@@ -1185,6 +1185,41 @@ rb_hash_delete_m(VALUE hash, VALUE key)
}
}
+/*
+ * call-seq:
+ * hsh.delete!(key) -> value
+ *
+ * Deletes the key-value pair and returns the value from hsh whose
+ * key is equal to key. If the key is not found, it raises a
+ * KeyError error.
+ *
+ * h = { "a" => 100, "b" => 200 }
+ * h.delete!("a") #=> 100
+ * h.delete!("z") #=> KeyError
+ *
+ */
+
+static VALUE
+rb_hash_delete_bang_m(VALUE hash, VALUE key)
+{
+ VALUE val;
+
+ rb_hash_modify_check(hash);
+ val = rb_hash_delete_entry(hash, key);
+
+ if (val != Qundef) {
+ return val;
+ }
+ else {
+ VALUE desc = rb_protect(rb_inspect, key, 0);
+ if (NIL_P(desc)) {
+ desc = rb_any_to_s(key);
+ }
+ desc = rb_str_ellipsize(desc, 65);
+ rb_key_err_raise(rb_sprintf("key not found: %"PRIsVALUE, desc), hash, key);
+ }
+}
+
struct shift_var {
VALUE key;
VALUE val;
@@ -4686,6 +4721,7 @@ Init_Hash(void)
rb_define_method(rb_cHash, "shift", rb_hash_shift, 0);
rb_define_method(rb_cHash, "delete", rb_hash_delete_m, 1);
+ rb_define_method(rb_cHash, "delete!", rb_hash_delete_bang_m, 1);
rb_define_method(rb_cHash, "delete_if", rb_hash_delete_if, 0);
rb_define_method(rb_cHash, "keep_if", rb_hash_keep_if, 0);
rb_define_method(rb_cHash, "select", rb_hash_select, 0);
diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb
index 55e46584b4..279c9f3f06 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -383,6 +383,23 @@ def test_delete
assert_equal('default 99', h1.delete(99) {|i| "default #{i}" })
end
+ def test_delete!
+ h1 = @cls[ 1 => 'one', 2 => 'two', true => 'true' ]
+ h2 = @cls[ 1 => 'one', 2 => 'two' ]
+ h3 = @cls[ 2 => 'two' ]
+
+ assert_equal('true', h1.delete!(true))
+ assert_equal(h2, h1)
+
+ assert_equal('one', h1.delete!(1))
+ assert_equal(h3, h1)
+
+ assert_equal('two', h1.delete!(2))
+ assert_equal(@cls[], h1)
+
+ assert_raise(KeyError) { h1.delete!(99) }
+ end
+
def test_delete_if
base = @cls[ 1 => 'one', 2 => false, true => 'true', 'cat' => 99 ]
h1 = @cls[ 1 => 'one', 2 => false, true => 'true' ]