Gemfileの有無で変わる読み込まれる.rubocop.yml、そして優先順位について

最初に

予期せぬ~/.rubocop.ymlが読み込まれいてトラブっているのを見たので、
.rubocop.ymlがどういう順序で読み込まれたりするのかについて調査した。

説明するのが難しいけれど、書いて公開しておかないとせっかく調査したのに忘れてしまいそうなので、書いてみる。

複数の.rubocop.yml設定ファイルを読み込むRuboCop

ここで前提として、rubocopコマンドのコマンド引数で、親ディレクトリなどの祖先は指定しない。
これは、簡単のためというのもあるが、そもそもRuboCop自体想定されてないと考えられるためだ。 rubocop ..みたいな形で親を指定して実行するとエラーが起きたので、そう考えられる。

ルールによっては、優先順位などが変わることもあるようだけど、基本的には以下のような感じ。

  • Rubyファイルから見ると、同じ位置か上位にある.rubocop.ymlのルール適用される。
  • 複数の.rubocop.ymlが見られる場合に、同じCopルールがあれば下にある.rubocop.ymlの方が優先順位が高い。

プロジェクトルートディレクトリというのは、Gemfileかgems.rbという名前のファイルがあるディレクトリ。
(GemfileはBundlerでよく使うけど、gems.rbは知らない)

コマンド実行位置が、ホームディレクトリでもプロジェクトルートディレクトリでもない場合は、
コマンド実行位置の.rubocop.ymlに加えて、 上位にあるプロジェクトルートディレクトリかホームディレクトリの.rubocop.ymlもあれば見られる。

ホームディレクトリのrubocop.ymlでrubocop-railsを読み込むべきではない。

gem install rubocop-railsで、RuboCop本家で開発されているRails用のgemをインストールできる。

これで、(書くべきではないが実験のため)ホームディレクトリの.rubocop.ymlで、 rubocop-railsを適用させる。

AllCops:
  NewCops: enable
require:
  - rubocop-rails

RailsアプリにはアプリのルートディレクトリにGemfileがあるはずで、 Railsアプリのプロジェクトルートでない位置でrubocopコマンドを打つと、
コマンド実行位置の.rubocop.ymlに加えて、
RailsアプリのGemfileのあるプロジェクトルートにある.rubocop.ymlが読み込まれる。

しかし、Gemfileのない普通のRubyコードに対してrubocopコマンドを打つと、
コマンド実行位置の.rubocop.ymlに加えて、
ホームディレクトリの.rubocop.ymlも読み込まれる。
だから、もしホームディレクトリの.rubocop.ymlRails用のルールがあれば、
RailsのコードじゃないのにRailsのルールを適用してきてしまうことになる。

だから、「ホームディレクトリに便利かも」みたいに思ってRails用のルールを適用させてしまうのはよくない。というより、誤っている。

Gemfileの有無で変わる.rubocop.ymlとは

上記の話を整理する。

ホームディレクトリに.rubocop.ymlがあり、あるディレクトリにGemfile.rubocop.ymlがあるとする。

このとき、あるディレクトリでコマンドを実行すると、Gemfileのあるディレクトリの.rubocop.ymlのみが見られる。
ここで、もしGemfileを削除すると、ホームディレクトリの.rubocop.ymlも見られる。

考え方的には、Gemfileがあるディレクトリなら何かのRubyアプリを作っているディレクトリで、そこに.rubocop.ymlがあるなら、 ホームディレクトリにある個人用の.rubocop.ymlは適用されるべきではない、という考え方をとっているのだと思う。

ドキュメントも読んで確かめてみる

Configuration :: RuboCop Docs

As an example, if RuboCop is invoked from inside /path/to/project/lib/utils, then RuboCop will use the config as specified inside the first of the following files:
-  /path/to/project/lib/utils/.rubocop.yml
-  /path/to/project/lib/.rubocop.yml
- /path/to/project/.rubocop.yml
- /.rubocop.yml
- ~/.rubocop.yml
- ~/.config/rubocop/config.yml
- RuboCop’s default configuration

公式ドキュメントに書いてある英語の細かいニュアンスなどがわかりにくいが、優先順位が書いてある。
よく見ると、ホームディレクトリよりルートディレクトリの方が優先順位が高かったりして、必ずしも子の方が優先されるというわけでもないらしい。
ただ、普通はPCのルートディレクトリに.rubocop.ymlを書いたりしないだろうし、気にすることではないだろう。

しかし、公式ドキュメントのどのあたりを読めば、コマンド実行位置の.rubocop.ymlだけでなく、ホームディレクトリかGemfileのあるプロジェクトルートディレクトリのどちらかの.rubocop.ymlが読み込まれるという話が書いてあるのかわからなかった。

最後に

読み込まれる.rubocop.ymlが1つだけなのか複数あるのかとか、どういう順番なのかとか、そういうのを一切知らずになんとなく使ってきていたので、読み込まれる順番がわかってよかった。