Island Life

< ベルガマスク組曲 | Mergers >

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

Name: