2012/01/29
Gaucheで書き捨てツールのtips
こちらでGaucheを取り上げていただいた。 こういうちょっとしたツールに使われるのは本望なので、 ちょっと書きツールに便利なtipsをいくつか。
- Perl風にdieというのを定義して、
(die (format "~a: invalid argument" opt)のように呼んでるけれど、実はexitに「メッセージをformatしてcurrent-error-portに出力してからexitする」という機能があるので、format+dieはexitひとつでいける。(exit 1 "~a: invalid argument" opt)
- コマンドライン引数の扱いは、オプションをlet-argsでパーズした後、残りの引数に
matchをかける、っていうのをよくやる。
(use gauche.parseopt) (use util.match) (define (main args) (let-args (cdr args) ([#f "h|help" => (cut usage 0)] . args) (match args [(file) ...処理...] [_ (usage 1)])))このパターンは頻出するので、let-argsを拡張してオプション以外の引数もbindできるように しちゃおうかなあ、と考えている。パーズできなかった場合のエラー処理をもうちょい 賢くしたいんだけど。 - あとはスタイルの好みだけど、
(or 条件チェック エラー),(and 条件チェック エラー)はそれぞれ(unless 条件チェック エラー)と(when 条件チェック エラー)と書ける。when/unlessは戻り値が無い(未定義な)ので、「ここの節は副作用がある(戻らないことがある)」っていう意図を示せる。and/orは逆に戻り値に意味があることを示す時に使う。 (もっともCommon Lispではwhen/unlessにも戻り値があり、それはそれで便利に使えるので、Schemeでも戻り値があるほうがいい、って議論もある。) - ファイルの存在チェックをどこでやるかはツールの目的によるけど、使い捨てスクリプトならファイル読めなければ
process-output->string-listがエラー出すんで、それを捕まえちゃってもいいかも。他のエラー (外部コマンドが見つけられないとか) の時も、スタックダンプを出すよりはメッセージ一行で終わらせちゃっていい、っていう用途であれば、処理全部をguardで囲んでエラーを一括して捕まえる、という手がある。 (もちろん、予想されるエラーだけ一行メッセージでexitして、 予想されないエラーはスタックトレース出したい、という用途であれば一括guardでない方がいい)。
そんなわけで、まあこんなふうにも書ける。
#!/usr/bin/gosh
(use gauche.process)
(use gauche.parseopt)
(use util.match)
(use file.util)
(define (usage status) (exit status "usage: ~a <file>\n" *program-name*))
(define (main args)
(let-args (cdr args) ([#f "h|help" (usage 0)] . args)
(match args
[(file)
(guard (e [(<error> e) (exit 1 "~a" (~ e'message))])
(let ([fl (process-output->string-list '(funclen) :input opt)]
[fn (process-output->string-list `(funcname ,opt))])
(unless (= (length fl) (length fn))
(error "funclen may have been failed"))
(for-each (^[x y] (print (regexp-replace #/\w*$/ x y))) fl fn)))]
[_ (usage 1)]))
0)
Tags: Programming, Gauche

Post a comment