From 21056753f48c146e4669cb4235f88f4c67270644 Mon Sep 17 00:00:00 2001 From: Timo Schilling Date: Sat, 4 May 2019 15:37:38 +0200 Subject: [PATCH] Add Hash#except ENV#except --- hash.c | 52 ++++++++++++++++++++++++++++++++++++++++++ test/ruby/test_env.rb | 11 +++++++++ test/ruby/test_hash.rb | 8 +++++++ 3 files changed, 71 insertions(+) diff --git a/hash.c b/hash.c index b4b0415c84b2..5b4d6f1688e7 100644 --- a/hash.c +++ b/hash.c @@ -2402,6 +2402,33 @@ rb_hash_slice(int argc, VALUE *argv, VALUE hash) return result; } +/* + * call-seq: + * hsh.except(*keys) -> a_hash + * + * Returns a hash excluding the given keys and their values. + * + * h = { a: 100, b: 200, c: 300 } + * h.except(:a) #=> {:b=>200, :c=>300} + * h.except(:b, :c, :d) #=> {:a=>100} + */ + +static VALUE +rb_hash_except(int argc, VALUE *argv, VALUE hash) +{ + int i; + VALUE key, result; + + result = rb_obj_dup(hash); + + for (i = 0; i < argc; i++) { + key = argv[i]; + rb_hash_delete(result, key); + } + + return result; +} + /* * call-seq: * hsh.values_at(key, ...) -> array @@ -5694,6 +5721,29 @@ env_to_h(void) return hash; } +/* + * call-seq: + * ENV.except(*keys) -> a_hash + * + * Returns a hash except the given keys from ENV and their values. + * + * ENV #=> {"LANG"="en_US.UTF-8", "TERM"=>"xterm-256color", "HOME"=>"/Users/rhc"} + * ENV.except("TERM","HOME") #=> {"LANG"="en_US.UTF-8"} + */ +static VALUE +env_except(int argc, VALUE *argv) +{ + int i; + VALUE key, hash = env_to_hash(); + + for (i = 0; i < argc; i++) { + key = argv[i]; + rb_hash_delete(hash, key); + } + + return hash; +} + /* * call-seq: * ENV.reject { |name, value| block } -> Hash @@ -6000,6 +6050,7 @@ Init_Hash(void) rb_define_method(rb_cHash, "reject", rb_hash_reject, 0); rb_define_method(rb_cHash, "reject!", rb_hash_reject_bang, 0); rb_define_method(rb_cHash, "slice", rb_hash_slice, -1); + rb_define_method(rb_cHash, "except", rb_hash_except, -1); rb_define_method(rb_cHash, "clear", rb_hash_clear, 0); rb_define_method(rb_cHash, "invert", rb_hash_invert, 0); rb_define_method(rb_cHash, "update", rb_hash_update, -1); @@ -6057,6 +6108,7 @@ Init_Hash(void) rb_define_singleton_method(envtbl, "delete_if", env_delete_if, 0); rb_define_singleton_method(envtbl, "keep_if", env_keep_if, 0); rb_define_singleton_method(envtbl, "slice", env_slice, -1); + rb_define_singleton_method(envtbl, "except", env_except, -1); rb_define_singleton_method(envtbl, "clear", rb_env_clear, 0); rb_define_singleton_method(envtbl, "reject", env_reject, 0); rb_define_singleton_method(envtbl, "reject!", env_reject_bang, 0); diff --git a/test/ruby/test_env.rb b/test/ruby/test_env.rb index 6343642ac1be..2dd705b49cc7 100644 --- a/test/ruby/test_env.rb +++ b/test/ruby/test_env.rb @@ -292,6 +292,17 @@ def test_slice assert_equal({"foo"=>"bar", "baz"=>"qux"}, ENV.slice("foo", "baz")) end + def test_except + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + ENV["bar"] = "rab" + assert_equal({"bar"=>"rab", "baz"=>"qux", "foo"=>"bar"}, ENV.except()) + assert_equal({"bar"=>"rab", "baz"=>"qux", "foo"=>"bar"}, ENV.except("")) + assert_equal({"bar"=>"rab", "baz"=>"qux", "foo"=>"bar"}, ENV.except("unknown")) + assert_equal({"bar"=>"rab"}, ENV.except("foo", "baz")) + end + def test_clear ENV.clear assert_equal(0, ENV.size) diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index c934d1015eb5..70c8d7decd3f 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -1053,6 +1053,14 @@ def test_slice assert_equal({}, {}.slice) end + def test_except + h = @cls[1=>2,3=>4,5=>6] + assert_equal({5=>6}, h.except(1, 3)) + assert_equal({1=>2,3=>4,5=>6}, h.except(7)) + assert_equal({1=>2,3=>4,5=>6}, h.except) + assert_equal({}, {}.except) + end + def test_filter assert_equal({3=>4,5=>6}, @cls[1=>2,3=>4,5=>6].filter {|k, v| k + v >= 7 })