mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* enum.c (enum_slice_before): take a pattern if no block given.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25188 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
aec8a4b0a4
commit
2e70b9e70d
3 changed files with 48 additions and 18 deletions
|
@ -1,3 +1,7 @@
|
||||||
|
Fri Oct 2 20:49:19 2009 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
|
* enum.c (enum_slice_before): take a pattern if no block given.
|
||||||
|
|
||||||
Fri Oct 2 20:37:37 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Fri Oct 2 20:37:37 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* parse.y (ripper_yylval_id, ripper_get_{id,value}): wrap ID by
|
* parse.y (ripper_yylval_id, ripper_get_{id,value}): wrap ID by
|
||||||
|
|
58
enum.c
58
enum.c
|
@ -2115,7 +2115,8 @@ enum_chunk(int argc, VALUE *argv, VALUE enumerable)
|
||||||
|
|
||||||
|
|
||||||
struct slicebefore_arg {
|
struct slicebefore_arg {
|
||||||
VALUE separator_p;
|
VALUE sep_pred;
|
||||||
|
VALUE sep_pat;
|
||||||
VALUE state;
|
VALUE state;
|
||||||
VALUE prev_elts;
|
VALUE prev_elts;
|
||||||
VALUE yielder;
|
VALUE yielder;
|
||||||
|
@ -2129,10 +2130,12 @@ slicebefore_ii(VALUE i, VALUE _argp, int argc, VALUE *argv)
|
||||||
|
|
||||||
ENUM_WANT_SVALUE();
|
ENUM_WANT_SVALUE();
|
||||||
|
|
||||||
if (NIL_P(argp->state))
|
if (!NIL_P(argp->sep_pat))
|
||||||
header_p = rb_funcall(argp->separator_p, rb_intern("call"), 1, i);
|
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
|
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 (RTEST(header_p)) {
|
||||||
if (!NIL_P(argp->prev_elts))
|
if (!NIL_P(argp->prev_elts))
|
||||||
rb_funcall(argp->yielder, rb_intern("<<"), 1, argp->prev_elts);
|
rb_funcall(argp->yielder, rb_intern("<<"), 1, argp->prev_elts);
|
||||||
|
@ -2155,7 +2158,8 @@ slicebefore_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)
|
||||||
struct slicebefore_arg arg;
|
struct slicebefore_arg arg;
|
||||||
|
|
||||||
enumerable = rb_ivar_get(enumerator, rb_intern("slicebefore_enumerable"));
|
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.state = rb_ivar_get(enumerator, rb_intern("slicebefore_initial_state"));
|
||||||
arg.prev_elts = Qnil;
|
arg.prev_elts = Qnil;
|
||||||
arg.yielder = yielder;
|
arg.yielder = yielder;
|
||||||
|
@ -2171,23 +2175,34 @@ slicebefore_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
|
* enum.slice_before(pattern) => enumerator
|
||||||
* enum.slice_before {|elt| ... } => enumerator
|
* enum.slice_before {|elt| ... } => enumerator
|
||||||
* enum.slice_before(initial_state) {|elt, state| ... } => enumerator
|
* enum.slice_before(initial_state) {|elt, state| ... } => enumerator
|
||||||
*
|
*
|
||||||
* Creates an enumerator for each chunked elements.
|
* 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.
|
* The result enumerator yields the chunked elements as an array.
|
||||||
* So "each" method can be called as follows.
|
* So "each" method can be called as follows.
|
||||||
*
|
*
|
||||||
|
* enum.slice_before(pattern).each {|ary| ... }
|
||||||
* enum.slice_before {|elt| bool }.each {|ary| ... }
|
* enum.slice_before {|elt| bool }.each {|ary| ... }
|
||||||
* enum.slice_before(initial_state) {|elt, state| 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.
|
* # iterate over ChangeLog entries.
|
||||||
* open("ChangeLog") {|f|
|
* 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,
|
* If the block needs to maintain state over multiple elements,
|
||||||
|
@ -2243,13 +2258,12 @@ slicebefore_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)
|
||||||
* They can be chunked as follows:
|
* They can be chunked as follows:
|
||||||
*
|
*
|
||||||
* IO.popen([{"LANG"=>"C"}, "svn", "proplist", "-R"]) {|f|
|
* 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 '.':\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 '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.
|
* mbox contains series of mails which start with Unix From line.
|
||||||
* So each mail can be extracted by slice before Unix From line.
|
* So each mail can be extracted by slice before Unix From line.
|
||||||
|
@ -2284,14 +2298,22 @@ slicebefore_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv)
|
||||||
static VALUE
|
static VALUE
|
||||||
enum_slice_before(int argc, VALUE *argv, VALUE enumerable)
|
enum_slice_before(int argc, VALUE *argv, VALUE enumerable)
|
||||||
{
|
{
|
||||||
VALUE initial_state, enumerator;
|
VALUE enumerator;
|
||||||
|
|
||||||
rb_scan_args(argc, argv, "01", &initial_state);
|
if (rb_block_given_p()) {
|
||||||
|
VALUE initial_state;
|
||||||
enumerator = rb_obj_alloc(rb_cEnumerator);
|
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_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);
|
rb_block_call(enumerator, rb_intern("initialize"), 0, 0, slicebefore_i, enumerator);
|
||||||
return enumerator;
|
return enumerator;
|
||||||
}
|
}
|
||||||
|
|
|
@ -383,6 +383,10 @@ class TestEnumerable < Test::Unit::TestCase
|
||||||
assert_not_same(hs[0], hs[1])
|
assert_not_same(hs[0], hs[1])
|
||||||
assert_not_same(hs[0], hs[2])
|
assert_not_same(hs[0], hs[2])
|
||||||
assert_not_same(hs[1], 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
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue