結論
Vim
で開いているrspec
ファイルのカーソル位置にあるテストを、自分の開発環境のdocker compose
上のrspec
で、気軽に実行出来る様にしました。
- 結果はvim-dispatchを使って
quickfix
に表示。 - あとは温かみのある手作り。
-
rspec
に渡すパスは、docker-compose
のパスに合うように、rspec
の絶対パスから切り出して作成 - カーソル行を取得してテスト対象を指定
-
" docker-composeでのテスト用定義。環境が変わったら書き換える
function! RunLineSpec() abort
let absolute_path = expand("%:p")
let relation_path = absolute_path[stridx(absolute_path, "spec/"):]
let rspec_cmd = 'docker compose run {docker-composeのサービス名}
bundle exec rspec ' . relation_path . ':' . line(".")
execute 'Dispatch' rspec_cmd
endfunction
nmap <silent> <Leader>test :call RunLineSpec()<CR>
経緯
最近、なんでもVimでやりたい病にかかっています。
先日も発作的に「docker-composeで実行するrubyのRspecをVimから呼び出したい」と思い立ち、いろいろと検討をしてみました。
vim-rspec 導入
まずは vim-rspecがシンプルで便利そうだったから入れてみました。
とはいえ、元々素直な開発環境ではないので、何とか頑張って設定して動けばいいなぁという気持ちからのスタートです。
自分の開発環境は
- 編集は
WSL(ubuntu20.04)
上のコードを、WindowsTerminal
でVim
- 実行環境は
WSL
で立ち上げたdocker compose
のサービス上に、コードをマウントして実行
という形にしてあります。
なので、Vim
とRspec
は実行環境が別々になっていて、Vim
からbin/rspec
を呼んでも、テストは動いてはくれないのです。
幸い、vim-rspec
には`実行するコマンドを変更する設定が用意されていたので、まずはこれを、自分の環境に合うように指定しました。
let g:rspec_command = "docker compose run {サービス名} bundle exec rspec {spec}"
{spec}には、カレントディレクトリからbuffer
への相対パスが入る様です。
なのでVimを開く前にカレントディレクトリをプロジェクトルートに変更するという運用にする事にしました。
これによって、「docker compose run
の際のコンテナ上のカレントディレクトリ=Vimを開いた際のカレントディレクト」となるので、{rspec}
に入っているパスが、サービスのコンテナ上のカレントディレクトリからも見れる事になります。
これで、vim-rspec
を用いた、docker compose
経由の実行は可能になりました。
ついでにhttps://github.com/tpope/vim-dispatch
も使って、結果をquickfix
に表示するようにもしました。
let g:rspec_command = "Dispatch docker compose run {サービス名} bundle exec rspec {spec}"
それから、実際にテスト実行につかうのは、カーソル付近のテストの実行
だけなので、以下のマッピングも追加しました。
nmap <silent> <Leader>test call :RunNearestSpec()<CR>
これで、個別テストがしたい時は、そのテストにカーソルを合わせて<space>(<Leader>をスペースにしてるので)test
でそのテストだけが動くし、全体のテストがしたければ、gg<space>test
で全テストが動く様になります。
vim-rspec
の使用感としては、これで全く問題なく運用出来ていました。
カレントディレクトリの制約を取り除きたい
Vimを開いた後の使用感の問題は無くなったけれども、プロジェクトルートでVimを開かないとVim上からテストが出来ない
ストレスは残り、カレントディレクトリがどうであれ、ちゃんとテストを実行出来る様にならないかと考えはじめました。
buffer
の絶対パスから、アプリケーションルート基準の相対パスを作り、docker-compose
に送る事が出来れば実現出来そうです。
rspec
は、アプリケーションルートの直下のspec
ディレクトリに入っているので、ここで絶対パスを区切れば、spec/
からの相対パスが取れると考えました。
(アプリケーションルートより前にspec
ディレクトリがある様な場合の事はもう考えなくて良いかなと諦めました。)
function! RunLineSpec() abort
let absolute_path = expand("%:p")
let relation_path = absolute_path[stridx(absolute_path, "spec/"):]
let rspec_cmd = 'docker compose run {docker-composeのサービス名}
bundle exec rspec ' . relation_path
let g:rspec_command = "Dispatch docker compose run operator_web bundle exec rspec " . relation_path
call RunNearestSpec()
endfunction
nmap <silent> <Leader>test call :RunLineSpec()<CR>
これで、Vim
側のカレントディレクトリに関係無く、rspec
が実行出来る様になりました!
万事解決!
と思いきや、まだ課題がありまして。
この時点で、vim-rspec
が提供する{rspec}がどこにも入っていないコマンドが出来上がっていることになってます。
なので、実行時のカーソル位置を受け取る場所もなくなってしまい、RunNearestSpec()
を実行しているのに、対象テストだけでなく、ファイル内の全テストが実行されるようになってしまったのです。
これじゃあ気軽なテストとしては使い物にならないですね…。
仕方ない、カーソル行を渡す記述も追加して…と考え始めたんですけど、このあたりでふと気づきました。
「考えてみたらこれ、もうvim-rspec
の機能は一つも使ってないな…」
じゃあ素のvimscriptで良いのでは
というわけで冒頭の結論の記述になりました。
(この時、作成したパスの変数をDispatch
とつなげて展開させる方法がわからず、Slack
のvim-jp
ではじめて質問を投げてみたんですけど、一瞬で返答を貰えて、大変ありがたかったです。
Vim
界は強いし、vim-jp
も強かった。
元々rspecは、全テスト実行か特定行の実行かしかしないんで、これで必要充分です。
vim
の勉強にもなったし、良い経験でした。
今後もvimを使い続けるのであれば、人様のプラグインを参考にしながら、自分でカスタマイズしたscriptを書いた方が、幸せになれるという事も多そうですね。