#open-with-input-files-or-standard-input とかいう名前にするとか。
#あるいは、open-with-input-files のなかでは () は特別扱いせず、(open-with-input-ports (and (null? (cdr files)) (list current-input-port))) みたいにすると混乱が少ないかも?
#その後者のやつをもうちょっと短く書けたら採用なのになあと言う感じです。CLだと「引数はファイルまたはポート、もしくはそれらのリストでもいいよ」みたいないい加減さがあって、nilの性質とも相まって (or (cdr files) *standard-input*) でいけるんですよね。この位短いと、毎回書いても負担でないし、何やってるかはっきりわかるのでむしろ好ましい。
#or でつなげると意味が分かりやすいんですよね。あ、(or (pair? (cdr files))) ... でもいいのか。
#(define (open-with-input-files files proc)
(cond
[ (input-port? files) (proc files ) ]
[ (list? files)
(for-each
(lambda (f)
(call-with-input-file f proc))
files) ]
[else (error "error")]
))
(define (main args)
(if (null? (cdr args))
(usage)
(let ((rx (string->regexp (cadr args))))
(open-with-input-files
(match (cddr args)
[() (current-input-port)] [x x] )
(cut grep rx <>))))
0)
#matchをつかってみました。
#文字列ならglobとみなしてしまうとダイヤモンド演算子っぽくなりそうですね。
#ふむ。コマンドラインツール用ユーティリティと割り切るならglob展開も「()ならstdin」もアリだと思う。
#もしくは、文字列ならファイル名ということにすれば、open-with-input-fileを拡張してポートとリストを受け入れるようにしたという解釈もできないことはない・・・・?
#このあたりは文化の問題になりますか。
#(define (call-with-input-files files proc)
(cond
[ (input-port? files) (proc files ) ]
[ (string? files) (call-with-input-file files proc) ]
[ (list? files)
(for-each
(lambda (f)
(call-with-input-file f proc))
files) ]
[else (error "error")]
))
(define (main args)
(if (null? (cdr args))
(usage)
(let ((rx (string->regexp (cadr args))))
(call-with-input-files
(match (cddr args)
[() (current-input-port)] [x x] )
(cut grep rx <>))))
0)
#名前を間違えていました。(汗
#コマンドラインツールを簡単に作るのが目的なら、いっそのこと、ここまで簡略化したらどうでしょう。
#(define-command-line-tool tool-name
[(var option-spec description ...)
...]
;; ツール本体の処理
)
#よくあるオプション(-h / --helpとか)は決め打ちにしてしまえば、usageは自動生成できるはず。
#それも一理あります。ただ、色々暗黙のルールを組み込んだ特定用途マクロって、錆びつくのが速いというか、しばらく使わない→使い方忘れる→マニュアルをひっくり返してルールを頭にロードするのが億劫→ますます使わなくなる、っていうパターンに落ちそうなのがちと怖い。
#たしかにそうですね。でも、ダイヤモンド演算子のような引数の扱い方って、コマンドライン以外では使いにくいので、思い切って特化しちゃったほうがいいんじゃないかなと思いました。
#個人的にはダイヤモンド演算子が持つ「コマンドライン引数にファイル名が指定されていたら、そこから読む/なければ標準入力」という機能が便利さが、いまいちピンと来ないのですが。
#標準入力から読むように作っておいて、必要ならコマンドラインで "cat file1 file2 | gosh cmd.scm" で渡せばいいと思ってしまうので。
#よく使い込むなら、ちゃんと作りこみますし。
#まあ自分で使うだけならそれでもいいけれど、周辺のツールと使いでを合わせたのをちゃちゃっと作りたいとかいう時もあるんですよね。
#ポートについての処理だけすげ替えて使いまわすということをやってしまうので、書き換えるポイントが少ないほうがいいなあと思ったのでした。
#マニュアルのcat,grepだと書き換えるポイントが複数ある。そこで変更するホットスポットを絞り込む、といった狙いでした。
#そのためには、ファイル名のリストとポートの処理を統合した手続きがあると都合がいいということです。
#それはわかります。Gaucheとしてサポートするとしたら特定化と一般化のバランス点を決めないとならなくて、私の感触では「catやgrep的なものを簡単に書ける」のに特化するのはちょっと特定化の方に触れすぎてるなって感じがしてるだけで。
#なるほど。
#でもコマンドラインツールをばりばり書いている人にとっては、それでも十分に汎用的と言えるかもしれず、そのへん色々意見を聞きながら見極めたいところです。
#ファイル名のリストから仮想的なポートを生成する、という方向での一般化が筋なのかもしれないですね。あたかも一つのファイルを読んでいるように見えて、じつは数珠つなぎになっているというようなポート。
#そういうポートができたとすれば、また違った表現になってくるのかなあと思いました。
#port-concatenateの方向ですね。これは有用だと思います。今読んでる入力元をメタデータで取れるようになってばなおよし。
#すみません、ちゃんと議論を追っていないんですが、複数のファイル名があったときにそれを1つのポートにまとめられると、どんなときにうれしいんでしょうか?
#(for-each (cut call-with-input-file <> proc) file-list)
#こんなんだと困るケースがある?
#「ファイルを次々読むor標準入力から読む」という動作と、「一連の入力に対して何かする」という動作を別個に書いて組み合わせやすい、という方向の良さなんじゃないかな、という感触。
#「一連の入力に対して何かする」というのは、内部状態を変更しつつ、処理を行うというイメージでしょうか?
#「catやgrepのような処理」って感じですね。今の文脈では。
#catやgrepなら、先のfor-eachでいいような気がする。
#再帰的にディレクトリを巡回しつつ「連結ポート」をつむいでいくようなこともできるのだろうか?とか思いました。
#ああ、catだと行番号表示があったか
#「catやgrepのようなコマンド」をあと10個書かないとならないとすれば、(if (null? arglist) (proc (current-input-port)) (for-each ...))) の繰り返しパターンを抽象化したくなりませんか? 「あと10個書く」が一般的かどうかってとこに議論がありますが。
#うーん、それを言ってしまうと先の define-command-line-tool まで抽象化したほうがいいんじゃないでしょうか。
#ファイル名のジェネレータから連結ポートをつくるということになるかな?とか。
#そのユースケースってコマンドラインツールを作る以外の箇所でよく出てきたりするんでしょうか?
#それをここずーっと話してるわけですよ。私としては、コマンドラインツールはそこまでたくさん書くものじゃないから、何かつくるとしたらもう少し一般的なパターンとして取り出したい。とすればどういうパターンがあり得るか。これかなあれかな、ってぐるぐるやってるのです。
#連結ポートだとファイルごとに行番号を管理するようなやつがやりにくいか。とするとそれほど汎用的ではないかもしれない。
#ちょっとずれますけど、個人的には、ワンライナーが書きやすいとコマンドラインツールとして使いやすそう。$ つかえばいいのかな。
#個人的にはコマンドラインツールを作るときに一番面倒なのが、引数の処理で、あんまり port の方で面倒と思うことは少ないような気がする。
#perlの-n,-pのようなものがあればいいですね。(そこでダイヤモンド演算子が(略)
#perl -ape みたいな感じがやりたくて、むかし ape.scm っていうのつくりました(笑)。 http://torus.jp/memo/x200810/ape-scm.html #標準入力しかうけつけないけど。
#gosh自体に機能を増やすことはしないけど、そういう感じの「ワンライナー向け便利ライブラリ」はあってもいいかもね。
#ただそうなると、Perl や awk のBEGIN ブロックに相当する物が欲しくなったりするので、ちょっと見方を変えた方がいいと思うんですよね。