[#38392] Enumerable#gather_each — Tanaka Akira <akr@...>

ときに、複数行をまとめて扱いたいことがあります。

47 messages 2009/05/09
[#38394] Re: Enumerable#gather_each — ujihisa <ujihisa@...> 2009/05/09

ujihisaと申します。

[#38400] Re: Enumerable#gather_each — Yukihiro Matsumoto <matz@...> 2009/05/09

まつもと ゆきひろです

[#38399] Re: Enumerable#gather_each — "Akinori MUSHA" <knu@...> 2009/05/09

At Sat, 9 May 2009 15:30:20 +0900,

[#38405] Re: Enumerable#gather_each — Tanaka Akira <akr@...> 2009/05/10

In article <86r5yy2nrg.knu@iDaemons.org>,

[#38417] Re: Enumerable#gather_each — "Akinori MUSHA" <knu@...> 2009/05/10

At Sun, 10 May 2009 10:08:47 +0900,

[#38524] [Bug #1503] -Kuをつけた時、/[#{s}]/n と Regexp.new("[#{s}]",nil,"n") で実行結果が異なる — sinnichi eguchi <redmine@...>

Bug #1503: -Kuをつけた時、/[#{s}]/n と Regexp.new("[#{s}]",nil,"n") で実行結果が異なる

8 messages 2009/05/22

[ruby-dev:38422] Re: Enumerable#gather_each

From: Tanaka Akira <akr@...>
Date: 2009-05-10 13:08:55 UTC
List: ruby-dev #38422
In article <86my9l2tts.knu@iDaemons.org>,
  "Akinori MUSHA" <knu@iDaemons.org> writes:

>  しかし、 ChangeLog のような場合は gather_each も単純さを維持
> できず複数行になると思います。buffer は、そうした少しの違いには
> 少しの違いで対応できます。

下にある ChangeLog の例は、slice_before と gather を使って書
くと以下のような感じになるでしょうか。
(ここで使っている gather は、[ruby-dev:38418] の仕様で、nil
によりその要素を除去します。そこでは slice_before も実装して
あります)

open("ChangeLog") {|f|
  f.slice_before {|l|
    /\A\S/ =~ l
  }.each {|h|
    header = h.shift
    h.gather {|l|
      /\A\s*\z/ !~ l
    }.each {|entry_lines|
      next if /\A\s+\*/ !~ entry_lines[0]
      puts header, *entry_lines
      puts "----"
    }
  }    
}

gather や slice_before は入力の並びを変えられないので、この
ような処理はこうやって何段階かに分けてやることになりますね。

>  はい。私の方は gather_each がカバーできる範囲の広さについて
> 疑問を持っていますが、二択という話ではないと思っています。

そうですね。

>  情報を捨てないとすると、カバー範囲はとても狭くなると思います。
> たとえばコード片の摘出の例は実用的な処理として完結しないので、
> gather の有用な使用例としては弱いのではないでしょうか。

あぁ、捨てないことが出来る、と書くべきでした。
どの値を捨てる印にするかという話はありますが、捨てる機能は付
けようと思っています。

コード片については、コード片の syntax check をやるのであれば
他は捨てていいでしょうし、また、文書の中のコード片を (色とか)
マークアップするのであれば、他の部分は残しておいたほうがいい
でしょう。用途次第ですね。

>  たとえばですが、 RD や markdown のような文書を処理する場合を
> 考えていました。考えてみると gather の守備範囲外かもしれませんね。

RD の pre はインデントが先頭行の深さ以上のところですからねぇ。
buffer のように上から処理していったほうが自然かも。

もし、インデントを先頭行よりも浅くできるようなフォーマットで
あれば、あとからやったほうがいいでしょうね。

>> もし、どうしても分類の値が必要だということであれば、yield す
>> る配列にインスタンス変数としてつけておく (必要ならそれを参照
>> するアクセサも) のにはやぶさかではありません。
>
>  その場合のAPIはどうなるのでしょう。gather 本来の用途には邪魔な
> データがくっついてしまうので、別メソッドですかね。

ary.category とかでいいんじゃないでしょうか。配列にメソッド
があったからって邪魔にはなりませんよね。

enum.gather { ... }.each {|ary| p ary.category }

>  むしろ、田中さんの出された2問を具体例としたときの私なりの解が
> Buffer なんですよ。scanf.rbからのコード片の切り出しという最初の
> 例は、コード片でない部分も含めて pp するというのが最終目的では
> ないですよね。削除するという機能が欠けているので不要な部分まで
> 得られてわずらわしい。従って取捨選択の機能が必要ではないか、と
> 思いました。

gather のブロックのなにかの値に削除の機能を割り当てようと思
います。

[ruby-dev:38418] の実装だと、nil, false, :reject が削除になっ
てます。

>  次にパラグラフごとに切るという例は gather_each がもっとも短く
> 書ける例でした。しかしながら、ヘッダを区切りとする構造を扱う際は
> 短くなくなる。従って恣意的なタイミングで yield できる必要がある、
> あるいは状態の管理を支援するといいのではないか、と思いました。

ヘッダを区切りとする場合には別メソッドの slice_before がいい
んじゃないかと思います。

>  これらを合わせた考えたのが Bufferです。当たり前ですが複雑なこと
> 自体を目指しているのではなくて、 gather_each では不十分と感じ、
> 一部のケースを除けば最適な解とは思えなかったのが対案の動機です。

なるほど。

> Unix mbox の切り分け:

slice_before (slice_by) による実装は [ruby-dev:38407] に書き
ましたが、buf の扱いが不要なぶん slice_before のほうが簡潔で
すね。

> ChangeLog の各エントリの切り出し:

これは上に書きましたが、もっと短く書けます。

> 簡単な電卓:

なんで buffer を使うんですか?

>   STDIN.lines.buffer { |line, buf|
>     until line.empty?
>       line.sub!(/\A\s+/, '')
>       line.sub!(/\A(\d*\.?\d+)/) { buf << [:NUM, $1.to_f]; '' }
>       line.sub!(/\A([+\-*\/])/) { buf << [:OP, $1.intern]; '' }
>     end
>     buf.flush
>   }.tap { |expr|

これって、1行ずつトークンにわけて、それを処理するわけですよ
ね。

STDIN.each_line {|line|
  line をトークンにわけて tokens に入れる
  tokens を計算して表示
}

というのではいけないんですか?
-- 
[田中 哲][たなか あきら][Tanaka Akira]

In This Thread