Emacsからrakeを呼び出してみた

最近「プログラミングしてないなぁ……」とか思っちゃったので, 試しにTwitterのUser Streamsを使ったプログラムを書こうとしたのですが, ErlangからUser Streamsが使えなかったので*1別のプログラムに逃避した次第です, こんにちは. id:siritoriごめん.

で, 何作ろうかと考えてたら, 「そういえばEmacsからrake呼び出したいなぁ. あるのかなぁ. ありそうだよねぇ」とふと思い立った. 調べると, testタスクを実行するのはあっても, その他タスクを実行するのがなかったので, ちょっとだけ作ってみた.

(defvar rake:output-buffer "*rake output*")

(defun rake:invoke ()
  (interactive)
  (let ((task-suggestions (rake:task-suggestions)))
    (if task-suggestions
      (rake:run (completing-read "rake " task-suggestions))
      (message "Not found target"))))

(defmacro rake:deftask (task)
  (list 'defun (prog1 (intern (concat "rake:run-" task))) '()
        '(interactive)
        (list 'rake:run task)))

(defmacro rake:task (task)
  (list 'lambda '()
        '(interactive)
        (list 'rake:run task)))

(defun rake:task-suggestions ()
  (reverse (reduce #'(lambda (suggestions line)
                       (if (string-match "rake \\([^ ]+\\)" line)
                           (cons (match-string 1 line) suggestions)
                         suggestions))
                   (split-string (shell-command-to-string "rake -T") "[\r\n]+")
                   :initial-value nil)))

(defun rake:run (task)
  (call-process-shell-command (format "rake %s" task) nil rake:output-buffer))

使い方は.emacsとかに:

(require 'rake)

(global-set-key "\C-cr" 'rake:invoke)

(global-set-key "\C-cRd" (rake:task "default")) ;; C-c R dでdefaultタスクを実行する

(rake:deftask "test") ;; testタスクを実行する関数rake:run-testを定義し,
(global-set-key "\C-cRt" 'rake:run-test) ;; C-c R tでrake:run-testを呼び出す

な感じで. 一応タスク名を補完するようにしてあるけども, それをちょっとがんばったくらいで他がガタガタ. 後々ちゃんとさせる.

Lispは不慣れなので, 「この書き方よりもこっちの方がいいよ」とかあったら突っ込んでいただけると嬉しいです.

自分用メモ

  • タスク名の一覧をキャッシュさせる(rake -Tの呼び出しに微妙に時間がかかるため). Rakefile(*.rake)のパスと更新時刻, タスク名一覧を持っておけばよさげ
  • となると, Rakefile(*.rake)の探索をrakeと合わせておかなければならない
  • *rake output*バッファにどんどん書き込まれるので, rake:runするたびにクリア
  • キーバインドの設定を簡潔に記述できるようにする
  • 直前に実行したタスクを記憶しておく. コレはRakefile(*.rake)ごとに記憶した方がいい気がする

あとなんかあるかなぁ……

*1:「使えたよ」という方がいたら教えていただけると嬉しいです