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

ruby-changes:14932

From: matz <ko1@a...>
Date: Wed, 3 Mar 2010 18:45:05 +0900 (JST)
Subject: [ruby-changes:14932] Ruby:r26803 (trunk): * hash.c (rb_hash_select_bang): add #select! and keep_if to Hash.

matz	2010-03-03 18:44:44 +0900 (Wed, 03 Mar 2010)

  New Revision: 26803

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=26803

  Log:
    * hash.c (rb_hash_select_bang): add #select! and keep_if to Hash.
    
    * hash.c (env_select_bang): ..and to ENV.

  Modified files:
    trunk/ChangeLog
    trunk/hash.c
    trunk/test/ruby/test_hash.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 26802)
+++ ChangeLog	(revision 26803)
@@ -1,3 +1,9 @@
+Wed Mar  3 18:35:55 2010  Yukihiro Matsumoto  <matz@r...>
+
+	* hash.c (rb_hash_select_bang): add #select! and keep_if to Hash.
+
+	* hash.c (env_select_bang): ..and to ENV.
+
 Wed Mar  3 15:54:20 2010  Yukihiro Matsumoto  <matz@r...>
 
 	* lib/matrix.rb (Vector#each2, collect2): small refactoring.
Index: hash.c
===================================================================
--- hash.c	(revision 26802)
+++ hash.c	(revision 26803)
@@ -990,6 +990,57 @@
 }
 
 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 @@
     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 @@
     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 @@
     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);
Index: test/ruby/test_hash.rb
===================================================================
--- test/ruby/test_hash.rb	(revision 26802)
+++ test/ruby/test_hash.rb	(revision 26803)
@@ -290,6 +290,13 @@
     assert_equal(base.size, n)
   end
 
+  def test_delete_if
+    h = {1=>2,3=>4,5=>6}
+    assert_equal({3=>4,5=>6}, h.keep_if {|k, v| k + v >= 7 })
+    h = {1=>2,3=>4,5=>6}
+    assert_equal({1=>2,3=>4,5=>6}, h.keep_if{true})
+  end
+
   def test_dup
     for taint in [ false, true ]
       for untrust in [ false, true ]
@@ -736,6 +743,14 @@
     assert_equal({3=>4,5=>6}, {1=>2,3=>4,5=>6}.select {|k, v| k + v >= 7 })
   end
 
+  def test_select!
+    h = {1=>2,3=>4,5=>6}
+    assert_equal(h, h.select! {|k, v| k + v >= 7 })
+    assert_equal({3=>4,5=>6}, h)
+    h = {1=>2,3=>4,5=>6}
+    assert_equal(nil, h.select!{true})
+  end
+
   def test_clear2
     assert_equal({}, {1=>2,3=>4,5=>6}.clear)
     h = {1=>2,3=>4,5=>6}

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

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