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

ruby-changes:13418

From: akr <ko1@a...>
Date: Fri, 2 Oct 2009 20:50:26 +0900 (JST)
Subject: [ruby-changes:13418] Ruby:r25188 (trunk): * enum.c (enum_slice_before): take a pattern if no block given.

akr	2009-10-02 20:50:11 +0900 (Fri, 02 Oct 2009)

  New Revision: 25188

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

  Log:
    * enum.c (enum_slice_before): take a pattern if no block given.

  Modified files:
    trunk/ChangeLog
    trunk/enum.c
    trunk/test/ruby/test_enum.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 25187)
+++ ChangeLog	(revision 25188)
@@ -1,3 +1,7 @@
+Fri Oct  2 20:49:19 2009  Tanaka Akira  <akr@f...>
+
+	* enum.c (enum_slice_before): take a pattern if no block given.
+
 Fri Oct  2 20:37:37 2009  Nobuyoshi Nakada  <nobu@r...>
 
 	* parse.y (ripper_yylval_id, ripper_get_{id,value}): wrap ID by
Index: enum.c
===================================================================
--- enum.c	(revision 25187)
+++ enum.c	(revision 25188)
@@ -2115,7 +2115,8 @@
 
 
 struct slicebefore_arg {
-    VALUE separator_p;
+    VALUE sep_pred;
+    VALUE sep_pat;
     VALUE state;
     VALUE prev_elts;
     VALUE yielder;
@@ -2129,10 +2130,12 @@
 
     ENUM_WANT_SVALUE();
 
-    if (NIL_P(argp->state))
-        header_p = rb_funcall(argp->separator_p, rb_intern("call"), 1, i);
+    if (!NIL_P(argp->sep_pat))
+        header_p = rb_funcall(argp->sep_pat, rb_intern("==="), 1, i);
+    else if (NIL_P(argp->state))
+        header_p = rb_funcall(argp->sep_pred, rb_intern("call"), 1, i);
     else
-        header_p = rb_funcall(argp->separator_p, rb_intern("call"), 2, i, argp->state);
+        header_p = rb_funcall(argp->sep_pred, rb_intern("call"), 2, i, argp->state);
     if (RTEST(header_p)) {
         if (!NIL_P(argp->prev_elts))
             rb_funcall(argp->yielder, rb_intern("<<"), 1, argp->prev_elts);
@@ -2155,7 +2158,8 @@
     struct slicebefore_arg arg;
 
     enumerable = rb_ivar_get(enumerator, rb_intern("slicebefore_enumerable"));
-    arg.separator_p = rb_ivar_get(enumerator, rb_intern("slicebefore_separator_p"));
+    arg.sep_pred = rb_attr_get(enumerator, rb_intern("slicebefore_sep_pred"));
+    arg.sep_pat = NIL_P(arg.sep_pred) ? rb_ivar_get(enumerator, rb_intern("slicebefore_sep_pat")) : Qnil;
     arg.state = rb_ivar_get(enumerator, rb_intern("slicebefore_initial_state"));
     arg.prev_elts = Qnil;
     arg.yielder = yielder;
@@ -2171,25 +2175,36 @@
 
 /*
  *  call-seq:
+ *     enum.slice_before(pattern) => enumerator
  *     enum.slice_before {|elt| ... } => enumerator
  *     enum.slice_before(initial_state) {|elt, state| ... } => enumerator
  *
  *  Creates an enumerator for each chunked elements.
- *  The chunked elements begins an element which the block returns true value.
+ *  The beginnings of chunks are defined by _pattern_ and the block.
+ *  If _pattern_ === _elt_ returns true or 
+ *  the block returns true for the element,
+ *  the element is beginning of a chunk.
  *
  *  The result enumerator yields the chunked elements as an array.
  *  So "each" method can be called as follows.
  *
+ *    enum.slice_before(pattern).each {|ary| ... }
  *    enum.slice_before {|elt| bool }.each {|ary| ... }
  *    enum.slice_before(initial_state) {|elt, state| bool }.each {|ary| ... }
  *
- *  For example, iteration over ChangeLog entries can be implemented as follows.
+ *  For example, iteration over ChangeLog entries can be implemented as
+ *  follows.
  *
  *    # iterate over ChangeLog entries.
  *    open("ChangeLog") {|f|
- *      f.slice_before {|line| /\A\S/ =~ line }.each {|e| pp e}
+ *      f.slice_before(/\A\S/).each {|e| pp e}
  *    }
  *
+ *    # same as above.  block is used instead of pattern argument.
+ *    open("ChangeLog") {|f|
+ *      f.slice_before {|line| /\A\S/ === line }.each {|e| pp e}
+ *    }
+ *
  *  If the block needs to maintain state over multiple elements,
  *  local variables can be used.
  *  For example, monotonically increasing elements can be chunked as follows.
@@ -2243,13 +2258,12 @@
  * They can be chunked as follows: 
  *
  *    IO.popen([{"LANG"=>"C"}, "svn", "proplist", "-R"]) {|f|
- *      f.lines.slice_before {|line| /^Prop/ =~ line }.each {|lines| p lines }
+ *      f.lines.slice_before(/^Prop/).each {|lines| p lines }
  *    }
  *    #=> ["Properties on '.':\n", "  svn:ignore\n", "  svk:merge\n"]
- *    #   ["Properties on 'goruby.c':\n", "  svn:keywords\n", "  svn:eol-style\n"]
+ *    #   ["Properties on 'goruby.c':\n", "  svn:eol-style\n"]
  *    #   ["Properties on 'complex.c':\n", "  svn:mime-type\n", "  svn:eol-style\n"]
- *    #   ["Properties on 'regparse.c':\n", "  svn:keywords\n", "  svn:eol-style\n"]
- *    #   ...
+ *    #   ["Properties on 'regparse.c':\n", "  svn:eol-style\n"]
  *
  * mbox contains series of mails which start with Unix From line.
  * So each mail can be extracted by slice before Unix From line.
@@ -2284,14 +2298,22 @@
 static VALUE
 enum_slice_before(int argc, VALUE *argv, VALUE enumerable)
 {
-    VALUE initial_state, enumerator;
+    VALUE enumerator;
 
-    rb_scan_args(argc, argv, "01", &initial_state);
-
-    enumerator = rb_obj_alloc(rb_cEnumerator);
+    if (rb_block_given_p()) {
+        VALUE initial_state;
+        rb_scan_args(argc, argv, "01", &initial_state);
+        enumerator = rb_obj_alloc(rb_cEnumerator);
+        rb_ivar_set(enumerator, rb_intern("slicebefore_sep_pred"), rb_block_proc());
+        rb_ivar_set(enumerator, rb_intern("slicebefore_initial_state"), initial_state);
+    }
+    else {
+        VALUE sep_pat;
+        rb_scan_args(argc, argv, "1", &sep_pat);
+        enumerator = rb_obj_alloc(rb_cEnumerator);
+        rb_ivar_set(enumerator, rb_intern("slicebefore_sep_pat"), sep_pat);
+    }
     rb_ivar_set(enumerator, rb_intern("slicebefore_enumerable"), enumerable);
-    rb_ivar_set(enumerator, rb_intern("slicebefore_separator_p"), rb_block_proc());
-    rb_ivar_set(enumerator, rb_intern("slicebefore_initial_state"), initial_state);
     rb_block_call(enumerator, rb_intern("initialize"), 0, 0, slicebefore_i, enumerator);
     return enumerator;
 }
Index: test/ruby/test_enum.rb
===================================================================
--- test/ruby/test_enum.rb	(revision 25187)
+++ test/ruby/test_enum.rb	(revision 25188)
@@ -383,6 +383,10 @@
     assert_not_same(hs[0], hs[1])
     assert_not_same(hs[0], hs[2])
     assert_not_same(hs[1], hs[2])
+
+    ss = %w[abc defg h ijk l mno pqr st u vw xy z]
+    assert_equal([%w[abc defg h], %w[ijk l], %w[mno], %w[pqr st u vw xy z]],
+                 ss.slice_before(/\A...\z/).to_a)
   end
 
 end

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

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