Emacs LispをTravis CIしてみる勉強ノート

何の因果か最近Emacs Lispを書くことになりました。

Emacsみたいなこわいエディタの話をしているのは必然的にこわいひとが多いです。
ドラクエで例えるとキラーマシンみたいな方ばっかです。
そんな中、ひのきのぼう/たびびとのふく/Lv1 でぷるぷるしながら調べたこと試したことをまとめて公開します。

新たな勇者のぼうけんの、最初の一歩を手伝えれば幸いです。

#注意
Emacs Lispは初心者、それ以外は今回はじめて触ったという体たらくで書いた記事です。

というか、主にこのページの劣化焼き直しです。
[Emacs Lispのテスト、依存性管理、CI - 備忘録][元記事様]
この記事を読む方は先にこちらのページをひと通り読みましょう。不自由なく理解できた方は以下を読む必要はありません。

#ERTとは
>ERT is an **E**macs Lisp library for **r**egression/unit **t**esting.
[EmacsWiki: Ert Test Library](http://www.emacswiki.org/emacs/ErtTestLibrary "EmacsWiki: Ert Test Library")

Emacs24には標準で入ってます。
[ELE](http://www.emacswiki.org/emacs/EmacsLispExpectations "EmacsWiki: Emacs Lisp Expectations")や[rejeep/ert-runner.el](https://github.com/rejeep/ert-runner.el "rejeep/ert-runner.el")のような便利糖衣もあって、この記事でやってる程度のことは全部できるっぽいですが試してません。

##つかいかた
適当なelファイル（例えばhoge-test.el）にテストコードを書いて、emacsから`M-x ert`で対話的に実行できます。

複数のテストを一括でやったりCIで自動実行したりするためには、emacsのバッチモードが使えます。
`$ emacs -Q -batch -l hoge-test.el -f ert-run-tests-batch-and-exit`
参考：[Initial Options - GNU Emacs Manual](http://www.gnu.org/software/emacs/manual/html_node/emacs/Initial-Options.html "Initial Options - GNU Emacs Manual") (emacs自体のオプション)
[Action Arguments - GNU Emacs Manual][-batchのオプション] (-batchのオプション)

##かきかた
###いあいあ えると
```el:hoge-test.el
(require 'ert)
(require 'hoge)
(eval-when-compile
  (require 'cl))
```
のようにertとテストしたいファイルをrequireします。
マクロは単にrequireしただけだとバイトコンパイル時にうまく置換されないようなので(eval-when-compile)で囲います。
参考：[12.3 マクロとバイトコンパイル](http://www.bookshelf.jp/texi/elisp-manual-20-2.5-jp/elisp_13.html#SEC174 "12.3 マクロとバイトコンパイル")

具体的なテストは`ert-deftest`を使って書きますが、`defun`スペシャルフォームとほぼ同じ書き方です。
###おまたせしました すごいやつ

```el:hoge-test.el
(ert-deftest hoge-test ()
  "Test of `hoge'."
  (should (equal EXPECTED
                 ACTUAL)))
```
*`should`マクロだよ。`ACTUAL`部に実際の処理を、`EXPECTED`部に予期される返り値を書くことで値を比較してエラーを吐いたりしてくれるすごいやつだよ。*

最低限これだけ覚えておけばテストが書けますやったね。
`should`に備わった ~~108式まである~~ 便利機能の詳細は以下のページを参照。
[How to Write Tests - Emacs Lisp Regression Testing](http://www.gnu.org/software/emacs/manual/html_node/ert/How-to-Write-Tests.html#How-to-Write-Tests "How to Write Tests - Emacs Lisp Regression Testing")

###お前もERTか？ERTなら俺が相手だ
```el:hoge.el
(ert-run-tests-batch-and-exit)
```
この式を評価すれば先述したバッチ処理がemacs内から呼べます。
具体的にはロードされてるelファイルの`ert-deftest`で定義されたテストをぜんぶ実行します。
複数のテストに共通する初期設定などを1ファイルで行い、そのあと各テストを呼ぶようなときに使えそうです。

#Cask
##Caskとは
Emacs用の非公式パッケージマネージャです。普段使いされてる方も多いようです。
今回は依存ライブラリをすごい勢いで解決してくれます。
インストールは[公式](https://github.com/cask/cask "cask/cask")にある通り、
`$ curl -fsSkL https://raw.github.com/cask/cask/master/go | python`でOK。
以下パスも通した体で行きます。

##つかいかた
`$ cask`か`$ cask install` で、カレントディレクトリのCaskファイルに応じて依存関係を解決してくれます。
その後 `$ cask exec emacs -Q -batch -L . -l hoge-test.el -f ert-run-tests-batch-and-exit` のようにバッチ処理。
先のバッチ処理に`-L .`なるオプションが加わりましたが、`.(カレントディレクトリ)`をロードパスに加える指示です。
詳細は[このへん][-batchのオプション]参照。

あとcaskは、環境変数`$EMACS`に応じてEmacsのバージョンを変えてくれます。
あとで`.travis.yml`でこの機能使うので頭の片隅に。

##かきかた
ワーキングディレクトリにCaskファイルを作って以下を記述。

```el:Cask
(source gnu)
(source melpa)
(source marmalade)

(files "hoge.el")

(development
 (depends-on "ert")
 (depends-on "cl")
)
```
基本Emacs Lispです。
(Emacs24.3以降しか相手にしないならclもertも標準で入ってるのでわざわざ書かなくてもいい・・・？)
cask固有の指示方法の詳細は[Cask Domain Specific Language — Cask 0.7.2](http://cask.readthedocs.org/en/latest/guide/dsl.html "Cask Domain Specific Language — Cask 0.7.2")参照。

実用的にはfileをちまちま指定せず特定ディレクトリにまとめて`*.el`のように指示するか、[packageにする](http://www.gnu.org/software/emacs/manual/html_node/elisp/Packaging.html#Packaging "Packaging - GNU Emacs Lisp Reference Manual")んでしょうか。
そのへんさっぱりわかりません。今後の課題（逃げ口上）。

#Travis CI
##Travis CIとは
Githubと連携した継続的インテグレーション(CI)サービスです。フリーミアム。
githubにpushするだけでweb-hookを受け取ってテストを走らせて結果を通知してくれます。

2015年1月現在、対応言語は驚きの20種類。

    C C++ Clojure C# D Erlang F# Go Groovy Haskell
    Java JavaScript (with Node.js) Julia Objective-C 
    Perl PHP Python Ruby Rust Scala Visual Basic

はい、Lispはありませんね。
でもテスト自体はERTに任せられるので、ERTをmakeから叩けば万事OKのようです。

ターミナルからいろいろしたい人のためにgemも用意されています。
`gem install travis`して`travis login --auto`するだけの簡単作業で256倍便利に。
Webのアカウント登録もgithubのログイン情報使って勝手にやってくれたしこっちでも勝手にやってくれるし便利~~すぎて薄気味悪い~~。

##とらびす だーくねす
```yaml:.travis.yml
language: emacs-lisp
env:
  - EMACS=emacs23
  - EMACS=emacs24
  - EMACS=emacs-snapshot
matrix:
  allow_failures:
    - env: EMACS=emacs-snapshot
before_install:
  # Install Emacs
  - sudo add-apt-repository -y ppa:cassou/emacs
  - sudo add-apt-repository -y ppa:ubuntu-elisp
  - sudo apt-get update -qq
  - sudo apt-get install -qq $EMACS
  # Install Cask
  - curl -fsSkL --max-time 10 --retry 10 --retry-delay 10
        https://raw.github.com/cask/cask/master/go | python
  - export PATH="$HOME/.cask/bin:$PATH"
  - cask
script:
  make
```
今までに解説したコマンドが総動員ですね。
`env:`で指定した環境変数ごとに1回ずつ一連のコマンドを実行する、ということが分かればぜんぶ読めます。

最新のemacsを拾ってくるにあたり、Travis CI側の環境がUbuntu 12.04LTSなのでppa形式でリポジトリを追加しています。
元記事様では`ppa:cassou/emacs`を採用していたようですが去年1月6日に[更新を停止された](https://launchpad.net/~cassou/+archive/ubuntu/emacs "[DEPRECATED] Old Emacs versions : Damien Cassou")ためこちらに切り替え。

では次肝心のmake。

##むーんぷりずむぱわーめいくふぁいる
```mf:Makefile
EMACS ?= emacs
CASK ?= cask

all:
        ${MAKE} clean
        ${MAKE} test
        ${MAKE} compile
        ${MAKE} test
        ${MAKE} clean

compile:
        ${CASK} exec ${EMACS} -Q -batch -L . -eval "(batch-byte-compile)" hoge.el
test:
        ${CASK} exec ${EMACS} -Q -batch -L . -l hoge-test.el -f ert-run-tests-batch-and-exit
clean:
        rm -f hoge.elc

.PHONY: all compile test clean
```
Makefileのお約束としてインデントはTAB文字じゃないと動きません。コピペ実行あぼん注意。
[元記事様]ではバイトコンパイル時に1つでもwarningが出たらmake失敗にしていたようですが、こちらはwarningのまま放置する感じです。

##でびる めいく らい
makeファイルを書いたらひとまずローカルで`make`すればテストが走ります。
エラーを全部直して一安心、いざ`git push`したらTravis側ではErrorとWarningが洪水だったりする。

頑張れ。

#まとめ
ここまでひと通りやったらあとはgithubにpushすればいいです。
初回push後Travis側の処理が終わったら通知が来ます。
その後はMakeがエラー吐けば通知が来ます。
治せれば通知が来ます。
治ってから次にエラーが発生するまでは静かに暮らせます。「植物の心」のような人生を送るためにもローカルでmake回しまくりましょう。

* pushするまでもなく、ローカルの段階でmakeが通らなければ`git commit`出来ないような仕組みがあると便利そうですね。
 * [gitの`pre-commit hook`機能](http://git-scm.com/book/ja/v1/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%83%95%E3%83%83%E3%82%AF "Git - Git フック")で実現できそう。

通知形式はデフォルトではgithub登録アドレスへのメールですが、[Web-hookを吐く](http://docs.travis-ci.com/user/notifications/ "Travis CI: Configuring Build Notifications")のでなんでもできそうです。

[元記事様]:http://www.kaichan.info/blog/2014-02-23-emacs-cask.html
[-batchのオプション]:http://www.gnu.org/software/emacs/manual/html_node/emacs/Action-Arguments.html#Action-Arguments "Action Arguments - GNU Emacs Manual"