aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hash.c52
-rw-r--r--test/ruby/test_env.rb11
-rw-r--r--test/ruby/test_hash.rb8
3 files changed, 71 insertions, 0 deletions
diff --git a/hash.c b/hash.c
index 742480d974..3babff59f3 100644
--- a/hash.c
+++ b/hash.c
@@ -2824,6 +2824,33 @@ rb_hash_slice(int argc, VALUE *argv, VALUE hash)
/*
* 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:
* hash.values_at(*keys) -> new_array
*
* Returns a new \Array containing values for the given +keys+:
@@ -6878,6 +6905,29 @@ env_to_h(VALUE _)
}
/*
+ * 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, VALUE _)
+{
+ 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 of name/value pairs
* ENV.reject -> an_enumerator
@@ -7543,6 +7593,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);
@@ -7678,6 +7729,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", 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 6a44cf17dd..c1109cb2ef 100644
--- a/test/ruby/test_env.rb
+++ b/test/ruby/test_env.rb
@@ -287,6 +287,17 @@ class TestEnv < Test::Unit::TestCase
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 c0ec078403..e63fdf32fd 100644
--- a/test/ruby/test_hash.rb
+++ b/test/ruby/test_hash.rb
@@ -1036,6 +1036,14 @@ class TestHash < Test::Unit::TestCase
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 })