ALEでrubocopが動かなかった

  • vim
  • raiis

3行

  • ALEはデフォルトでGemfile に記載されてるものじゃなくグローバルインストールされてる rubocop を使う
  • 両者のバージョンが違うとエラーになって rubocop は静かに異常終了してしまう
  • let g:ale_ruby_rubocop_executable = 'bundle' すると解決する

前提

  • Ubuntu20 (WSL2)
  • NeoVim v0.6.1
  • ALE
  • Ruby
  • rubocop

起きたこと

ALEにrubocopを設定した。こんな感じで。

" ale
let g:ale_fix_on_save = 1
let g:ale_sign_column_always = 1
let g:ale_disable_lsp = 1
let g:ale_linters = {
\ "...
\  'ruby': ['solargraph', 'rubocop'],
\ }
let g:ale_fixers = {
\   '*': ['remove_trailing_lines', 'trim_whitespace'],
\   " ...
\   'ruby': ['rubocop'],
\   }

let g:ale_ruby_rubocop_auto_correct_all = 1

しかし、コードに空行をあけてみても、まったく効かない。

この状態のコードをCLIから検査すると普通にエラーが検知される。

$ bundle exec rubocop ./app/controllers/hoge_controller.rb

Inspecting 1 file
C

Offenses:

app/controllers/api/v1/procedures/requests_collection_controller.rb:44:1: C: Layout/EmptyLines: Extra blank line detected.

1 file inspected, 1 offenses detected, 1 offenses auto-correctable

原因

:ALEInfo した結果

  Command History:
(executable check - success) rubocop
(finished - exit code 2) ['/usr/bin/zsh', '-c', '''rubocop'' --format json --force-exclusion  --stdin ''/home/zoshigayan/ghq/github.com/zoshigayan/koban/app/controllers/api/v1/procedures/requests_collection_controller.rb'' < ''/tmp/nvimrPD0GN/3/requests_collection_controller.rb''']
<<<NO OUTPUT RETURNED>>>

終了ステータスが 2 なので、なんかの事情で異常終了している。

ALEのコードを読んでいると、どうやら ruby_rubocop_executable という変数があって、そこに rubocop という値が初期値として設定されていることが分かった。 ale/rubocop.vim at 7d4ce4e6aa960a6052a16d90322566d6f4fddb7c · dense-analysis/ale

つまり bundle exec rubocop で呼ばれるプロジェクト内にローカルインストールされた rubocop ではなく、普通にグローバルで入っている rubocop が呼ばれているっぽい。

これだとまずそう。バージョンが違うので。

$ bundle exec rubocop -v
1.20

$ rubocop -v
1.33

試しに bundle exec つけない状態で検査をかけようとすると以下のようになった。

$ rubocop app/controllers/api/v1/hoge_controller.rb
`RuboCop::Cop::EnforceSuperclass` is deprecated and will be removed in RuboCop 2.0. Please upgrade to RuboCop Rails 2.9 or newer to continue.
`RuboCop::Cop::EnforceSuperclass` is deprecated and will be removed in RuboCop 2.0. Please upgrade to RuboCop Rails 2.9 or newer to continue.
`RuboCop::Cop::EnforceSuperclass` is deprecated and will be removed in RuboCop 2.0. Please upgrade to RuboCop Rails 2.9 or newer to continue.
`RuboCop::Cop::EnforceSuperclass` is deprecated and will be removed in RuboCop 2.0. Please upgrade to RuboCop Rails 2.9 or newer to continue.

(中略)

/home/zoshigayan/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/rubocop-1.33.0/exe/rubocop:19:in `<top (required)>'
/home/zoshigayan/.asdf/installs/ruby/2.7.5/bin/rubocop:23:in `load'
/home/zoshigayan/.asdf/installs/ruby/2.7.5/bin/rubocop:23:in `<main>'

$ echo $?
2 # ← 出、

グローバルに入ってるrubocopとプロジェクトに入ってるものとのバージョンが違っていることで大量のエラーを吐いている。終了ステータスが 2 であることからしても、ほぼこれが原因と思って問題なさそう。

よって、「ALEがプロジェクト内の rubocop を使って検査できるようになる方法」を見つければ解決するのではないか。

解決策

ちょっとググったらそれっぽいIssueが出てきた。 ALE not working with a locally installed Rubocop · Issue #1403 · dense-analysis/ale

「binstabを作れ」とか「executable として実行ファイルのパス以外を指定するのが思想的に許されるか」みたいな議論を華麗にスルーして解決策だけ拾い読みすると、 ale_ruby_rubocop_executable 変数に bundle を指定すればいいらしい。なんか bundle exec rubocop まで書いちゃうのはダメらしい。

ということで、そうしてみる。

@@ -155,7 +155,7 @@ let g:ale_fixers = {
 \   }
 
 let g:ale_ruby_rubocop_auto_correct_all = 1
-" let g:ale_ruby_rubocop_executable = 'bundle exec rubocop'
+let g:ale_ruby_rubocop_executable = 'bundle'

動いた!やった~

おまけ: なんで ale_ruby_rubocop_executablebundle exec rubocop を書いてはいけないのか

#tobe_調査

…?

Update all Ruby linters to work consistently with bundler by rrosenblum · Pull Request #1850 · dense-analysis/ale