[Bug:trunk] Enumerator.new {|y| y << 1 << 2 << 3 }

e$B1sF#$G$9!#e(B

Enumerator.new e$B$NCf$Ge(B yielder << 1 << 2 << 3 e$B$H=q$1$^$;$s!#e(B

OK

generator = Enumerator.new do |yielder|
yielder << 1
yielder << 2
yielder << 3
end
generator.each {|x| p x } #=> 1, 2, 3

NG

generator = Enumerator.new do |yielder|
yielder << 1 << 2 << 3
end
generator.each {|x| p x } #=> 1

Enumerator::Yielder#<< e$B$,e(B {|x| p x }
e$B$N%V%m%C%/$NLa$jCM$rJV$9$?$ae(B
e$BJQ$J$3$H$K$J$C$F$$$^$9!#e(B
Yielder#<< e$B$Oe(B IO
e$B=PNO$N$h$&$K!"Ns5s$7$?$$$b$N$rN.$79~$`$h$&$K;H$&e(B
[email protected]$H;W$C$F$$$^$9!#$3$NM}2r$,@5$7$1$l$P!“6/Nu$K0cOB46$N$”$k5sF0e(B
[email protected]$H;W$$$^$9!#e(B

e$B:#e(B Yielder#<< e$B$Oe(B Yielder#yield e$B$Ne(B alias
e$B$K$J$C$F$$$^$9$,!"e(Byield e$B$Oe(B
e$B85$N5sF0$N$^$^!"e(BYielder#<< [email protected]$1>o$Ke(B self
e$B$rJV$9$h$&$K$7$F$b$$$$$Ge(B
e$B$7$g$&$+!#e(B

diff --git a/enumerator.c b/enumerator.c
index e341c07…7c50f3d 100644
— a/enumerator.c
+++ b/enumerator.c
@@ -1012,6 +1012,13 @@ yielder_yield(VALUE obj, VALUE args)
return rb_proc_call(ptr->proc, args);
}

+/* :nodoc: */
+static VALUE yielder_yield_push(VALUE obj, VALUE args)
+{

  • yielder_yield(obj, args);
  • return obj;
    +}

static VALUE
yielder_yield_i(VALUE obj, VALUE memo, int argc, VALUE *argv)
{
@@ -1228,7 +1235,7 @@ Init_Enumerator(void)
rb_define_alloc_func(rb_cYielder, yielder_allocate);
rb_define_method(rb_cYielder, “initialize”, yielder_initialize, 0);
rb_define_method(rb_cYielder, “yield”, yielder_yield, -2);

  • rb_define_method(rb_cYielder, “<<”, yielder_yield, -2);
  • rb_define_method(rb_cYielder, “<<”, yielder_yield_push, -2);

    id_rewind = rb_intern(“rewind”);
    id_each = rb_intern(“each”);

In article
[email protected],
Yusuke ENDOH [email protected] writes:

e$B:#e(B Yielder#<< e$B$Oe(B Yielder#yield e$B$Ne(B alias e$B$K$J$C$F$$$^$9$,!"e(Byield e$B$Oe(B
e$B85$N5sF0$N$^$^!"e(BYielder#<< [email protected]$1>o$Ke(B self e$B$rJV$9$h$&$K$7$F$b$$$$$Ge(B
e$B$7$g$&$+!#e(B

e$B$"$!!"[email protected]$H;W$$$^$9!#e(B

e$B$=$l$O$=$l$H$7$F!"%I%-%e%a%s%H$OI,MW$G$7$g$&$M$’!#e(B

e$B1sF#$G$9!#e(B

2009e$BG/e(B11e$B7ne(B11e$BF|e(B22:54 Tanaka A. [email protected]:

In article [email protected],
Yusuke ENDOH [email protected] writes:

e$B:#e(B Yielder#<< e$B$Oe(B Yielder#yield e$B$Ne(B alias e$B$K$J$C$F$$$^$9$,!"e(Byield e$B$Oe(B
e$B85$N5sF0$N$^$^!"e(BYielder#<< [email protected]$1>o$Ke(B self e$B$rJV$9$h$&$K$7$F$b$$$$$Ge(B
e$B$7$g$&$+!#e(B

e$B$"$!!"[email protected]$H;W$$$^$9!#e(B

e$B$"$j$,$H$&$4$6$$$^$9!#$=$l$G$O%3%_%C%H$7$^$9!#e(B

e$B$=$l$O$=$l$H$7$F!"%I%-%e%a%s%H$OI,MW$G$7$g$&$M$’!#e(B

Enumerator::Yielder e$B$He(B Enumerator::Generator e$B$OA4Ite(B nodoc
[email protected]$C$?$N$G!“e(B
e$B$”$o$;$FE,Ev$K=q$$$F$$^$7$?!#$3$l$b%3%%C%H$7$h$&$H;W$$$^$9!#e(B

e$B=q$$$F$$$F5$$,$D$$$?$s$G$9$,!"e(BGenerator#each e$B$Oe(B self
e$B$G$O$J$/e(B proc e$B$Ne(B
e$BLa$jCM$rJV$9$h$&$G$9!#0U?^E*$J$s$G$7$g$&$+!#e(B

g = Enumerator::Generator.new {|y| y << 1 << 2 << 3; :foo }
p g.each {} #=> :foo

e$B$^$"!"e(BGenerator
e$B$rD>@;H$&$3$H$OIaDL$O$J$$$N$G!"LdBj$K$J$k$3$H$O$J$$e(B
e$B$N$+$b$7$l$^$;$s$,!#e(B

diff --git a/enumerator.c b/enumerator.c
index e341c07…e8e147a 100644
— a/enumerator.c
+++ b/enumerator.c
@@ -994,7 +994,19 @@ yielder_init(VALUE obj, VALUE proc)
return obj;
}

-/* :nodoc: /
+/

    • call-seq:
    • Enumerator::Yielder.new {|x| block }  => new_yielder
      
    • Returns a new yielder encapsulating a given proc.
    • proc is called with arguments that the yielder receives by
    • Enumerator::Yielder#yield or <<.
    • y = Enumerator::Yielder.new {|x| p x }
      
    • y << 1  #=> 1
      
    • y << 2  #=> 2
      
    • y << 3  #=> 3
      
  • */
    static VALUE
    yielder_initialize(VALUE obj)
    {
    @@ -1003,7 +1015,18 @@ yielder_initialize(VALUE obj)
    return yielder_init(obj, rb_block_proc());
    }

-/* :nodoc: /
+/

    • call-seq:
    • yielder.yield(val)  =>  value that proc returns
      
    • Invokes the encapsulated proc and passes val as an argument.
    • Returns value that the proc returns.
    • y = Enumerator::Yielder.new {|x| x * 10 }
      
    • p y.yield(1)  #=> 10
      
    • p y.yield(2)  #=> 20
      
    • p y.yield(3)  #=> 30
      
  • */
    static VALUE
    yielder_yield(VALUE obj, VALUE args)
    {
    @@ -1012,6 +1035,22 @@ yielder_yield(VALUE obj, VALUE args)
    return rb_proc_call(ptr->proc, args);
    }

+/*

    • call-seq:
    • yielder << val  =>  self
      
    • Invokes the encapsulated proc and passes val as an argument.
    • Returns self.
    • y = Enumerator::Yielder.new {|x| p x }
      
    • y << 1 << 2 << 3  #=> 1, 2, 3
      
  • */
    +static VALUE yielder_yield_push(VALUE obj, VALUE args)
    +{
  • yielder_yield(obj, args);
  • return obj;
    +}

static VALUE
yielder_yield_i(VALUE obj, VALUE memo, int argc, VALUE *argv)
{
@@ -1092,7 +1131,18 @@ generator_init(VALUE obj, VALUE proc)

VALUE rb_obj_is_proc(VALUE proc);

-/* :nodoc: /
+/

    • call-seq:
    • Enumerator::Generator.new {|y| block }  => new_generator
      
    • Enumerator::Generator.new(proc)         => new_generator
      
    • Returns a new generator encapsulating a given proc.
    • proc receives an instance of Enumerator::Yielder. The
      generator
    • enumerates a sequence of values that the yielder receives by
    • Enumerator::Yielder#yield or <<.
    • Enumerator::Generator.new {|y| y << 1 << 2 << 3 }.to_a  #=> [1, 
      

2, 3]

  • */
    static VALUE
    generator_initialize(int argc, VALUE *argv, VALUE obj)
    {
    @@ -1137,7 +1187,14 @@ generator_init_copy(VALUE obj, VALUE orig)
    return obj;
    }

-/* :nodoc: /
+/
call-seq:

    • generator.each {|x| block }  =>  value that <i>proc</i> returns
      
    • Enumerates the sequence of the generator.
    • g = Enumerator::Generator.new {|y| y << 1 << 2 << 3 }
      
    • g.each {|x| p x }  #=> 1, 2, 3
      
  • */
    static VALUE
    generator_each(VALUE obj)
    {
    @@ -1228,7 +1285,7 @@ Init_Enumerator(void)
    rb_define_alloc_func(rb_cYielder, yielder_allocate);
    rb_define_method(rb_cYielder, “initialize”, yielder_initialize, 0);
    rb_define_method(rb_cYielder, “yield”, yielder_yield, -2);
  • rb_define_method(rb_cYielder, “<<”, yielder_yield, -2);
  • rb_define_method(rb_cYielder, “<<”, yielder_yield_push, -2);

    id_rewind = rb_intern(“rewind”);
    id_each = rb_intern(“each”);

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:39663] Re: [Bug:trunk] Enumerator.new {|y| y
<< 1 << 2 << 3 }”
on Wed, 11 Nov 2009 23:50:47 +0900, Yusuke ENDOH [email protected]
writes:

|e$B=q$$$F$$$F5$$,$D$$$?$s$G$9$,!“e(BGenerator#each e$B$Oe(B self e$B$G$O$J$/e(B proc e$B$Ne(B
|e$BLa$jCM$rJV$9$h$&$G$9!#0U?^E*$J$s$G$7$g$&$+!#e(B
|
| g = Enumerator::Generator.new {|y| y << 1 << 2 << 3; :foo }
| p g.each {} #=> :foo
|
|e$B$^$”!"e(BGenerator e$B$rD>@;H$&$3$H$OIaDL$O$J$$$N$G!"LdBj$K$J$k$3$H$O$J$$e(B
|e$B$N$+$b$7$l$^$;$s$,!#e(B

e$B0U?^E*$G$O$J$$$H;W$$$^$9!#e(B

e$B1sF#$G$9!#e(B

2009e$BG/e(B11e$B7ne(B12e$BF|e(B0:38 Akinori MUSHA [email protected]:

e$B$=$l$O$=$l$H$7$F!"%I%-%e%a%s%H$OI,MW$G$7$g$&$M$’!#e(B

Enumerator::Yielder e$B$He(B Enumerator::Generator e$B$OA4Ite(B nodoc [email protected]$C$?$N$G!“e(B
e$B$”$o$;$FE,Ev$K=q$$$F$$^$7$?!#$3$l$b%3%%C%H$7$h$&$H;W$$$^$9!#e(B

e$B!!e(BYielder/Generator e$B$H$$$&AH9g$;$K$h$k<BAu$O<B83E*$J$b$N$G!“FC$Ke(B
e$B8e<T$O30It$K8x3+$9$kI,MW$,$J$$$N$G4:$($FIz$;$F$$$^$7$?!#8x3+;EMM$Ke(B
[email protected])Ls$K$J$k$N$G!”<{MW$,@8$8$k$^$G$OHs8x3+$NJ}$,$$$$$N$G$O$J$$e(B
e$B$G$7$g$&$+!#e(B

e$B$"$"!"$d$C$Q$j$=$&$$$&0U?^$J$s$G$9$h$M!#$=$&$$$&$3$H$J$i%I%-%e%a%s%H$Oe(B
e$B%3%_%C%H$7$J$$$G$*$-$^$9!#e(B

[email protected]!“e(BEnumerator.new [email protected]@$,$”$k$H$O$$$(!"e(BYielder
e$B$N%$%s%9e(B
e$B%?%s%9$O%f!<%6$K4]8+$($J$N$G!“e(BYielder#yield e$B$He(B << e$B$^$Ge(B
nodoc e$B$H$$$&$N$Oe(B
e$B$”$^$j$h$/$J$$$+$J$H$O;W$$$^$7$?!#e(B

e$BJQ99$5$l$F$$$k$N$G!“EDCf$5$s$K$O2?$i$+$N0U?^$,$”[email protected]$H;W$$$^$9!#e(B
e$B$J$k$[$I!#e(B
e$B0U?^E*$H$$$&$3$H$J$i!"$;$C$+$/[email protected]$i$l$k>pJs$r$o$6$H1#$9$3$H$b$J$$!"$He(B
e$B$$$&$3$H$+$J$H;W$$$^$7$?!#e(B
e$B;[email protected]$o$j$O$J$$$N$G!"?($i$J$$$G$*$-$^$9!#e(B

At Wed, 11 Nov 2009 23:50:47 +0900,
Yusuke ENDOH wrote:

ありがとうございます。それではコミットします。
 self を返すようにしていたはずだと思ったら、 r24587 で変更されて
いたんですね。ブロックの値を取れなかったわけか。#yield はその方が
いいですね。一方 #<< は self を返す方が自然と思うので賛成です。

それはそれとして、ドキュメントは必要でしょうねぇ。

Enumerator::Yielder と Enumerator::Generator は全部 nodoc だったので、
あわせて適当に書いてみました。これもコミットしようと思います。

 Yielder/Generator という組合せによる実装は実験的なもので、特に
後者は外部に公開する必要がないので敢えて伏せていました。公開仕様に
すると制約になるので、需要が生じるまでは非公開の方がいいのではない
でしょうか。

書いていて気がついたんですが、Generator#each は self ではなく proc の
戻り値を返すようです。意図的なんでしょうか。

g = Enumerator::Generator.new {|y| y << 1 << 2 << 3; :foo }
p g.each {} #=> :foo

まあ、Generator を直接使うことは普通はないので、問題になることはない
のかもしれませんが。

 私が実装したときは self を返していましたが、こちらも r24587 で
変更されているので、田中さんには何らかの意図があるのだと思います。

In article
[email protected],
Yusuke ENDOH [email protected] writes:

e$B=q$$$F$$$F5$$,$D$$$?$s$G$9$,!"e(BGenerator#each e$B$Oe(B self e$B$G$O$J$/e(B proc e$B$Ne(B
e$BLa$jCM$rJV$9$h$&$G$9!#0U?^E*$J$s$G$7$g$&$+!#e(B

g = Enumerator::Generator.new {|y| y << 1 << 2 << 3; :foo }
p g.each {} #=> :foo

e$B$A$g$C$H$O$C$-$j$7$?5-21$,$J$$$N$G$9$,!"e(B

e = Enumerator.new {|y| … }
e.each { … }

e$B$H$$$&7A<0$G$b!"e(Beach e$B$NJV$jCM$re(B Enumerator
e$BB&$G7h$a$i$l$k$he(B
e$B$&[email protected]$C$?$h$&$J5$$,$7$^$9!#e(B

[ruby-dev:39109] e$B$+$i$NOC$O!"%$%F%l!<%?%a%=%C%[email protected](B
[email protected])8f$9$k$H$$$&L\E*$G$7$?$+$i!#e(B

e$B%A%1%C%He(B #2356 e$B$,99?7$5$l$^$7$?!#e(B (by Yusuke E.)

e$B%9%F!<%?%9e(B Opene$B$+$ie(BClosede$B$KJQ99e(B
e$B?JD=e(B % 0e$B$+$ie(B100e$B$KJQ99e(B

This issue was solved with changeset r25721.
Yusuke, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


http://redmine.ruby-lang.org/issues/show/2356

Yusuke ENDOH wrote:

e$B$"$"!"$d$C$Q$j$=$&$$$&0U?^$J$s$G$9$h$M!#$=$&$$$&$3$H$J$i%I%-%e%a%s%H$Oe(B
e$B%3%_%C%H$7$J$$$G$*$-$^$9!#e(B

experimenal
e$B$J$i$P$=$N;]$N%I%-%e%a%s%H$OF~$l$F$*$$$?J}$,$$$$$N$G$O$J$$$G$7$g$&$+!#e(B

At Thu, 12 Nov 2009 01:23:56 +0900,
Yusuke ENDOH wrote:

あまりよくないかなとは思いました。
 こういうときは

class Enumerator

ブロックを渡すと(略)インスタンスが生成されて、

Enumerator::Yieldable なオブジェクトが渡されて呼ばれるよ

def initialize
end

レキシカルなコンテクスト外のブロックにyieldするためのモジュール

このモジュールは #yield を前提にしているよ

module Yieldable
# 渡されたvalueをyieldするよ
# このモジュールをincludeするクラスが実装するよ
def yield(value)
raise NotImplementedError
end

# yieldしてselfを返すよ
def <<(value)
  self.yield(value)
  self
end

end

:nodoc:

class Yielder
def yield(value)
# …
end

include Yieldable

end
end

のような構成にすると、クラス名の明文化を避けつつドキュメントする
ことができて、将来の変更に対する制約を回避できるかもしれませんね。

 つまり、ユーザが y.instance_of?(Yielder) などとしだすともう特異
オブジェクトを返すように変えることはAPI変更になってしまいますが、
y.is_a?(Yieldable) と y.respond_to?(:yield) (および :<<)しか仮定
させないことで、 extend Yieldable した特異オブジェクトを返しても
互換性の問題なしというわけです。

e$B1sF#$G$9!#e(B

2009e$BG/e(B11e$B7ne(B12e$BF|e(B21:17 NARUSE, Yui [email protected]:

e$B%3%_%C%H$7$J$$$G$*$-$^$9!#e(B

experimenal e$B$J$i$P$=$N;]$N%I%-%e%a%s%H$OF~$l$F$*$$$?J}$,$$$$$N$G$O$J$$$G$7$g$&$+!#e(B

e$B!V2?$d$ie(B yield e$B%a%=%C%I$He(B <<
e$B%a%=%C%I$,Dj5A$5$l$?%*%V%8%’%/%H$,EO$5$l$k!We(B
e$B$H$$$&;EMM$Oe(B fix e$B$5$l$F$$$k$1$l$I!"$=$l$,e(B Yielder
e$B$N%$%s%9%?%s%9$G$"$k$He(B
e$B$$$&$3$H$Oe(B (e$B8=:_$N<BAu$,$=$&[email protected]$1$Ge(B)
e$BJ]>Z$7$F$$$J$$!"$H$$$&0UL#[email protected](B
e$B$H;W$$$^$9!#$"$C$F$^$9$h$M!)e(B > knu e$B$5$se(B

e$B$=$&$$$&>l9g$I$3$Ke(B doc
e$B$r=q$/$Y$-$+$J$s$G$9$,!"e(B[ruby-dev:39672] e$B$N$h$&$Ke(B
e$B$9$l$P$h$5$=$&$G$9!#e(B

e$B1sF#$G$9!#e(B

2009e$BG/e(B11e$B7ne(B12e$BF|e(B21:11 Akinori MUSHA [email protected]:

e$B$D$^$j!"%f!<%6$,e(B y.instance_of?(Yielder) [email protected]$9$H$b$&FC0[e(B
e$B%%V%8%’%/%H$rJV$9$h$&$KJQ$($k$3$H$Oe(BAPIe$BJQ99$K$J$C$F$7$^$$$^$9$,!"e(B
y.is_a?(Yieldable) e$B$He(B y.respond_to?(:yield) (e$B$
$h$Se(B :<<)e$B$7$+2>Dje(B
e$B$5$;$J$$$3$H$G!"e(B extend Yieldable e$B$7$?FC0[%*%V%8%’%/%H$rJV$7$F$be(B
[email protected]$NLdBj$J$7$H$$$&$o$1$G$9!#e(B

e$B$J$k$[$I!#$$$$$H;W$$$^$9!#e(B
Yielder e$B$rF?L>%/%i%9$K$9$l$P40`[email protected]$H;W$$$^$9!#e(B

e$B1sF#$G$9!#e(B

2009e$BG/e(B11e$B7ne(B12e$BF|e(B21:55 Akinori MUSHA [email protected]:

e$B$=$&$$$&>l9g$I$3$Ke(B doc e$B$r=q$/$Y$-$+$J$s$G$9$,!"e(B[ruby-dev:39672] e$B$N$h$&$Ke(B
e$B$9$l$P$h$5$=$&$G$9!#e(B

e$B!!1sF#$5$s$OF?L>%/%i%92=$rDs0F$5$l$F$$$^$9$,!“e(B :nodoc: e$B$”$k$$$Oe(B
e$B!V$3$N%/%i%9$O<[email protected]$+$i0MB86X;_!W$H=q$/$N$G$O4E$$$G$9$+$M!#e(B
SEGVe$BEy$N4m81$G$O$J$/[email protected]$N2>Dj$rHr$1$k$?$a$NF?L>2=$H$$$&$N$O!“e(B
e$B%W%m%0%i%^$r?.MQ$7$J$$$H$$$&[email protected]$Ge(BRubye$BE*$G$O$J$/!”$b$747=,2=$9$k$He(B
e$B%i%$%V%i%j$r=q$/>e$GLLE][email protected])Ls$K$J$C$F$7$^$&$N$G$O$J$$$+$H4mW|e(B
e$B$7$^$9!#e(B

e$B%f!<%6$,IaDL$K8F$S=P$9%a%=%C%Ie(B (e$B$3$3$G$Oe(B #yield e$B$de(B
#<<) e$B$,e(B :nodoc: e$B$Ke(B
e$B$J$C$F$7$^$&$N$,[email protected]$C$?$N$G!"e(BYieldable e$B$,8x3+e(B API
e$B$K$J$k$J$i$=$l$Ge(B
e$B$$$$$H;W$$$^$9!#e(B

e$B$$$$$H;W$&$s$G$9$,!"$^$"%3%"$NCf$/$i$$$O$`$d$_$KFbIt$,8+$($J$$$h$&$Ke(B
e$B$7$H$/J}$,$$$$$s$8$c$J$$$+$J!"$H$$$&5$;}$A$b$J$$$3$H$O$J$$$G$9!#e(B
RubyVM e$B$H$+2x$7$$$G$9$1$I$M!#e(B

At Thu, 12 Nov 2009 21:33:23 +0900,
Yusuke ENDOH wrote:

[email protected])Ls$K$J$k$N$G!"<{MW$,@8$8$k$^$G$OHs8x3+$NJ}$,$$$$$N$G$O$J$$e(B
e$B$H;W$$$^$9!#$"$C$F$^$9$h$M!)e(B > knu e$B$5$se(B
e$B!!$O$$!"$=$NDL$j$G$9!#e(B

e$B$=$&$$$&>l9g$I$3$Ke(B doc e$B$r=q$/$Y$-$+$J$s$G$9$,!"e(B[ruby-dev:39672] e$B$N$h$&$Ke(B
e$B$9$l$P$h$5$=$&$G$9!#e(B

e$B!!1sF#$5$s$OF?L>%/%i%92=$rDs0F$5$l$F$$$^$9$,!“e(B :nodoc:
e$B$”$k$$$Oe(B
e$B!V$3$N%/%i%9$O<[email protected]$+$i0MB86X;_!W$H=q$/$N$G$O4E$$$G$9$+$M!#e(B
SEGVe$BEy$N4m81$G$O$J$/[email protected]$N2>Dj$rHr$1$k$?$a$NF?L>2=$H$$$&$N$O!“e(B
e$B%W%m%0%i%^$r?.MQ$7$J$$$H$$$&[email protected]$Ge(BRubye$BE*$G$O$J$/!”$b$747=,2=$9$k$He(B
e$B%i%$%V%i%j$r=q$/>e$GLLE][email protected])Ls$K$J$C$F$7$^$&$N$G$O$J$$$+$H4mW|e(B
e$B$7$^$9!#e(B

P.S.
Redminee$B$,;d$NEj9F$r=&$C$F$/$l$J$$$N$Oe(BPGPe$B=pL>$N$;$$$+$J!)e(B
e$B=pL>$J$7$GAw$C$F$_$^$9!#e(B