summaryrefslogtreecommitdiff
path: root/hash.c
diff options
context:
space:
mode:
authormatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-03-03 09:44:44 +0000
committermatz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-03-03 09:44:44 +0000
commit871e9d175e07e364802f00c945cec56ef42084df (patch)
treeedbe6570cf15491eed37c7c929eca6e6143d59e8 /hash.c
parent800dda6c28aad062d1d3c3342fb3dcd23ae790f3 (diff)
* hash.c (rb_hash_select_bang): add #select! and keep_if to Hash.
* hash.c (env_select_bang): ..and to ENV. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@26803 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'hash.c')
-rw-r--r--hash.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/hash.c b/hash.c
index 51537e91b6..5eba21654e 100644
--- a/hash.c
+++ b/hash.c
@@ -990,6 +990,57 @@ rb_hash_select(VALUE hash)
}
static int
+keep_if_i(VALUE key, VALUE value, VALUE hash)
+{
+ if (key == Qundef) return ST_CONTINUE;
+ if (!RTEST(rb_yield_values(2, key, value))) {
+ return ST_DELETE;
+ }
+ return ST_CONTINUE;
+}
+
+/*
+ * call-seq:
+ * hsh.select! {| key, value | block } -> hsh or nil
+ *
+ * Equivalent to <code>Hash#keep_if</code>, but returns
+ * <code>nil</code> if no changes were made.
+ */
+
+VALUE
+rb_hash_select_bang(VALUE hash)
+{
+ st_index_t n;
+
+ RETURN_ENUMERATOR(hash, 0, 0);
+ rb_hash_modify(hash);
+ if (!RHASH(hash)->ntbl)
+ return Qnil;
+ n = RHASH(hash)->ntbl->num_entries;
+ rb_hash_foreach(hash, keep_if_i, hash);
+ if (n == RHASH(hash)->ntbl->num_entries) return Qnil;
+ return hash;
+}
+
+/*
+ * call-seq:
+ * hsh.keep_if {| key, value | block } -> hsh
+ *
+ * Deletes every key-value pair from <i>hsh</i> for which <i>block</i>
+ * evaluates to <code>false</code>.
+ *
+ */
+
+VALUE
+rb_hash_keep_if(VALUE hash)
+{
+ RETURN_ENUMERATOR(hash, 0, 0);
+ rb_hash_modify(hash);
+ rb_hash_foreach(hash, keep_if_i, hash);
+ return hash;
+}
+
+static int
clear_i(VALUE key, VALUE value, VALUE dummy)
{
return ST_DELETE;
@@ -2367,6 +2418,37 @@ env_select(VALUE ehash)
return result;
}
+static VALUE
+env_select_bang(VALUE ehash)
+{
+ volatile VALUE keys;
+ long i;
+ int del = 0;
+
+ RETURN_ENUMERATOR(ehash, 0, 0);
+ keys = env_keys(); /* rb_secure(4); */
+ for (i=0; i<RARRAY_LEN(keys); i++) {
+ VALUE val = rb_f_getenv(Qnil, RARRAY_PTR(keys)[i]);
+ if (!NIL_P(val)) {
+ if (!RTEST(rb_yield_values(2, RARRAY_PTR(keys)[i], val))) {
+ FL_UNSET(RARRAY_PTR(keys)[i], FL_TAINT);
+ env_delete(Qnil, RARRAY_PTR(keys)[i]);
+ del++;
+ }
+ }
+ }
+ if (del == 0) return Qnil;
+ return envtbl;
+}
+
+static VALUE
+env_keep_if(VALUE ehash)
+{
+ RETURN_ENUMERATOR(ehash, 0, 0);
+ env_select_bang(ehash);
+ return envtbl;
+}
+
VALUE
rb_env_clear(void)
{
@@ -2755,7 +2837,9 @@ Init_Hash(void)
rb_define_method(rb_cHash,"shift", rb_hash_shift, 0);
rb_define_method(rb_cHash,"delete", rb_hash_delete, 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);
+ rb_define_method(rb_cHash,"select!", rb_hash_select_bang, 0);
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,"clear", rb_hash_clear, 0);
@@ -2792,10 +2876,12 @@ Init_Hash(void)
rb_define_singleton_method(envtbl,"each_value", env_each_value, 0);
rb_define_singleton_method(envtbl,"delete", env_delete_m, 1);
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,"clear", rb_env_clear, 0);
rb_define_singleton_method(envtbl,"reject", env_reject, 0);
rb_define_singleton_method(envtbl,"reject!", env_reject_bang, 0);
rb_define_singleton_method(envtbl,"select", env_select, 0);
+ rb_define_singleton_method(envtbl,"select!", env_select_bang, 0);
rb_define_singleton_method(envtbl,"shift", env_shift, 0);
rb_define_singleton_method(envtbl,"invert", env_invert, 0);
rb_define_singleton_method(envtbl,"replace", env_replace, 1);