[#38371] Re: [ruby-cvs:30538] Ruby:r23320 (trunk): * lib/set.rb (SortedSet#add): Do not let an uncomparable object — "Yugui (Yuki Sonoda)" <yugui@...>
Yuguiです。
At Mon, 4 May 2009 23:44:22 +0900,
遠藤です。
At Fri, 8 May 2009 02:00:10 +0900,
[#38372] making install-sh more descriptive — "Yugui (Yuki Sonoda)" <yugui@...>
install-shが空になって久しい(r520)です。
[#38382] [Bug #1442] indentation check and coverage for toplevel do not work — Yusuke Endoh <redmine@...>
Bug #1442: indentation check and coverage for toplevel do not work
[#38390] [Bug:1.8] Tempfile and extended Enumerable — Tanaka Akira <akr@...>
1.8.8dev で、以下のように、Enumerable に each2 を定義し、
[#38392] Enumerable#gather_each — Tanaka Akira <akr@...>
ときに、複数行をまとめて扱いたいことがあります。
ujihisaと申します。
まつもと ゆきひろです
In article <[email protected]>,
まつもと ゆきひろです
In article <[email protected]>,
In article <[email protected]>,
At Sat, 9 May 2009 15:30:20 +0900,
In article <[email protected]>,
At Sun, 10 May 2009 10:08:47 +0900,
In article <[email protected]>,
At Sun, 10 May 2009 15:57:33 +0900,
In article <[email protected]>,
Haskell の groupBy と Python の groupby が似ている、という話
[#38423] longlife gc — Narihiro Nakamura <authornari@...>
nariと申します.
[#38446] [Bug:1.9] exact Time and inexact Time — Yusuke ENDOH <mame@...>
遠藤です。
In article <[email protected]>,
遠藤です。
[#38463] SQLiteライブラリ — "NARUSE, Yui" <naruse@...>
成瀬です。
[#38486] [Bug #1483] some commands installed without program-suffix — Kazuhiro NISHIYAMA <redmine@...>
Bug #1483: some commands installed without program-suffix
[#38493] [Feature:trunk] enhancement of Array#drop — "U.Nakamura" <usa@...>
こんにちは、なかむら(う)です。
まつもと ゆきひろです
こんにちは、なかむら(う)です。
[#38518] [Bug:1.9] Enumerator.new { }.take(1).inject(&:+) causes stack overflow — Yusuke ENDOH <mame@...>
遠藤です。
[#38524] [Bug #1503] -Kuをつけた時、/[#{s}]/n と Regexp.new("[#{s}]",nil,"n") で実行結果が異なる — sinnichi eguchi <redmine@...>
Bug #1503: -Kuをつけた時、/[#{s}]/n と Regexp.new("[#{s}]",nil,"n") で実行結果が異なる
[ruby-dev:38431] Re: Enumerable#gather_each
In article <[email protected]>, Tanaka Akira <[email protected]> writes: > gather も Yielder を使う形にすれば、gather_each をなくすこと > は可能だと思います。 そういう形で作ってみたのでつけておきます。 ふと思いついたので、gather には chunk_by という名前もつけてあります。 * Enumerable#chunk_by * Enumerable#gather * Enumerable#slice_before % svn diff --diff-cmd diff -x '-u -p' Index: enum.c =================================================================== --- enum.c (revision 23381) +++ enum.c (working copy) @@ -1793,6 +1793,170 @@ enum_cycle(int argc, VALUE *argv, VALUE return Qnil; /* not reached */ } +struct chunk_by_arg { + VALUE categorize; + VALUE prev_value; + VALUE prev_elts; + VALUE yielder; +}; + +static VALUE +chunk_by_ii(VALUE i, VALUE _argp, int argc, VALUE *argv) +{ + struct chunk_by_arg *argp = (struct chunk_by_arg *)_argp; + VALUE v; + VALUE singleton = ID2SYM(rb_intern("_singleton")); + VALUE separator = ID2SYM(rb_intern("_separator")); + + ENUM_WANT_SVALUE(); + + v = rb_funcall(argp->categorize, rb_intern("call"), 1, i); + + if (v == singleton) { + if (!NIL_P(argp->prev_value)) { + rb_funcall(argp->yielder, rb_intern("<<"), 1, argp->prev_elts); + argp->prev_value = argp->prev_elts = Qnil; + } + rb_funcall(argp->yielder, rb_intern("<<"), 1, rb_ary_new3(1, i)); + } + else if (!RTEST(v) || v == separator) { + if (!NIL_P(argp->prev_value)) { + rb_funcall(argp->yielder, rb_intern("<<"), 1, argp->prev_elts); + argp->prev_value = argp->prev_elts = Qnil; + } + } + else if (SYMBOL_P(v) && rb_id2name(SYM2ID(v))[0] == '_') { + rb_raise(rb_eRuntimeError, "symbol begins with an underscore is reserved"); + } + else { + if (NIL_P(argp->prev_value)) { + argp->prev_value = v; + argp->prev_elts = rb_ary_new3(1, i); + } + else { + if (rb_equal(argp->prev_value, v)) { + rb_ary_push(argp->prev_elts, i); + } + else { + rb_funcall(argp->yielder, rb_intern("<<"), 1, argp->prev_elts); + argp->prev_value = v; + argp->prev_elts = rb_ary_new3(1, i); + } + } + } + return Qnil; +} + +static VALUE +chunk_by_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv) +{ + VALUE enumerable; + struct chunk_by_arg arg; + + enumerable = rb_ivar_get(enumerator, rb_intern("chunk_by_enumerable")); + arg.categorize = rb_ivar_get(enumerator, rb_intern("chunk_by_categorize")); + arg.prev_value = Qnil; + arg.prev_elts = Qnil; + arg.yielder = yielder; + + rb_block_call(enumerable, id_each, 0, 0, chunk_by_ii, (VALUE)&arg); + if (!NIL_P(arg.prev_elts)) + rb_funcall(arg.yielder, rb_intern("<<"), 1, arg.prev_elts); + return Qnil; +} + +/* + * call-seq: + * enum.chunk_by {|elt| ... } => enumerator + * + * Creates an enumerator for iterating chunked elements of _enum_. + * + * This method gathers consecutive elements which + * the blocks returns a same value. + * + * The following values has special meaning: + * - nil, false and :_separator specifies that gathered elements is not yielded. + * - :_singleton specifies the element should be gathered only itself. + * + * Other symbols which begins an underscore may be used in future. + * + * (1..10).chunk_by {|n| n & 2 }.each {|a| p a } + * #=> [1] # 1 & 2 = 0 + * # [2, 3] # 2 & 2 = 3 & 2 = 1 + * # [4, 5] # 4 & 2 = 5 & 2 = 0 + * # [6, 7] # 6 & 2 = 7 & 2 = 1 + * # [8, 9] # 8 & 2 = 9 & 2 = 0 + * # [10] # 10 & 2 = 1 + * + * # gather indented blocks. + * io.chunk_by {|line| /\A\s/ =~ line }.each {|lines| pp lines } + * + */ +static VALUE +enum_chunk_by(VALUE enumerable) +{ + VALUE enumerator = rb_obj_alloc(rb_cEnumerator); + rb_ivar_set(enumerator, rb_intern("chunk_by_enumerable"), enumerable); + rb_ivar_set(enumerator, rb_intern("chunk_by_categorize"), rb_block_proc()); + rb_block_call(enumerator, rb_intern("initialize"), 0, 0, chunk_by_i, enumerator); + return enumerator; +} + +struct slice_before_arg { + VALUE separator_p; + VALUE prev_elts; + VALUE yielder; +}; + +static VALUE +slice_before_ii(VALUE i, VALUE _argp, int argc, VALUE *argv) +{ + struct slice_before_arg *argp = (struct slice_before_arg *)_argp; + + ENUM_WANT_SVALUE(); + + if (RTEST(rb_funcall(argp->separator_p, rb_intern("call"), 1, i))) { + if (!NIL_P(argp->prev_elts)) + rb_funcall(argp->yielder, rb_intern("<<"), 1, argp->prev_elts); + argp->prev_elts = rb_ary_new3(1, i); + } + else { + if (NIL_P(argp->prev_elts)) + argp->prev_elts = rb_ary_new3(1, i); + else + rb_ary_push(argp->prev_elts, i); + } + + return Qnil; +} + +static VALUE +slice_before_i(VALUE yielder, VALUE enumerator, int argc, VALUE *argv) +{ + VALUE enumerable; + struct slice_before_arg arg; + + enumerable = rb_ivar_get(enumerator, rb_intern("slice_before_enumerable")); + arg.separator_p = rb_ivar_get(enumerator, rb_intern("slice_before_separator_p")); + arg.prev_elts = Qnil; + arg.yielder = yielder; + + rb_block_call(enumerable, id_each, 0, 0, slice_before_ii, (VALUE)&arg); + if (!NIL_P(arg.prev_elts)) + rb_funcall(arg.yielder, rb_intern("<<"), 1, arg.prev_elts); + return Qnil; +} + +static VALUE +enum_slice_before(VALUE enumerable) +{ + VALUE enumerator = rb_obj_alloc(rb_cEnumerator); + rb_ivar_set(enumerator, rb_intern("slice_before_enumerable"), enumerable); + rb_ivar_set(enumerator, rb_intern("slice_before_separator_p"), rb_block_proc()); + rb_block_call(enumerator, rb_intern("initialize"), 0, 0, slice_before_i, enumerator); + return enumerator; +} + /* * The <code>Enumerable</code> mixin provides collection classes with * several traversal and searching methods, and with the ability to @@ -1852,6 +2016,9 @@ Init_Enumerable(void) rb_define_method(rb_mEnumerable, "drop", enum_drop, 1); rb_define_method(rb_mEnumerable, "drop_while", enum_drop_while, 0); rb_define_method(rb_mEnumerable, "cycle", enum_cycle, -1); + rb_define_method(rb_mEnumerable, "gather", enum_chunk_by, 0); + rb_define_method(rb_mEnumerable, "chunk_by", enum_chunk_by, 0); + rb_define_method(rb_mEnumerable, "slice_before", enum_slice_before, 0); id_eqq = rb_intern("==="); id_each = rb_intern("each"); -- [田中 哲][たなか あきら][Tanaka Akira]