Enumerable#gather_each

e$B$H$-$K!“J#?t9T$r$^$H$a$F07$$$?$$$3$H$,$”$j$^$9!#e(B

e$B$?$H$($P!"e(BRD e$B$G%$%s%G%s%H$5$l$?ItJ,$r<h$j=P$9$H$+!"e(BIO
e$B$N%Q%ie(B
e$B%0%i%U%b!<%I$C$]$$$3$H$H$+!“8D?ME*$K$O:G6ae(B chkbuild e$B$G%m%0$Ne(B
e$B0lIt$r%=!<%H$9$k$H$$$&I,MW$,$”$j$^$7$?!#e(B

e$B$7$+$7!“e(BEnumerable e$B$G$=$&$$$&$^$H$^$j$r07$&%a%=%C%I$Oe(B
each_slice e$B$7$+$J$/$F!”=@Fp$J$3$H$O=PMh$^$;$s!#e(B

e$B%U%!%$%k$rA4ItFI$_9~$s$G@55,I=8=$G$d$k$H$$$&$N$O$R$H$D$N0F$Ge(B
e$B$9$,!"%U%!%$%k$,$H$F$bBg$-$$$+$b$7$l$J$$$H$J$k$H$d$j$?$/$J$$e(B
e$B$3$H$,$"$j$^$9!#e(B
(e$B<B:]e(B chkbuild e$B$N%m%0$O$H$F$bBg$-$/$J$k$3$H$,$"$j$^$9e(B)

e$B$G$O<+J,$G=q$/$+!"$H$$$&$H!"$3$l$,$J$+$J$+$-$l$$$K$+$1$^$;$s!#e(B
e$BNc$($P!"%$%s%G%s%H$5$l$?ItJ,$r<h$j=P$9$K$O$=$ND>8e$N%$%s%G%se(B
e$B%H$5$l$F$$$J$$ItJ,$^$GFI$^$J$$$H$^$H$^$j$,H=CG$G$-$J$/$F!“e(B
IO#each_line e$B$G=q$3$&$H$9$k$H$1$C$3$&LLE]$G$9!#$R$H$D$N9T$,e(B
e$B%$%s%G%s%H$5$l$F$$$k$+$I$&$+$rD4$Y$k$N$O9TF,$,6uGr$+$I$&$+$re(B
e$BD4$Y$k$@$1$G4JC1$K$G$-$k$N$G$9$,!”$=$N7k2L$K=>$C$FO"B3$7$?9Te(B
e$B$r$^$H$a$k$N$,Lq2p$G$9!#e(B

e$B$3$3$G!"%$%s%G%s%H$5$l$F$$$k$+$I$&$+$H$+!"%Q%i%0%i%U$@$C$?$ie(B
e$B6u9T$+$I$&$+$H$+!"8D!9$NMWAG$rJ,N$9$k$H$3$m$OLdBj$K$h$C$F0[e(B e$B$J$k$N$G$9$,!"$=$N8e$NJ,N7k2L$K$7$?$,$C$FO"B3$7$?MWAG$r$^$H$ae(B
e$B$k$N$O6&DL$7$F$$$k$N$G!“e(BEnumerable e$B$K%a%=%C%I$H$7$F$”$C$F$be(B
e$B$$$$$s$8$c$J$$$+$H;W$$$^$9!#e(B

e$B$H$$$&$o$1$G!“e(BEnumerable#gather_each(arg) {|ary| … } e$B$NDse(B
e$B0F$G$9!#0z?t$K$Oe(B Proc e$B$rM?$($F!”$3$l$O3FMWAG$K$D$$$F8F$P$l!"e(B
e$B7k2L$H$7$FJ,N7k2L$rJV$7$^$9!#e(Bgather_each e$B$O$=$NJ,N7k2L$,Eye(B
e$B$7$$O"B3$7$?MWAG$rG[Ns$H$7$F$^$H$a$Fe(B yield e$B$7$^$9!#e(B

e$B$J$*!“J,N`7k2L$,e(B nil e$B$H$$$&$N$OFCJL07$$$G!”$=$NMWAG$OC1FH$Ge(B
e$B$^$H$^$j$H$J$k$3$H$r<($7$^$9!#e(B

Ruby e$B$G$N<BAu$r0J2<$K<($7$^$9!#e(B

module Enumerable
def gather_each(arg)
prev_value = prev_elts = nil
self.each {|e|
v = arg.call(e)
if prev_value == nil
if v == nil
yield [e]
else
prev_value = v
prev_elts = [e]
end
else
if v == nil
yield prev_elts
yield [e]
prev_value = prev_elts = nil
elsif prev_value == v
prev_elts << e
else
yield prev_elts
prev_value = v
prev_elts = [e]
end
end
}
if prev_value != nil
yield prev_elts
end
end
end

e$B$?$H$($P!"e(Blib/scanf.rb e$B$K$Oe(B RD
e$B$J%I%-%e%a%s%H$,F~$C$F$$$F!"e(B
e$B0J2<$N$h$&$K$9$k$H%$%s%G%s%H$5$l$?%3!<%INc$NItJ,$r$R$H$D$K$^e(B
e$B$H$a$k$3$H$,$G$-$^$9!#e(B

arg = lambda {|l| /\A=~ l ? true : nil }
open(“lib/scanf.rb”) {|f|
f.gather_each(arg) {|lines| pp lines }
}
=>
["# scanf for Ruby\n"]
["#\n"]
["# $Release Version: 1.1.2 $\n"]

[“the return array (or yielded to the block, if a block was
given).\n”]
["\n", “\n”]
["==Basic usage\n"]
["\n",
" require ‘scanf.rb’\n",
“\n”,
" # String#scanf and IO#scanf take a single argument (a
format string)\n",
" array = aString.scanf("%d%s")\n",
" array = anIO.scanf("%d%s")\n",
“\n”,
" # Kernel#scanf reads from STDIN\n",
" array = scanf("%d%s")\n",
“\n”]
["==Block usage\n"]
["\n"]

e$B%Q%i%0%i%U%b!<%I$C$]$/!"6u9T$G6h@Z$i$l$?ItJ,$r$^$H$a$?$$$J$ie(B
e$B0J2<$N$h$&$K$G$-$^$9!#e(B

arg = lambda {|l| l == “\n” }
open(“lib/scanf.rb”) {|f|
f.gather_each(arg) {|lines| pp lines }
}
=>
["# scanf for Ruby\n",
“#\n”,
“# $Release Version: 1.1.2 $\n”,
“# $Revision: 22784 $\n”,
“# $Id: scanf.rb 22784 2009-03-06 03:56:38Z nobu $\n”,
“# $Author: nobu $\n”,
“#\n”,
“# A product of the Austin Ruby Codefest (Austin, Texas,
August 2002)\n”]
["\n"]
["=begin\n"]
["\n"]
["=scanf for Ruby\n"]
["\n"]
["==Description\n"]
["\n"]
[“scanf for Ruby is an implementation of the C function
scanf(3),\n”,
“modified as necessary for Ruby compatibility.\n”]
["\n"]

e$B$I$&$G$7$g$&e(B?

e$B$J$*!“J#?t9T$r$^$H$a$kJ}K!$H$7$F;H$$$=$&$J$b$N$O!”$^$H$a$k@he(B
e$BF,MWAG$r8!=P$9$kJ}K!$r;XDj$9$k$H$+!“B>$K$b$$$/$D$+$”$k$h$&$Ke(B
e$B;W$$$^$9!#$?$H$($Pe(B ChangeLog e$B$de(B mbox
e$B$r07$&$N$K$O!"@hF,MWAGe(B
e$B$r;XDj$9$k$N$,$$$$$G$7$g$&!#$=$&$$$&$b$N$O$^$?JL$N%a%=%C%I$He(B
e$B$7$F:n$k$N$,$$$$$N$G$O$J$$$+$H;W$$$^$9!#e(B

e$B=q$-K:$l$^$7$?!#e(B

In article [email protected],
Tanaka A. [email protected] writes:

Ruby e$B$G$N<BAu$r0J2<$K<($7$^$9!#e(B

e$B$3$l$Oe(B Ruby e$B$N<BAu$r$=$N$^$^;H$&$H$$$&0UL#$G$O$J$/!";EMM$K$De(B
e$B$$$F5DO@$9$kF;6q$G$9!#e(B

C e$B$G$N<BAu$O$^$@$G$9$,!"$3$l$+$i$d$kM=Dj$G$9!#e(B

ujihisae$B$H?=$7$^$9!#e(B

e$B0lEY$KFs$D$N<jB3$-$rEO$9$N$G$O$J$/!“0l$D$N%V%m%C%/$r<u$1<h$je(BEnumeratore$B$rJV$9e(Bgathere$B$H!”=>Mh$Ne(Beache$B$KJ,$1$?J}$,<+A3$K$J$k$N$G$O$J$$$G$7$g$&$+!#e(B

e$B85!9$NNce(B:
f.gather_each(lambda {|l| l == “\n” }) {|lines| pp lines }
f.gather_each(->(l){ l == “\n” }) {|lines| pp lines }

e$BDs0FNce(B:
f.gather {|i| i == “\n” }.each {|lines| pp lines }

e$B$"$k$$$O$=$NH]Dj7A$Ge(B
f.gather {|i| i != “\n” }.each {|lines| pp lines }

e$B;d$H$7$F$O:G8e$NNc$,0lHV<+A3$K8+$($k$N$G$9$,!"$I$&$J$N$G$7$g$&$+!#e(B

In article
[email protected],
ujihisa [email protected] writes:

f.gather {|i| i != “\n” }.each {|lines| pp lines }
e$B$J$k$[$I!“$=$l$O$”$jF@$k$+$b$7$l$^$;$s!#e(B

gather_each e$B$r;H$C$Fe(B gather
e$B$r<BAu$9$k$H0J2<$N$h$&$K$J$k$G$7$g$&$+!#e(B

module Enumerable
def gather(&b)
enum_for(:gather_each, b)
end
end

gather_each e$B$J$7$Ge(B gather e$B$r<BAu$G$-$k$+$H$$$&$H$A$g$C$H$o$+e(B
e$B$j$^$;$s!#e(B

e$B;d$H$7$F$O:G8e$NNc$,0lHV<+A3$K8+$($k$N$G$9$,!"$I$&$J$N$G$7$g$&$+!#e(B

e$B$3$N%1!<%9$G$OH]Dj$7$F$b$7$J$/$F$b7k2L$OF1$8$J$N$G<+A3$K46$8e(B
e$B$k$[$&$G=q$1$P$$$$$s$8$c$J$$$G$7$g$&$+!#e(B

At Sat, 9 May 2009 15:30:20 +0900,
Tanaka A. wrote:

というわけで、Enumerable#gather_each(arg) {|ary| … } の提
案です。引数には Proc ã‚’ä¸Žãˆã¦ã€ã“ã‚Œã¯å„è¦ç´ ã«ã¤ã„ã¦å‘¼ã°ã‚Œã€
結果として分類結果を返します。gather_each はその分類結果が等
ã—ã„é€£ç¶šã—ãŸè¦ç´ ã‚’é…åˆ—ã¨ã—ã¦ã¾ã¨ã‚ã¦ yield します。

なお、分類結果が nil ã¨ã„ã†ã®ã¯ç‰¹åˆ¥æ‰±ã„ã§ã€ãã®è¦ç´ ã¯å˜ç‹¬ã§
まとまりとなることを示します。

 少し仕様がわかりにくいように思います。繰り返しというストリームの
バッファという発想から、次のようなインターフェースを考案しました。
どうでしょうか。

class Enumerator
class Buffer
# status: 自由なメモ用途に提供
attr_accessor :status

def initialize(yielder)
  @buffer = []
  @yielder = yielder
  @status = nil
end

# ãƒãƒƒãƒ•ã‚¡ã«è¿½åŠ 
def push(item)
  @buffer.push(item)
end
alias << push

# ãƒãƒƒãƒ•ã‚¡ã®æœ€å¾Œã®è¦ç´ ã‚’å–ã‚Šå‡ºã™
def pop
  @buffer.pop
end

# バッファをクリア
def clear
  @buffer.clear
  self
end

# バッファが空かどうか
def empty?
  @buffer.empty?
end

# ãƒãƒƒãƒ•ã‚¡ã«æºœã¾ã£ãŸè¦ç´ æ•°
def size
  @buffer.size
end

# バッファの内容を yield してクリア
def flush
  @yielder.yield(@buffer)
  @buffer = []
  nil
end

end
end

module Enumerable
def buffer(&block)
Enumerator.new { |yielder|
buffer = Enumerator::Buffer.new(yielder)
each { |*args|
case args.size
when 0
block.call(buffer)
when 1
block.call(args.first, buffer)
else
block.call(args, buffer)
end
}
buffer.flush unless buffer.empty? # ※終了時に自動flush
}
end
end

使用例:

è¦ç´ ã‚’ãƒãƒƒãƒ•ã‚¡ã«æºœã‚ã¦ã„ãã€ nil が現れたら

そこまでのまとまりを yield する

p [1,2,3,nil,4,5,nil,6].buffer {|e, b|
if e.nil?
b.flush
else
b << e
end
}.to_a

表示結果: [[1, 2, 3], [4, 5], [6]]

なお、複数行をまとめる方法として使いそうなものは、まとめる先
é ­è¦ç´ ã‚’æ¤œå‡ºã™ã‚‹æ–¹æ³•ã‚’æŒ‡å®šã™ã‚‹ã¨ã‹ã€ä»–ã«ã‚‚ã„ãã¤ã‹ã‚ã‚‹ã‚ˆã†ã«
思います。たとえば ChangeLog ã‚„ mbox ã‚’æ‰±ã†ã®ã«ã¯ã€å…ˆé ­è¦ç´
を指定するのがいいでしょう。そういうものはまた別のメソッドと
して作るのがいいのではないかと思います。

 上記のインターフェースだと使用例のように区切りを渡さないことも
できますし、 yield ã‚’è¿½åŠ ã®å‰ã«ã™ã‚‹ã‹å¾Œã«ã™ã‚‹ã‹ã‚‚è‡ªç”±ã§ã™ã€‚ã¾ãŸã€
status/status= を提供することで状態遷移を扱うことも支援できます。

 あとは、終了時のハンドラを定義すると上記の※印の代わりに実行
するようにするといいかなと思っています。

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

In message “Re: [ruby-dev:38394] Re: Enumerable#gather_each”
on Sat, 9 May 2009 15:53:22 +0900, ujihisa [email protected]
writes:

|e$B0lEY$KFs$D$N<jB3$-$rEO$9$N$G$O$J$/!“0l$D$N%V%m%C%/$r<u$1<h$je(BEnumeratore$B$rJV$9e(Bgathere$B$H!”=>Mh$Ne(Beache$B$KJ,$1$?J}$,<+A3$K$J$k$N$G$O$J$$$G$7$g$&$+!#e(B

e$B;d$b$=$&;W$$$^$9!#$?$@!"e(BEnumerablee$B$+$i!V>r7o$rK~$?$98B$jO"B3e(B
e$B$7$?MWAG$r$^$H$a$k!W$3$H$re(Bgathere$B$H8F$V$3$H$K$J$s$H$J$/K~B-$Ge(B
e$B$-$^$;$s!#e(Bgathere$B$H$$$&C18l$+$i$OA4BN$+$i=8$a$k$h$&$J0u>]$r<ue(B
e$B$1$^$;$s$+!)e(B e$B;d$@$1$N463P$G$7$g$&$+!#e(B

e$B$@$+$i$H$C$FBe$o$j$NC18l$r;W$$$D$+$J$$$o$1$G$9$,!#e(B

e$B$@$1$@$H>pJs$,$"$^$j$K$b$J$$$N$G<j85$N%7%=!<%i%9$Ge(Bgathere$B$r0ze(B
e$B$$$?$H$3$m!"e(B

accumulate, aggregate, amass, assemble, associate, bunch up,
capture, choose, close with, cluster, collect, concentrate,
congregate, convence, converge, corral, crowd, cull, draw,
draw in, flock, forgather, gang up, garner, get together,
group, hang around, hang out, heap, herd, hoard, huddle, ake
the scene, marshal, mass, meet, muster, pick, pile up,
pluck, poke, pour in, punch, rally, reunite, round up, scare
up, scrape together, show up, stack up, stockpile, swarm,
throng, unite

e$B$H$“$j$^$7$?!#L@$i$+$K0c$&$@$m$&$H$+!“JL$N0UL#$G;H$C$F$k$H$+e(B
e$B$$$&$b$N$b$”$j$^$9$,!”;29M$^$G$K!#e(B

e$B$H$O$$$(!"e(B[ruby-dev:38399]e$B$Ne(Bbuffere$B$H$$$&$N$b!“5$;}$A$OJ,$+$ke(B
e$B$s$G$9$,!”$A$g$C$H0c$&$h$&$J5$$,$7$^$9!#=@Fp@-$O9b$$$s$G$9$,!"e(B
e$B$J$s$+FbB!$,8+$($F$k5$$,$7$F!#e(B

                            e$B$^$D$b$He(B e$B$f$-$R$me(B /:|)

At Sun, 10 May 2009 06:00:08 +0900,
matz wrote:

In message “Re: [ruby-dev:38394] Re: Enumerable#gather_each”
on Sat, 9 May 2009 15:53:22 +0900, ujihisa [email protected] writes:

|一度に二つの手続きを渡すのではなく、一つのブロックを受け取りEnumeratorを返すgatherと、従来のeachに分けた方が自然になるのではないでしょうか。

私もそう思います。ただ、Enumerableから「条件を満たす限り連続
ã—ãŸè¦ç´ ã‚’ã¾ã¨ã‚ã‚‹ã€ã“ã¨ã‚’gatherと呼ぶことになんとなく満足で
きません。gatherという単語からは全体から集めるような印象を受
けませんか? 私だけの感覚でしょうか。

 最初に提案を見て split_by, slice_at, group_until のような名前を
思い付きましたが、そうして名前を付けてみると、件の挙動にぴったり
来る名前がないというよりむしろ、それらの名前から想起される機能が
ある程度の幅を持つということが本質なのではないかと気づきます。

ã€€ã™ãªã‚ã¡ã€ç”°ä¸­ã•ã‚“ã‚‚è§¦ã‚ŒãŸé€šã‚Šã€ãƒ˜ãƒƒãƒ€è¡Œã®å ´åˆã¯ãã“ã‹ã‚‰å§‹ã¾ã‚Šã€
ãƒ•ãƒƒã‚¿è¡Œã®å ´åˆã¯ãã“ã§çµ‚ã‚ã‚Šã€åŒºåˆ‡ã‚Šè¡Œã®å ´åˆã¯èª­ã¿æ¨ã¦ã‚‹ã€ã¨ã„ã†
ような複数の要求が想定でき、それら使い分けができる柔軟性が必要
なのではないかということです。

とはいえ、[ruby-dev:38399]のbufferというのも、気持ちは分かる
んですが、ちょっと違うような気がします。柔軟性は高いんですが、
なんか内臓が見えてる気がして。

 内臓というのはどのあたりのことでしょうか。すっきりしていると
思うんですが。Ruby って大体の部分において内臓は見られますよね。

e$B@.@%$G$9!#e(B

Akinori MUSHA wrote:

e$B$7$?MWAG$r$^$H$a$k!W$3$H$re(Bgathere$B$H8F$V$3$H$K$J$s$H$J$/K~B-$Ge(B
e$B$-$^$;$s!#e(Bgathere$B$H$$$&C18l$+$i$OA4BN$+$i=8$a$k$h$&$J0u>]$r<ue(B
e$B$1$^$;$s$+!)e(B e$B;d$@$1$N463P$G$7$g$&$+!#e(B

e$B!!:G=i$KDs0F$r8+$Fe(B split_by, slice_at, group_until e$B$N$h$&$JL>A0$re(B
e$B;W$$IU$-$^$7$?$,!"$=$&$7$FL>A0$rIU$1$F$_$k$H!“7o$N5sF0$K$T$C$?$je(B
e$BMh$kL>A0$,$J$$$H$$$&$h$j$`$7$m!”$=$l$i$NL>A0$+$iA[5/$5$l$k5!G=$,e(B
e$B$"$kDxEY$NI}$r;}$D$H$$$&$3$H$,K<A$J$N$G$O$J$$$+$H5$$E$-$^$9!#e(B

gather_bye$B$H$+e(Bsplit_before/aftere$B$H$+?’!9G:$s$@$s$G$9$,!"e(B
e$B$3$l$NF0$-$C$F!"e(Bdivide lines according to proc’s return
valuee$B$8$c$J$$$G$9$+$M!#e(B
e$B$D$^$j!"e(Bdivide_eache$B$H$+!#e(B
e$B=8$a$k$H8@$&$h$j$b!"J,$1$k%$%a!<%8e(B

e$B;W$&$s$G$9$,!#e(BRuby e$B$C$FBgBN$NItJ,$K$*$$$FFbB!$O8+$i$l$^$9$h$M!#e(B
e$B$o$?$7$b%P%C%U%!$rMQ0U$7$F!<$H$$$&$N$O9M$($?$N$G$9$,!"e(B
e$BEDCf$5$s$Ne(Bgather_eache$B$G2DG=$J$3$H$,!"e(B
gather_eache$B$h$jJ#;($K$J$C$F$7$^$C$?$i%@%a$J$s$8$c$J$$$G$9$+$M!#e(B

e$BEDCf$5$s$Ne(Bgather_eache$B$G$G$-$k$3$H$O!"$3$l0J>e35G0$rA}$d$5$:e(B
e$B$[$\F1Ey$N5-=RNL$G$3$J$;$D$D!"<+M3EY$b$"$2$i$l$J$$$H$$$1$J$$$N$+$J$H!#e(B

Rubye$B$J$s$Ge(BBuffere$B$_$?$$$J35G0$rF3F~$7$F$b0U30$H$9$C$-$j$9$k$s$G$9$,!"e(B
e$B$=$3$G4E$($A$c$$$1$J$$$s$8$c$J$$$+$H;W$&$N$G$9$h!#e(B

e$B$H$$$&$+!"$3$l$C$F%P%C%U%!$OJL$KDs6!$7$F!"e(B

Enumerablee$BHGe(Binjecte$B$G$d$k$Y$-$J5$$be(B

e$B$J$*!“J#?t9T$r$^$H$a$kJ}K!$H$7$F;H$$$=$&$J$b$N$O!”$^$H$a$k@he(B
e$BF,MWAG$r8!=P$9$kJ}K!$r;XDj$9$k$H$+!“B>$K$b$$$/$D$+$”$k$h$&$Ke(B
e$B;W$$$^$9!#$?$H$($Pe(B ChangeLog e$B$de(B mbox e$B$r07$&$N$K$O!"@hF,MWAGe(B
e$B$r;XDj$9$k$N$,$$$$$G$7$g$&!#$=$&$$$&$b$N$O$^$?JL$N%a%=%C%I$He(B
e$B$7$F:n$k$N$,$$$$$N$G$O$J$$$+$H;W$$$^$9!#e(B

e$B$G!"9M$($?$N$G$9$,!"e(BChangeLoge$B$de(Bmboxe$B$N>l9g$KBP1~$9$k$K$O!"e(B
e$BD>A0$NMWAG$NJ,N`7k2L$,$o$+$l$P$=$l$GB-$j$k$s$8$c$J$$$G$9$+$M!#e(B
e$B7k6I$3$l$i$O!"e(B

  • e$BFCDj$NMWAG$O<+J,$,J,N`7k2Le(B
  • e$B$=$l0J30$OD>A0$NJ,N`7k2L$HF1$8e(B
    e$B$H$$$&%k!<%k$J$N$G!"e(B
    arg = lambda {|l, current| l =~ /^\S/ ? self : current }
    e$B$_$?$$$K$9$l$P$h$$$+$J$!$H!#e(B

e$B$3$l$J$i$PEDCf$5$s$Ne(Bgather_eache$B$G2DG=$@$C$?$3$H$O!"e(B
currente$B$rFI$_<N$F$l$P$$$$$@$1$J$N$GA4$/F1$8%3!<%I$G2DG=$K$J$j$^$9!#e(B

In article [email protected],
Yukihiro M. [email protected] writes:

e$B;d$b$=$&;W$$$^$9!#$?$@!"e(BEnumerablee$B$+$i!V>r7o$rK~$?$98B$jO"B3e(B
e$B$7$?MWAG$r$^$H$a$k!W$3$H$re(Bgathere$B$H8F$V$3$H$K$J$s$H$J$/K~B-$Ge(B
e$B$-$^$;$s!#e(Bgathere$B$H$$$&C18l$+$i$OA4BN$+$i=8$a$k$h$&$J0u>]$r<ue(B
e$B$1$^$;$s$+!)e(B e$B;d$@$1$N463P$G$7$g$&$+!#e(B

e$B$&$%$!#$=$s$J$K0-$/$O$J$$$H;W$C$F$$$?$N$G$9$,!"NI$$L>A0$,$"e(B e$B$l$P@Q6KE*$K<u$1F~$l$?$$$H;W$C$F$$$^$9!#e(B (e$B$"$H!"e(BChangeLog e$B$NN$N$?$a$N%a%=%C%IL>$be(B)

e$B$@$+$i$H$C$FBe$o$j$NC18l$r;W$$$D$+$J$$$o$1$G$9$,!#e(B

Unix e$B$@$He(B uniq e$B$J$s$G$9$,e(B ruby e$B$@$He(B uniq
e$B$bA4BN$@$7$J$!!#e(B

up, scrape together, show up, stack up, stockpile, swarm,
throng, unite

e$B$H$“$j$^$7$?!#L@$i$+$K0c$&$@$m$&$H$+!“JL$N0UL#$G;H$C$F$k$H$+e(B
e$B$$$&$b$N$b$”$j$^$9$,!”;29M$^$G$K!#e(B

e$B$3$NCf$@$H!“e(Baccumulate, aggregate, pour, unite e$B$”$?$j$O$I$&e(B
e$B$G$9$+$M!#e(B

e$BB>$K$Oe(B each_slice e$B$+$i8l$r<ZMQ$7$Fe(B slice e$B$b$7$/$Oe(B
slice_by
e$B$O$I$&$G$7$g$&$+e(B?

e$B$"$H$Oe(B categorize e$B$H$$$&$N$b;W$$$D$-$^$7$?$,$3$l$OA4BN$C$]$$e(B
e$B$J$!!#e(B

In article [email protected],
“NARUSE, Yui” [email protected] writes:

e$B$G!"9M$($?$N$G$9$,!"e(BChangeLoge$B$de(Bmboxe$B$N>l9g$KBP1~$9$k$K$O!"e(B
e$BD>A0$NMWAG$NJ,N`7k2L$,$o$+$l$P$=$l$GB-$j$k$s$8$c$J$$$G$9$+$M!#e(B

e$BD>A0$N$O$$$i$J$$$s$8$c$J$$$G$7$g$&$+!#e(B

e$B$“$kJB$S$,$”$C$F!“$=$N$J$+$G$N$^$H$^$j$N@hF,MWAG$,H=JL$G$-$le(B
e$B$P!”$=$3$G6h@Z$l$P$$$$$o$1$G$9!#2>$Ke(B slice_by e$B$H$9$k$H0J2<$Ne(B
e$B$h$&$J46$8$K$J$j$^$9!#e(B

module Enumerable
def slice_by
i = 0
self.gather {|e| i += 1 if yield e; i }
end
end

open(“mbox”) {|f|
f.slice_by {|l| l.start_with? "From " }.each {|lines| pp lines }
}

In article [email protected],
“Akinori MUSHA” [email protected] writes:

e$B!!>/$7;EMM$,$o$+$j$K$/$$$h$&$K;W$$$^$9!#7+$jJV$7$H$$$&%9%H%j!<%`$Ne(B
e$B%P%C%U%!$H$$$&H/A[$+$i!"<!$N$h$&$J%$%s%?!<%U%'!<%9$r9M0F$7$^$7$?!#e(B

e$B$I$N$h$&$K$o$+$j$K$/$+$C$?$G$7$g$&$+e(B?

e$B$I$&$G$7$g$&$+!#e(B

e$B$^$:!“e(Bgather_each
e$B$KHf$Y$F%3!<%I$,D9$/$J$C$F$h$m$7$/$”$j$^$;$s!#e(B

e$B$?$H$($P!":G=i$K=P$7$?%Q%i%0%i%U$NNc$O0J2<$N$h$&$KD9$/$J$C$F$7$^$$$^$9!#e(B

buffer:
open(“lib/scanf.rb”) {|f|
f.buffer {|e, b|
s = e == “\n”
b.flush if b.status != nil && b.status != s
b.status = s
b << e
}.each {|lines| pp lines }
}

gather_each:
arg = lambda {|l| l == “\n” }
open(“lib/scanf.rb”) {|f|
f.gather_each(arg) {|lines| pp lines }
}

e$B$^$?!“e(Bgather_each e$B$O!”$“$kMWAG$KBP$9$k=hM}$O!”$=$NMWAG$H$=$le(B
e$B$,B0$9$k$^$H$^$j$N$3$H$@$1$r9M$($F=q$1$P$$$$$h$&$K%G%6%$%s$7e(B
e$B$F$"$k$N$G$9$,!“e(Bbuffer e$B$G$OD>A0$N$^$H$^$j$re(B flush
e$B$9$kI,MW$,e(B
e$B$”$C$F!"D>A0$N$^$H$^$j$K$D$$$F$b9M$($J$1$l$P$$$1$^$;$s!#e(B
e$B$D$^$j!“e(Bbuffer e$B$N$[$&$,9M$($k$3$H$,B?$/$J$C$F$h$m$7$/$”$j$^e(B
e$B$;$s!#e(B

e$B$?$H$($P!"e(BChangeLog e$B$r%(%s%H%jC10L$K=hM}$9$k$K$O!“9TF,$,6uGre(B
e$B$8$c$J$+$C$?$ie(B flush e$B$9$l$P$$$$$H$$$&$o$1$G0J2<$N$h$&$K$9$le(B
e$B$P$$$$$H9M$($k$+$b$7$l$^$;$s$,!”<B$O$=$l$@$1$@$H@hF,$Ke(B [] e$B$,e(B
e$BI=<($5$l$k$H$$$&%P%0$,H/@8$7$F$7$^$$$^$9!#e(B

open(“ChangeLog”) {|f|
f.buffer {|e, b|
b.flush if /\A\S/ =~ e
b << e
}.each {|lines| pp lines }
}

e$B$A$c$s$H$d$k$K$O>r7o$re(B /\A\S/ =~ e && !b.empty? e$B$K$7$J$$$H$$e(B
e$B$1$^$;$s!#e(B

e$B$3$&$$$&!“D>A0$,$J$s$@$C$?$+!”$H$$$&$N$r9M$($J$/$F$$$$$H$$$&e(B
e$B$N$,e(B gather_each e$B$NMxE@$G$9!#e(B

e$B$“$H!“e(BBuffer e$B$K$Oe(B status
e$B$H$$$&5!G=$,$”$j$^$9$,!”>uBV$r$I$&e(B
e$B$7$F$b4IM}$7$?$$$J$i%l%-%7%+%k%9%3!<%W$NJQ?t$G$$$$$s$8$c$J$$e(B
e$B$G$7$g$&$+!#$?$H$($P!"%Q%i%0%i%U$NNc$O0J2<$N$h$&$K=q$$$F$b$$$$e(B
e$B$o$1$G$9!#e(B

open(“lib/scanf.rb”) {|f|
status = nil
f.buffer {|e, b|
s = e == “\n”
b.flush if status != nil && status != s
status = s
b << e
}.each {|lines| pp lines }
}

e$B$=$7$F!"e(Bgather_each e$B$G$bF1MM$K>uBV$O07$($F!"e(BChangeLog
e$B$N%(%se(B
e$B%H%j$O0J2<$N$h$&$K=hM}$G$-$^$9!#e(B(gather e$B$r;H$C$F$_$^$7$?e(B)

open(“ChangeLog”) {|f|
i = 0
f.gather {|l| i += 1 if /\A\S/ =~ l; i }.each {|lines| pp lines }
}

e$B$J$*!“;d$H$7$F$O$3$l$r4+$a$F$$$k$o$1$G$O$J$/$F!”%f!<%6$,$=$&e(B
e$B$$$&>uBVA+0$r9M$($J$/$F:Q$`$H$$$&$N$,NI$$$H;W$C$F$$$^$9!#e(B
e$B$D$^$j!“@lMQ$N%a%=%C$r:n$k$[$&$,!”>uBV$r9M$($J$/$F$$$$$N$GNIe(B
e$B$$$H;W$$$^$9!#e(B

e$B!!>e5-$N%$%s%?!<%U%'!<%9$@$H;HMQNc$N$h$&$K6h@Z$j$rEO$5$J$$$3$H$be(B
e$B$G$-$^$9$7!"e(B yield e$B$rDI2C$NA0$K$9$k$+8e$K$9$k$+$b<+M3$G$9!#$^$?!"e(B
status/status= e$B$rDs6!$9$k$3$H$G>uBVA+0$r07$&$3$H$b;Y1g$G$-$^$9!#e(B

gather_each e$B$G$b!“MWAG$r7k2L$+$i=|5n$9$k;XDj$O=PMh$F$b$$$$$+e(B
e$B$J!”$H$$$&5$$O$7$^$9!#$=$N$?$a$NCM$rJ,N`7k2L$KDj5A$7$F$*$1$Pe(B
e$B2DG=$G!“e(Bnil e$B$r$=$N0UL#$K$9$k$+!”$“$k$$$Oe(B :delete
e$B$”$?$j$K$9e(B
e$B$k$+!"$J$K$,$$$$$+$J!#e(B

buffer e$B$O$$$m$s$J$3$H$,$G$-$k$h$&$K$9$k$H$$$&0U?^$,46$8$i$le(B
e$B$^$9$,!“8=<BE*$JMQES$NA[Dj$H$7$F!”$I$s$J$b$N$,9M$($i$l$^$9$+e(B?

e$B;d$O!“e(Bgather_each e$B$H$”$H$b$&$R$H$De(B ChangeLog
e$B$_$?$$$J$b$N$re(B
e$B=hM}$9$k$b$N$,$“$k$H!”$+$J$j$NHO0O$NMQES$r07$($k$N$G$O$J$$$+!"e(B
e$B$H9M$($F$$$^$9!#$=$N?dB,$,@5$7$1$l$P@lMQ$N%a%=%C%I$N$[$&$,JXe(B
e$BMx$G$7$g$&!#e(B

In article [email protected],
“NARUSE, Yui” [email protected] writes:

e$B$J$k$[$I!"%f!<%9%1!<%9$4$H$K@lMQ%a%=%C%I$rMQ0U$9$kJ}?K$G$9$+!#e(B

Enumerable e$B$N>l9g!“$”$k%a%=%C%I$G$G$-$J$$$3$H$,$“$C$F$bB>$Ge(B
e$B<B8=$G$-$J$$$3$H$O$J$$$N$G!”$J$s$G$b$G$-$J$1$l$P$J$i$J$$$H$$e(B
e$B$&MW5a$O>.$5$$$G$9$M!#e(B

e$B$=$&$9$k$H3N$+$KLdBj$O$I$N$h$&$J%f!<%9%1!<%9$K$D$$$F!"e(B
e$B$I$s$JL>A0$N%a%=%C%I$rMQ0U$9$k$+$@$1$J$o$1$G$9$M!#e(B

e$B$b$A$m$s!“>/$J$$CN<1$H5-=R$G$?$/$5$s$NMQES$rK~$?$;$k$K1[$7$?e(B
e$B$3$H$O$J$$$N$G!”$I$N$"$?$j$rA@$&$+$,LdBj$K$J$j$^$9!#e(B

Array#compacte$B$H$+!"@N$Ne(BArray#[]=nile$B$H$+$r9M$($k$He(Bnile$B$,<+A3$J5$$b$7$^$9$,!"e(B
e$B$=$l$3$=N>J}MQ0U$7$?J}$,$$$$$s$8$c$J$$$G$9$+$M!"FCDj$N$r=|30$9$k$N$H$7$J$$$N$r!#e(B

:delete e$B$He(B :singleton e$B$H$+$+$J$!e(B

svn log e$B$H$+$r=hM}$9$k$H6h@Z$j$O>C$7$?$/$J$k$N$G!"e(B

% svn log enum.c|./ruby -rpp -e ’
sep =
“------------------------------------------------------------------------\n”
ARGF.gather {|l| l == sep }.each {|lines| pp lines }

[“------------------------------------------------------------------------\n”]
[“r22552 | nobu | 2009-02-22 23:23:33 +0900 (Sun, 22 Feb 2009) | 1
line\n”,
“\n”,
“stripped trailing spaces.\n”]
[“------------------------------------------------------------------------\n”]
[“r21678 | nobu | 2009-01-20 06:47:48 +0900 (Tue, 20 Jan 2009) | 3
lines\n”,
“\n”,
“* array.c (take_items), enum.c (enum_zip): tries to
convert to\n”,
" array first. [ruby-core:21442]\n",
“\n”]

e$B$3$3$Ge(B
ARGF.gather {|l| l == sep ? : :delete : true }
e$B$K$9$k$H$+!#e(B

e$B$^$H$a$k$H!"I,MW$J$N$Oe(B

  • e$B0z?t$G$"$ke(Bproce$B$NLa$jCM$4$H$K$^$H$a$k4pK%a%=%C%Ie(B
  • e$B0lIt$r<N$F$k%a%=%C%Ie(B
  • e$BFCDj$NMWAG$ND>A0$GJ,$1$k%a%=%C%Ie(B
  • e$BFCDj$NMWAG$ND>8e$GJ,$1$k%a%=%C%Ie(B
    e$B$"$?$j$J$N$G$7$g$&$+e(B

e$B$I$l$,4pK$+$I$&$+$H$$$&$N$O$H$/$K0U<1$7$J$/$F$$$$$s$8$c$J$$e(B
e$B$G$9$+$M!#$?$V$se(B slice_by e$B$r;H$C$Fe(B gather
e$B$r<B8=$9$k$N$O$G$-e(B
e$B$k5$$,$7$^$9!#e(B

e$BD>8e$GJ,$1$kMQES$O=<J,$K$?$/$5$s$"$k$s$G$9$+$M$'!#$=$l$Oe(B
e$B$h$/$o$+$j$^$;$s!#:n$k$3$H$K$J$C$?$H$-$KL>A0$KG:$^$J$$$h$&$Ke(B
e$B$7$F$$/$N$O$$$$$+$b$7$l$^$;$s$,!#D>A0$re(B slice_before e$B$K$7$Fe(B
e$B$
$$$F!"I,MW$K$J$C$?$H$-$K$Oe(B slice_after e$B$r:n$k$H$+!#e(B

e$B$“$H!”@lMQ%a%=%C%I$rA}$d$;$PA}$d$9$[$I$$$$$H$$$&$o$1$G$b$“$je(B
e$B$^$;$s!#%a%=%C%I$,A}$($k$H$I$l$,E,@Z$+%f!<%6$,A*$P$J$$$H$$$1e(B
e$B$^$;$s$+$i!#5-=R$,HK;($K$J$i$J$$$J$i!”$R$H$D$N%a%=%C%I$N5!G=e(B
e$B$rA}$d$9$H$$$&$N$bABr;h$K$J$j$^$9!#$=$&$9$l$P!"$&$^$/F0$+$Je(B
e$B$+$C$?$H$-$K%a%=%C%I$rA
$V$H$3$m$+$i$d$jD>$9$N$G$J$/!"%V%m%Ce(B
e$B%/$NCf$r$$$8$k$@$1$G=$@5$7$F$$$1$k2DG=@-$,A}$7$^$9!#e(B

e$B@.@%$G$9!#e(B

Tanaka A. wrote:

e$B$J$*!";d$H$7$F$O$3$l$r4+$a$F$$$k$o$1$G$O$J$/$F!"%f!<%6$,$=$&e(B
e$B$$$&>uBVA+0$r9M$($J$/$F:Q$`$H$$$&$N$,NI$$$H;W$C$F$$$^$9!#e(B
e$B$D$^$j!"@lMQ$N%a%=%C$r:n$k$[$&$,!">uBV$r9M$($J$/$F$$$$$N$GNIe(B
e$B$$$H;W$$$^$9!#e(B

e$B$J$k$[$I!"%f!<%9%1!<%9$4$H$K@lMQ%a%=%C%I$rMQ0U$9$kJ}?K$G$9$+!#e(B
e$B$=$&$9$k$H3N$+$KLdBj$O$I$N$h$&$J%f!<%9%1!<%9$K$D$$$F!"e(B
e$B$I$s$JL>A0$N%a%=%C%I$rMQ0U$9$k$+$@$1$J$o$1$G$9$M!#e(B

e$B!!>e5-$N%$%s%?!<%U%’!<%9$@$H;HMQNc$N$h$&$K6h@Z$j$rEO$5$J$$$3$H$be(B
e$B$G$-$^$9$7!"e(B yield e$B$rDI2C$NA0$K$9$k$+8e$K$9$k$+$b<+M3$G$9!#$^$?!"e(B
status/status= e$B$rDs6!$9$k$3$H$G>uBVA+0$r07$&$3$H$b;Y1g$G$-$^$9!#e(B

gather_each e$B$G$b!“MWAG$r7k2L$+$i=|5n$9$k;XDj$O=PMh$F$b$$$$$+e(B
e$B$J!”$H$$$&5$$O$7$^$9!#$=$N$?$a$NCM$rJ,N`7k2L$KDj5A$7$F$*$1$Pe(B
e$B2DG=$G!“e(Bnil e$B$r$=$N0UL#$K$9$k$+!”$"$k$$$Oe(B :delete e$B$"$?$j$K$9e(B
e$B$k$+!"$J$K$,$$$$$+$J!#e(B

Array#compacte$B$H$+!"@N$Ne(BArray#[]=nile$B$H$+$r9M$($k$He(Bnile$B$,<+A3$J5$$b$7$^$9$,!"e(B
e$B$=$l$3$=N>J}MQ0U$7$?J}$,$$$$$s$8$c$J$$$G$9$+$M!"FCDj$N$r=|30$9$k$N$H$7$J$$$N$r!#e(B

e$B;d$O!“e(Bgather_each e$B$H$”$H$b$&$R$H$De(B ChangeLog e$B$_$?$$$J$b$N$re(B
e$B=hM}$9$k$b$N$,$"$k$H!"$+$J$j$NHO0O$NMQES$r07$($k$N$G$O$J$$$+!"e(B
e$B$H9M$($F$$$^$9!#$=$N?dB,$,@5$7$1$l$P@lMQ$N%a%=%C%I$N$[$&$,JXe(B
e$BMx$G$7$g$&!#e(B

e$B$^$H$a$k$H!"I,MW$J$N$Oe(B

  • e$B0z?t$G$"$ke(Bproce$B$NLa$jCM$4$H$K$^$H$a$k4pK%a%=%C%Ie(B
  • e$B0lIt$r<N$F$k%a%=%C%Ie(B
  • e$BFCDj$NMWAG$ND>A0$GJ,$1$k%a%=%C%Ie(B
  • e$BFCDj$NMWAG$ND>8e$GJ,$1$k%a%=%C%Ie(B
    e$B$"$?$j$J$N$G$7$g$&$+e(B

ujihisae$B$H$$$$$^$9!#e(B

e$B$=$l$3$=N>J}MQ0U$7$?J}$,$$$$$s$8$c$J$$$G$9$+$M!"FCDj$N$r=|30$9$k$N$H$7$J$$$N$r!#e(B
ARGF.gather {|l| l == sep ? : :delete : true }

ARGF.gather(false) {|l| l == sep }
e$B$H$$$&$N$O$I$&$G$7$g$&!#e(B

module Enumerable
def gather(included = true)

e$BL5;XDj$^$?$Oe(Btruee$B$J$i$P!V6-3&!W$b4^$_!“e(Bfalsee$B$J$i$P$=$NItJ,$r=|30$9$k!”$H!#e(B

e$B@.@%$G$9!#e(B

Tanaka A. wrote:

group, hang around, hang out, heap, herd, hoard, huddle, ake
the scene, marshal, mass, meet, muster, pick, pile up,
pluck, poke, pour in, punch, rally, reunite, round up, scare
up, scrape together, show up, stack up, stockpile, swarm,
throng, unite

e$B$H$“$j$^$7$?!#L@$i$+$K0c$&$@$m$&$H$+!“JL$N0UL#$G;H$C$F$k$H$+e(B
e$B$$$&$b$N$b$”$j$^$9$,!”;29M$^$G$K!#e(B

e$B$3$NCf$@$H!“e(Baccumulate, aggregate, pour, unite e$B$”$?$j$O$I$&e(B
e$B$G$9$+$M!#e(B

e$B$=$Ne(B4e$B$D$@$He(Baggregatee$B$,9%$_$+$J$!!#e(B
e$B$^$!!"e(Bgathere$B$NMQK!$r8+$F$$$k$HBg;(GD$J8l$N$h$&$K$b8+$($k$N$G!"e(B
e$B$o$?$7$Oe(Bgathere$B$G$b$$$$$+$J$!$H;W$$;O$a$F$b$$$^$9!#e(B
http://dic.yahoo.co.jp/dsearch?enc=UTF-8&p=gather&dtype=1

e$B<-=q$rA`$k$H!“!VF1<o$NJ*$r$^$H$a$k!WIw$N0UL#$Ne(Bbunche$B$He(Bsheafe$B$H$+$”$j$^$9$M!#e(B
http://dic.yahoo.co.jp/dsearch?enc=UTF-8&p=bunch&dtype=1
http://dic.yahoo.co.jp/dsearch?enc=UTF-8&p=sheaf&dtype=1
e$BA4BN$G$J$/E,Ev$KB+$K$9$k46$8e(B

e$BB>$K$Oe(B each_slice e$B$+$i8l$r<ZMQ$7$Fe(B slice e$B$b$7$/$Oe(B slice_by
e$B$O$I$&$G$7$g$&$+e(B?

e$BD>A0$G@Z$k!<$@$He(Bslice_beforee$B$H$+$NJ}$,$7$C$/$jMh$k$s$G$9$,!"e(B
e$BEDCf$5$s$Ne(Bgathere$B$re(Bslicee$B$J$s$A$c$i$K$7$F$7$^$&$H0c$&46$8$G$9$M!#e(B

In article
[email protected],
ujihisa [email protected] writes:

e$BL5;XDj$^$?$Oe(Btruee$B$J$i$P!V6-3&!W$b4^$_!“e(Bfalsee$B$J$i$P$=$NItJ,$r=|30$9$k!”$H!#e(B

gather e$B$N;EMM$K$O6-3&$H$$$&35G0$O$J$$$N$G!"$=$l$O$&$^$/$J$$e(B
e$B$+$J$!!#e(B

gather e$B$OC1$K%V%m%C%/$NCM$,F1$8$GNY@$7$F$$$k$b$N$r$^$H$a$ke(B
e$B$@$1$J$N$G!"$I$l$,6-3&$G$I$l$,$=$&$G$J$$$+$H$+$H$$$&6hJL$O$7e(B
e$B$F$$$J$$$s$G$9!#e(B

e$B$b$A$m$s!“FCDj$N%V%m%C%/$NCM$K!V6-3&!W$H$$$&0UL#$r$D$1$F!”$=e(B
e$B$l$r<h$j=|$/$+$I$&$+$r0z?t$G;XDj$9$k$H$$$&;EMM$r9M$($k$3$H$be(B
e$B=PMh$^$9$,!"$=$l$@$C$?$i!V6-3&!W$8$c$J$/$FD>@!V<h$j=|$/!W$He(B
e$B$$$&0UL#$r$D$1$?$[$&$,4JC1$G$7$g$&!#e(B

false e$B$K!V<h$j=|$/!W$H$$$&0UL#$r$D$1$k$H$$$&$N$b9M$($i$l$J$/e(B
e$B$O$"$j$^$;$s$,!#e(B

At Sun, 10 May 2009 10:08:47 +0900,
Tanaka A. wrote:

In article [email protected],
“Akinori MUSHA” [email protected] writes:

 少し仕様がわかりにくいように思います。繰り返しというストリームの
バッファという発想から、次のようなインターフェースを考案しました。

どのようにわかりにくかったでしょうか?

nil の扱いの特殊性(捨てるのでなくそれ単独で、という意味づけ)とか、
gather という名前のせいかも知れませんが同じ値が再出しても前とは
関係ないというあたりですかねえ。

 引用を前後させてしまいますが、

}

ちゃんとやるには条件を /\A\S/ =~ e && !b.empty? にしないとい
けません。

これは思いました。バッファが空(初期化状態)ã®å ´åˆã¯ flush しても
yield しないようにするべきですね。

どうでしょうか。

まず、gather_each に比べてコードが長くなってよろしくありません。

たとえば、最初に出したパラグラフの例は以下のように長くなってしまいます。

 最初の例というのが

arg = lambda {|l| /\A=~ l ? true : nil }
で読めなかったのですが、 l == “\n” でしたか。

buffer:
open(“lib/scanf.rb”) {|f|
f.buffer {|e, b|
s = e == “\n”
b.flush if b.status != nil && b.status != s
b.status = s
b << e
}.each {|lines| pp lines }
}

これは

    prev, s.status = s.status, (e == "\n")
    b.flush if prev != b.status
    b << e

くらいで悪くはないと思います。b.status != nil のところは、上記の
「空なら flush しない」で手当てするとして。

 やりすぎかもしれませんが、 status/status= を提供するのなら、
prev_status や status_changed? も用意するという手はあります。

gather_each:
arg = lambda {|l| l == “\n” }
open(“lib/scanf.rb”) {|f|
f.gather_each(arg) {|lines| pp lines }
}

 区切るだけなら確かに1行で済みますが、実際にはサンプルコード辺か
どうかを判定したり、前後の空行を除いたりと最終結果までの道のりは
長いので何とも言えません。要らない部分まで集めて(gather)いますが、
本当はもっと複雑な処理が必要なので buffer のようなものがあれば、
å–æ¨ã‚„åŠ å·¥ã«ã¤ã„ã¦ã‚‚å¼•ãå—ã‘ã‚‹ã“ã¨ãŒã§ãã‚‹ã¨æ€ã„ã¾ã—ãŸã€‚

また、gather_each ã¯ã€ã‚ã‚‹è¦ç´ ã«å¯¾ã™ã‚‹å‡¦ç†ã¯ã€ãã®è¦ç´ ã¨ãã‚Œ
が属するまとまりのことだけを考えて書けばいいようにデザインし
てあるのですが、buffer では直前のまとまりを flush する必要が
あって、直前のまとまりについても考えなければいけません。
つまり、buffer のほうが考えることが多くなってよろしくありま
せん。

こういう、直前がなんだったか、というのを考えなくていいという
のが gather_each の利点です。

 上記の通り、実際に考えるべきことが後ろに残ると思うので、 gather
単体の提供する機能が中途半端に思えたのです。すなわち、インデント
レベル等、分類の基準として計算した値(ブロックの評価値)を捨てて
しまっていますが、この例でも、後段でまた必要になりそうですよね。

そして、gather_each でも同様に状態は扱えて、ChangeLog のエン
トリは以下のように処理できます。(gather を使ってみました)

open(“ChangeLog”) {|f|
i = 0
f.gather {|l| i += 1 if /\A\S/ =~ l; i }.each {|lines| pp lines }
}

 そこが妥協可能ならそれでもいいですね。buffer の引数で status の
初期値を与えるようなことも考えていましたが。

なお、私としてはこれを勧めているわけではなくて、ユーザがそう
いう状態遷移を考えなくて済むというのが良いと思っています。
つまり、専用のメソッを作るほうが、状態を考えなくていいので良
いと思います。

 なるほど。それと、再び引用が前後しますが、

私は、gather_each とあともうひとつ ChangeLog みたいなものを
処理するものがあると、かなりの範囲の用途を扱えるのではないか、
と考えています。その推測が正しければ専用のメソッドのほうが便
利でしょう。

ということであれば、 buffer を使って gather 等を実装するのは容易
なので、複数のメソッドを用意するのなら、実装を共有するためにも
buffer のような汎用のものを持つメリットがあるということになるの
ではないでしょうか。

gather_each ã§ã‚‚ã€è¦ç´ ã‚’çµæžœã‹ã‚‰é™¤åŽ»ã™ã‚‹æŒ‡å®šã¯å‡ºæ¥ã¦ã‚‚ã„ã„ã‹
な、という気はします。そのための値を分類結果に定義しておけば
可能で、nil をその意味にするか、あるいは :delete あたりにす
るか、なにがいいかな。

buffer はいろんなことができるようにするという意図が感じられ
ますが、現実的な用途の想定として、どんなものが考えられますか?

 buffer は1回のイテレーションで複数の値を push したり複数回
flush したり(あるいはしなかったり)でき、またイテレータ引数で
なく任意の値を push できるので、 lexer などを実装できます。

 というか、 scanf.rb をパースする例を見て、実際の延長上には
lexer のようなものがあるんじゃないかと推測しました。

e$B@.@%$G$9!#e(B

ujihisa wrote:

...

e$BL5;XDj$^$?$Oe(Btruee$B$J$i$P!V6-3&!W$b4^$_!“e(Bfalsee$B$J$i$P$=$NItJ,$r=|30$9$k!”$H!#e(B

e$B!VL5;XDj$^$?$Oe(Btruee$B$J$i$P!W$@$HLa$jCM$,e(Btruee$B$N;~$K=|30$7$?$$>l9g$K:$$j$^$9!#e(B
e$B$^$!!"e(B*arge$B$G=&$C$F$d$l$PL5;XDj$N>l9g$r$-$A$s$H=&$($k$N$G!“e(B
e$B=|30$9$k7k2L$r0z?t$GM?$($k$H$$$&$N$O$”$j$G$7$g$&$M!#e(B

In article [email protected],
Tanaka A. [email protected] writes:

C e$B$G$N<BAu$O$^$@$G$9$,!"$3$l$+$i$d$kM=Dj$G$9!#e(B

e$B$H$j$"$($:e(B C e$B$G<BAu$7$F$_$?$N$G$D$1$F$*$-$^$9!#e(B

e$B0J2<$N%a%=%C%I$r<BAu$7$F$"$j$^$9!#e(B

  • Enumerable#gather_each
  • Enumerable#gather
  • Enumerable#slice_before

slice_before e$B$Oe(B Yielder e$B$r;H$C$F$"$j$^$9!#e(B

gather e$B$be(B Yielder e$B$r;H$&7A$K$9$l$P!"e(Bgather_each
e$B$r$J$/$9$3$He(B
e$B$O2DG=$@$H;W$$$^$9!#e(B

% svn diff --diff-cmd diff -x ‘-u -p’
Index: enumerator.c

— enumerator.c (revision 23381)
+++ enumerator.c (working copy)
@@ -14,6 +14,18 @@

#include “ruby/ruby.h”

+static VALUE
+enum_values_pack(int argc, VALUE *argv)
+{

  • if (argc == 0) return Qnil;
  • if (argc == 1) return argv[0];
  • return rb_ary_new4(argc, argv);
    +}

+#define ENUM_WANT_SVALUE() do { \

  • i = enum_values_pack(argc, argv);
    +} while (0)

/*

  • Document-class: Enumerator

@@ -45,6 +57,7 @@ struct yielder {
VALUE proc;
};

+static VALUE enumerator_allocate(VALUE klass);
static VALUE generator_allocate(VALUE klass);
static VALUE generator_init(VALUE obj, VALUE proc);

@@ -247,6 +260,61 @@ enum_each_with_object(VALUE obj, VALUE m
return memo;
}

+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 = enumerator_allocate(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;
    +}

static VALUE
enumerator_allocate(VALUE klass)
{
@@ -862,6 +930,8 @@ Init_Enumerator(void)
rb_define_method(rb_mEnumerable, “each_cons”, enum_each_cons, 1);
rb_define_method(rb_mEnumerable, “each_with_object”,
enum_each_with_object, 1);

  • rb_define_method(rb_mEnumerable, “slice_before”, enum_slice_before,
    0);
  • rb_cEnumerator = rb_define_class(“Enumerator”, rb_cObject);
    rb_include_module(rb_cEnumerator, rb_mEnumerable);

Index: enum.c

— enum.c (revision 23381)
+++ enum.c (working copy)
@@ -1793,6 +1793,141 @@ enum_cycle(int argc, VALUE argv, VALUE
return Qnil; /
not reached */
}

+struct gather_each_st {

  • VALUE arg;
  • VALUE prev_value;
  • VALUE prev_elts;
    +};

+static VALUE
+gather_each_i(VALUE i, VALUE _state, int argc, VALUE *argv)
+{

  • struct gather_each_st *statep = (struct gather_each_st *)_state;
  • VALUE v;
  • VALUE singleton, reject;
  • ENUM_WANT_SVALUE();
  • v = rb_funcall(statep->arg, rb_intern(“call”), 1, i);
  • singleton = ID2SYM(rb_intern(“singleton”));
  • reject = ID2SYM(rb_intern(“reject”));
  • if (v == singleton) {
  •    if (!NIL_P(statep->prev_value)) {
    
  •        rb_yield(statep->prev_elts);
    
  •        statep->prev_value = statep->prev_elts = Qnil;
    
  •    }
    
  •    rb_yield(rb_ary_new3(1, i));
    
  • }
  • else if (!RTEST(v) || v == reject) {
  •    if (!NIL_P(statep->prev_value)) {
    
  •        rb_yield(statep->prev_elts);
    
  •        statep->prev_value = statep->prev_elts = Qnil;
    
  •    }
    
  • }
  • else {
  •    if (NIL_P(statep->prev_value)) {
    
  •        statep->prev_value = v;
    
  •        statep->prev_elts = rb_ary_new3(1, i);
    
  •    }
    
  •    else {
    
  •        if (rb_equal(statep->prev_value, v)) {
    
  •            rb_ary_push(statep->prev_elts, i);
    
  •        }
    
  •        else {
    
  •            rb_yield(statep->prev_elts);
    
  •            statep->prev_value = v;
    
  •            statep->prev_elts = rb_ary_new3(1, i);
    
  •        }
    
  •    }
    
  • }
  • return Qnil;
    +}

+/*

    • call-seq:
    • enum.gather_each(arg) {|ary| ... } => nil
      
    • enum.gather_each(arg)              => enumerator
      
    • Iterates for each gathered elements of enum.
    • This method gathers consecutive elements which
    • arg.call(element) returns a same value.
    • The following values has special meaning:
      • nil, false and :reject specifies that gathered elements is not
        yielded.
      • :singleton specifies the element should be gathered only itself.
    • The gathered element is yielded as an array.
    • If the block is not given, an enumerator is returned.
    • (1…10).gather_each(lambda {|n| n & 2 }) {|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.gather_each(lambda {|line| /\A\s/ =~ line }) {|lines| pp lines
      }
  • */
    +static VALUE
    +enum_gather_each(int argc, VALUE *argv, VALUE self)
    +{
  • struct gather_each_st state;
  • rb_scan_args(argc, argv, “01”, &state.arg);
  • RETURN_ENUMERATOR(self, argc, argv);
  • state.prev_value = Qnil;
  • state.prev_elts = Qnil;
  • rb_block_call(self, id_each, 0, 0, gather_each_i, (VALUE)&state);
  • if (state.prev_value != Qnil)
  •    rb_yield(state.prev_elts);
    
  • return Qnil;
    +}

+/*

    • call-seq:
    • enum.gather {|elt| ... } => enumerator
      
    • Creates an enumerator for iterating gathered elements of enum.
    • This method gathers consecutive elements which
    • the blocks returns a same value.
    • The following values has special meaning:
      • nil, false and :reject specifies that gathered elements is not
        yielded.
      • :singleton specifies the element should be gathered only itself.
    • (1…10).gather {|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.gather {|line| /\A\s/ =~ line }.each {|lines| pp lines }
  • */
    +static VALUE
    +enum_gather(VALUE self)
    +{
  • VALUE block = rb_block_proc();
  • return rb_enumeratorize(self, ID2SYM(rb_intern(“gather_each”)), 1,
    &block);
    +}

/*

  • The Enumerable mixin provides collection classes with
  • several traversal and searching methods, and with the ability to
    @@ -1852,6 +1987,8 @@ 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_each”, enum_gather_each,
    -1);

  • rb_define_method(rb_mEnumerable, “gather”, enum_gather, 0);

    id_eqq = rb_intern(“===”);
    id_each = rb_intern(“each”);

In article [email protected],
“Akinori MUSHA” [email protected] writes:

nil e$B$N07$$$NFC<l@-e(B(e$B<N$F$k$N$G$J$/$=$lC1FH$G!"$H$$$&0UL#$E$1e(B)e$B$H$+!"e(B

e$B$J$k$[$I!#$3$l$K$D$$$F$O$$$^5DO@$,$“$j$^$9$,!”$$$/$D$+$NCM$Ke(B
e$B$D$$$F$OFC<l$J0UL#$,$"$k$H$$$&$3$H$K$J$l$P!"0lHL2=$5$l$F$=$&e(B
e$B$$$&$b$N$@$H$$$&5$$K$J$k$+$b$7$l$^$;$s!#e(B

gather e$B$H$$$&L>A0$N$;$$$+$bCN$l$^$;$s$,F1$8CM$,:F=P$7$F$bA0$H$Oe(B
e$B4X78$J$$$H$$$&$"$?$j$G$9$+$M$(!#e(B

e$B$3$l$O$^$D$b$H$5$s$N0u>]$HF1$8$G$9$M!#O"B3$7$?CM$7$+$^$H$^$ie(B
e$B$J$$$H$$$&5$J,$r$+$b$7$@$9L>A0$,$“$C$?$iDs0F$7$F$$$?$@$1$k$He(B
e$B$”$j$,$?$$$G$9!#e(B

e$B!!:G=i$NNc$H$$$&$N$,e(B

arg = lambda {|l| /\A=~ l ? true : nil }
e$B$GFI$a$J$+$C$?$N$G$9$,!"e(B l == “\n” e$B$G$7$?$+!#e(B

e$B$“$!!”$9$$$^$;$s!#$=$3$Oe(B /\A\s/ =~ l e$B$G$9!#e(B

e$B%Q%i%0%i%U$NNc$O:G=i$N%a!<%ke(B [ruby-dev:38392] e$B$N$b$&$A$g$C$He(B
e$B2<$K=P$F$-$^$9!#e(B

e$B$3$l$Oe(B

    prev, s.status = s.status, (e == "\n")
    b.flush if prev != b.status
    b << e

e$B$/$i$$$G0-$/$O$J$$$H;W$$$^$9!#e(Bb.status != nil e$B$N$H$3$m$O!">e5-$Ne(B
e$B!V6u$J$ie(B flush e$B$7$J$$!W$G<jEv$F$9$k$H$7$F!#e(B

e$B$=$l$G$be(B gather_each e$B$N$[$&$,$:$C$HC;$$$G$9$h$M!#e(B

e$B!!$d$j$9$.$+$b$7$l$^$;$s$,!"e(B status/status= e$B$rDs6!$9$k$N$J$i!“e(B
prev_status e$B$de(B status_changed? e$B$bMQ0U$9$k$H$$$&<j$O$”$j$^$9!#e(B

e$B;d$H$7$F$O!">uBVJQ2=$r%f!<%6$,0U<1$9$kI,MW$O$J$$MQES$O=<J,$Ke(B
e$BB?$$$H9M$($F$$$^$9!#e(B

e$B>uBVJQ2=$r$=$&$d$C$F%5%]!<%H$9$k$N$O!“>uBVJQ2=$r%f!<%6$,0U<1e(B
e$B$9$kI,MW$,$”$kMQES$K$OM-MQ$G$7$g$&!#$7$+$7!"$^$:$=$&$$$&MQESe(B
e$B$,=<J,$KB?$$$N$+$H$$$&E@$K$D$$$F5DO@$,I,MW$G$O$J$$$G$7$g$&$+!#e(B

e$B!!6h@Z$k$@$1$J$i3N$+$Ke(B1e$B9T$G:Q$_$^$9$,!"<B:]$K$O%5%s%W%k%3!<%IJU$+e(B
e$B$I$&$+$rH=Dj$7$?$j!"A08e$N6u9T$r=|$$$?$j$H:G=*7k2L$^$G$NF;$N$j$Oe(B
e$BD9$$$N$G2?$H$b8@$($^$;$s!#MW$i$J$$ItJ,$^$G=8$a$Fe(B(gather)e$B$$$^$9$,!“e(B
e$BK\Ev$O$b$C$HJ#;($J=hM}$,I,MW$J$N$Ge(B buffer e$B$N$h$&$J$b$N$,$”$l$P!"e(B
e$B<h<N$d2C9)$K$D$$$F$b0z$-<u$1$k$3$H$,$G$-$k$H;W$$$^$7$?!#e(B

e$B8e$G$d$l$P$$$$$s$8$c$J$$$G$7$g$&$+!#e(Bgather e$B$O$^$H$a$k$@$1$Ge(B
e$B>pJs$r<N$F$^$;$s$7!#e(B

e$B!!>e5-$NDL$j!"<B:]$K9M$($k$Y$-$3$H$,8e$m$K;D$k$H;W$&$N$G!“e(B gather
e$BC1BN$NDs6!$9$k5!G=$,CfESH>C<$K;W$($?$N$G$9!#$9$J$o$A!”%$%s%G%s%He(B
e$B%l%Y%kEy!“J,N$N4p=$H$7$F7W;;$7$?CMe(B(e$B%V%m%C%/$NI>2ACMe(B)e$B$r<N$F$Fe(B
e$B$7$^$C$F$$$^$9$,!”$3$NNc$G$b!"8eCJ$G$^$?I,MW$K$J$j$=$&$G$9$h$M!#e(B

e$B%$%s%G%s%H$N?<$5$O!"$`$7$m8e$+$i7W;;$9$k$[$&$,$$$$$s$8$c$J$$e(B
e$B$G$7$g$&$+!#%$%s%G%s%H$5$l$?%V%m%C%/$G$O!“J#?t$N9T$N$&$A!”$b$Ce(B
e$B$H$b@u$$%$%s%G%s%H$,M_$7$=$&$G$9$h$M!#e(B

e$B$b$7!“$I$&$7$F$bJ,N`$NCM$,I,MW$@$H$$$&$3$H$G$”$l$P!“e(Byield e$B$9e(B
e$B$kG[Ns$K%$%s%9%?%s%9JQ?t$H$7$F$D$1$F$*$/e(B (e$BI,MW$J$i$=$l$r;2>He(B
e$B$9$k%”%/%;%5$be(B) e$B$N$K$O$d$V$5$+$G$O$"$j$^$;$s!#e(B

e$B$H$$$&$3$H$G$"$l$P!“e(B buffer e$B$r;H$C$Fe(B gather e$BEy$r<BAu$9$k$N$OMF0We(B
e$B$J$N$G!“J#?t$N%a%=%C%I$rMQ0U$9$k$N$J$i!”<BAu$r6&M-$9$k$?$a$K$be(B
buffer e$B$N$h$&$JHFMQ$N$b$N$r;}$D%a%j%C%H$,$”$k$H$$$&$3$H$K$J$k$Ne(B
e$B$G$O$J$$$G$7$g$&$+!#e(B

e$B<BAu$7$F$_$^$7$?$,!"$=$&$$$&$b$N$,$J$/$F$b$=$l$[$ILLE]$G$O$"e(B
e$B$j$^$;$s$G$7$?!#e(B

e$BHFMQ$N$b$N$rMQ0U$9$k$N$O!"HFMQ$N$b$N$,I,MW$JNc$,=P$F$-$F$+$ie(B
e$B$G$$$$$s$8$c$J$$$G$7$g$&$+!#e(B

e$B!!e(Bbuffer e$B$Oe(B1e$B2s$N%$%F%l!<%7%g%s$GJ#?t$NCM$re(B push e$B$7$?$jJ#?t2se(B
flush e$B$7$?$je(B(e$B$“$k$$$O$7$J$+$C$?$je(B)e$B$G$-!”$^$?%$%F%l!<%?0z?t$Ge(B
e$B$J$/G$0U$NCM$re(B push e$B$G$-$k$N$G!"e(B lexer e$B$J$I$r<BAu$G$-$^$9!#e(B

e$B!!$H$$$&$+!“e(B scanf.rb e$B$r%Q!<%9$9$kNc$r8+$F!”<B:]$N1dD9>e$K$Oe(B
lexer e$B$N$h$&$J$b$N$,$"$k$s$8$c$J$$$+$H?dB,$7$^$7$?!#e(B

e$BJ#;($J$3$H$,$G$-$k$+$i$$$m$s$JMQES$,$“$k$K0c$$$J$$!”$H$$$&OCe(B
e$B$G$O$J$/!“6qBNE*$JNc$O$”$j$^$;$s$+e(B?