Vim script で最高の assertion 体験,vital-power-assert を作りました
テスト書いてないとかお前それ Vim script の前でも同じこと言えんの?
ということで Vim script 版 power-assert, vital-power-assert を作りました.
Vim script でも power-assert できてテストをバリバリ書けるんだから Vim で書いてる他の言語でテスト書いてないとか Vim が泣いちゃいますね…(煽り,そしてブーメラン)
使い方とか 力こそパワー!! 百聞よりパワー!!
使っている様子です
1 2 3 4 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
上記コードを実行するとこうなります.
1 2 3 4 5 6 7 8 9 |
|
インストールや詳しい使い方は GitHub/help を参照してください.
-> haya14busa/vital-power-assert
基本的に関数とコマンドのassert方法を用意しているのですが,プラグインのコードに残しておいたりするものは
関数の .assert()
, Vimのテスティングフレームワークで使う際などはコマンドでやることを推奨してます.
1 2 3 4 |
|
両者ともデバッグ用変数をONにしないとassertは実行されないので,プラグインに埋め込んでおいても プラグインのユーザが使ってる時は発動しないし,評価なにもされないのでコードに残しておいても 問題ないようになっています.(コマンドの方はユーザのVimにコマンドが新たに定義されてしまうので推奨しません)
power-assert 最高! 一番好きな assertion ライブラリです!
vital-power-assert はもちろん JavaScript の assertion ライブラリである https://github.com/power-assert-js/power-assert にインスパイアされて作っています.
何がベンリなのかとかは @t_wadaさんが本家のpower-assertの紹介とかで 各所で説明なされているので説明は不要だとおもいますが,
個人的にはやはり
- assert 失敗時の式がどうなってるか一目瞭然のグラフィカルな見た目
- たくさんの matcher を一つ一つ憶えたりドキュメントを見なくても
assert
一つだけ知ってれば使える優しさ
あたりのよさが使ってみて,開発してみて本当によいなと思います.
マッチャーは自然言語的な書き方ができたり, テストのコード自体が間違えにくいみたいなところがよいとチラッと聞いたことがありますが 僕は断然power-assertのほうが好きという思いが強まりました (間違ってたり他にもある場合は教えてください)
Vim script 版 vital-power-assert のよさ
(このあたりは特に Vim script 書いてる人/興味あるひと向けです)
power-assert としてのよさはもちろんのところ, Vim script の assertion ライブラリとしての vital-power-assert のいいところがあります.
それはassertionを実行する際のスコープが assert する行と 同じなので, スクリプトローカル変数やローカル関数など何でもassert する 式の中で使えるということです!!! (わかりづらい)
1 2 3 4 5 6 7 8 9 |
|
例えば Vimのテスティングフレームワークの一つの thinca/vim-themis の assert コマンドではスクリプトローカル変数が使えなくて不便…ということがあったりするのですが vital-power-assert を使えばそのあたりを気にせず使うことができます.ベンリ.
どうやって実装しているか
Vim script のパース & コンパイル
power-assert のようにassert が失敗したときに式中のそれぞれの変数や関数, 演算子の評価結果を得るためにはまず与えられた式をパースする必要があります. そこでは Vim script で Vim script をパースできる ynkdir/vim-vimlparser を使用させていただいています. 使っていて改めて ynkdir さんすごすぎる…
vitalのライブラリとして使うためにhaya14busa/vital-vimlcompilerにバンドルしちゃっています.(ライセンス的に問題なさそうだったのでynkdirさんに相談するまえに衝動的にVim版power-assertを作ってしまいました…スイマセン)
とにかく,vimlparser のおかげでVim scriptをパースしてASTを得ることができたので, あとはASTをトラバースして評価したいノードを集めることができました.
そして再コンパイル
あとは集めたASTのノードの式中の位置を記録, そしてASTをVim scriptに戻してスコープに気を付けながら評価すれば必要なものが揃います.
vimlparser に付属している Compiler
オブジェクトはS式的なものにコンパイルするものだったので,
Vim scriptにコンパイルする haya14busa/vital-vimlcompiler
というライブラリを作って使用しています.
注意点としてまだexpr
のコンパイルしか実装してないので関数とかはコンパイルできないです.
ドキュメントもないし今のところ完全に vital-power-assert 用になっていますが,何かできたら面白そう.
Vim script スコープハック
Vim のコマンドの引数はString
として渡されてその場で評価しているわけではないので
普通にやるとスクリプトローカル変数が無いと怒られます.
もちろん文字列で受け取って eval()
してもスコープは変わってるので対応できません.
これを完全に解消するためにはassertする行と同じ位置で評価する必要がありますが,
そこで execute
を使うことによって実現しています.
どういうことかというと,{rhs}
である s:assert('...')
が評価され返り値が帰ってくるのですが,
その返り値に実行したいコマンドを文字列として返すと :execute
によってそのコマンドが同じスコープで
実行できて… という感じで実装しております.
1 2 3 4 5 6 7 8 9 10 11 |
|
コマンドも基本は同じでコマンドの{rhs}
がexecute
になってるのですが,
どうしてもスクリプトローカル変数だけはコマンドを定義したファイルの方で評価されてしまうので
ファイルごとにコマンドは定義する必要があるのはこれが理由です.
つまりスクリプトローカル変数諦めるなら一回定義すればあとは同じように使えますが そもそもコマンドは雑な開発用スクリプトとかテスティングフレームワークで使うことを想定しているので そんな感じで察してください.
グラフィカルな描画
ところで見た目とユーザの驚き的には power-assert のあのグラフィカルな表示を作るところが華と見ることもできそうですが, 今のところとりあえず線が被らない最低限のアルゴリズムで作っているのでもっと改善した表示ができると思います.
もしいい感じのグラフ描画のアルゴリズムわかる人は僕に教えてくださると大変ウレシイです
最後に
勢いでワーッと作っていてまだまだ改善点はあるのですが,一通り開発してテストしてる限りではめっちゃよい感じに動くので Vim script 書いてる方や興味あるかたは是非使って見ていただけると嬉しいです.
あと themis との連携を書いてますが,別に themis の作者である thinca さんに使い方とか確認をとったわけでもないので もしかしたらもうちょっと良く出来たりするかもしれません.
フィードバックとか使い方の質問とか github: https://github.com/haya14busa/vital-power-assert , twitter: https://twitter.com/haya14busa , Lingr: http://lingr.com/room/vim あたりにいただけると嬉しさあります.
Vim script でも power-assert して最高の assertion 書いていくゾ!!!