RuboCopのv0.67で確認している話です。以前・以降のバージョンではもしかしたら違うかもしれないので注意してください。
document: https://docs.rubocop.org/en/latest/configuration/
TL;DR
inherit_from
に書く相対パス
inherit_from
が書かれた設定ファイルからの相対パス
Include/Exclude
に書く相対パス
- それが書かれた設定ファイルが
.rubocop
で始まるファイル名の場合- その設定ファイルからの相対パス
- 設定ファイル名が
.rubocop
で始まらない場合-
rubocop
コマンドを実行したディレクトリからの相対パス
-
答えとしては上記で終わりですが、これがどういうケースで問題になりやすいのか(ハマりはやすいのか)、というのも書いているので良かったら最後まで見てください
RuboCopでパスが書ける部分
inherit_from: .rubocop_todo.yml
Style/CollectionMethods:
Exclude:
- 'foo/bar.rb'
Include:
- 'hoge/huga.rb'
-
inherit_from
- 共通の設定ファイルなどを継承できる
-
Include/Exclude
- Copを実行する対象・実行しない対象を宣言できる
RuboCopでは上記の2つにパスを書くことができます。
どちらも絶対パス・相対パスどちらでもかけますが、通常は相対パスになると思います。
ここで書く、相対パスはどこから見た相対パスなのか?という記事です。
inherit_fromに書く相対パス
こちらはとてもシンプルです。
inherit_fromに書く相対パスは、inherit_fromが書いてある設定ファイルからの相対パスになります。
inherit_from: '../.rubocop_todo.yml'
例えば上記の場合、.rubocop.yml
の中で.rubocop_todo.yml
を読み込んでいますが、
これは、.rubocop.yml
からみて../
にある.rubocop_todo.yml
を読み込みます。
treeでいうと以下のような関係になります。(baseというディレクトリ名は適当です。)
.
├── .rubocop_todo.yml
└── base
└── .rubocop.yml
Include/Excludeに書く相対パス
こちらがややこしいです。
Include/Excludeの設定が書かれている設定ファイルの名前によって変わります!
- ファイル名が
.rubocop
で始まる設定ファイルの場合- その設定ファイルからの相対パス
- 例:
.rubocop.yml
や.rubocop_todo.yml
など
- それ以外の設定ファイルの場合
-
rubocop
コマンドを実行したディレクトリからの相対パス - 例:
.my_rubocop_config.yml
やrubocop.yml
(ドットなし)など
-
具体例
.
├── config
│ ├── .my_rubocop_config.yml
│ ├── .rubocop_todo.yml
│ └── .rubocop.yml
└── src
└── sample.rb
上記のようなディレクトリ構成があるとします。configディレクトリ以下に、3つのrubocopの設定ファイルがあります。
inherit_from:
- .my_rubocop_config.yml
- .rubocop_todo.yml
.rubocop.yml
の中でほか2つの設定ファイルを読み込みます。
$ rubocop -c config/.rubocop.yml
rubocopコマンドは、ルートディレクトリから実行するとします。
上記のような前提とします。
この状態で、3つの設定ファイルそれぞれで、src/sample.rb
をExcludeする設定を書きたいとします。
以下のようになります。
# config/.rubocop_todo.yml
Style/CollectionMethods:
Exclude:
- '../src/sample.rb' # .rubocopで始まるので、設定ファイルからの相対
Style/CollectionMethods:
Exclude:
- '../src/sample.rb' # .rubocopで始まるので、設定ファイルからの相対
Style/CollectionMethods:
Exclude:
- 'src/sample.rb' # .rubocopではないので、実行ディレクトリからの相対
# or
# - '**/sample.rb'
- ファイル名が
.rubocop
で始まる設定ファイルの場合
- その設定ファイルからの相対パス
- それ以外の設定ファイルの場合
rubocop
コマンドを実行したディレクトリからの相対パス
なので、
config/.rubocop.yml
とconfig/.rubocop_todo.yml
では、../src/sample.rb
というように../
でたどる必要があります。
config/.my_rubocop_config.yml
は、rubocopコマンドを実行したディレクトリからの相対パスなので、'src/sample.rb'
や**/sample.rb
とかけます。
なので、RuboCopの設定ファイルをtoolsやconfigディレクトリなどに置いて、rubocopコマンドはリポイ取りルートなどから実行するようなケースでは、
.rubocop
から始まらない設定ファイルにするのをおすすめします。
どういう時に問題になりやすいか
RuboCopがデフォルトで読み込むのは.rubocop.yml
なので、この名前で設定ファイルを書かれている方が多いかと思うのですが、
.rubocop.yml
がリポジトリルート(またはrubocopコマンドを実行するディレクトリ)においてあるのであれば、問題になりません。
ですが、設定ファイルをconfig
ディレクトリやtools/rubocop
等においてる場合に問題になりやすいです。
.
├── src
│ ├── admin_server
│ │ └── test
│ │ └── bar.rb
│ └── api_server
│ └── test
│ └── foo.rb
└── tool
└── rubocop
└── config
└── rubocopの設定ファイル
上記のような構成にし、rubocopコマンドをリポジトリルートなどで実行する場合は、
設定ファイルは.rubocop
で始めないほうが楽です。
Foo/BarCop:
Exclude:
- '**/test/**/*.rb'
testディレクトリではまるっと無視したいcopが時折あると思うのですが、その場合上記のように書けると楽です。
ですが、.rubocop
で始まる設定ファイルの場合、
../../../src/**/test/**/*.rb
というように適切に../
で階層を戻る必要が出てしまいます。
rubocop
で始まらない設定ファイルの場合は、
実行ディレクトリからの相対パスなので'**/test/**/*.rb'
と簡単にかけます。
.rubocop.ymlをルートに置かない理由
Inculude/Exclude
の相対パスがややこしい問題は、.rubocop.yml
をリポジトリルートに置けば解決なので通常はそれで全く問題ないと思っています。
ただ、さまざまな都合でtoolsやconfigディレクトリなどの下にRuboCopの設定ファイルを置きたいケースがあると思っています。
- 一つのリポジトリの中に複数のアプリがあり、RuboCopの設定は共通にしたい
- 上の方で例に上げたように、
api_server
,admin_server
のようケース - メインのアプリは一つだが、デプロイ・コード生成・バッチなどのような、メインアプリとは別の小さなアプリ・スクリプトでディレクトリを切っているケース
- 上の方で例に上げたように、
- rubocop gemをアプリのGemfileに入れたくない・入れにくい
- アプリの実行に必要なgemではない
- 上の方で例に上げたように、
api_server
,admin_server
のようにアプリが複数あってそれぞれのGemfileに入れるのは微妙感ある- かといって、RuboCopのためだけにリポジトリルートに別途Gemfileを用意するのも微妙
- rubocopをdockerで実行できるようにしておきたい
- Gemfileにrubocopを入れない場合、各ユーザーが
gem install rubocop
するのも微妙なのでdockerで起動できるようにしておきたい - => dockerfileや便利スクリプトの置き場が必要
- Gemfileにrubocopを入れない場合、各ユーザーが
- RuboCopに関するREADMEや設定のガイドラインを用意したい
- RuboCopの実行の仕方・エディタで動かす方法などを書きたい
- RuboCopの設定は揉めやすいのでガイドラインとしてドキュメント化しておきたい
- => 設定ファイル・ドキュメントを一つのディレクトリにまとめたい
さまざまな都合が存在するかなと思います。
チームや状況によってもちろん異なると思いますが、.rubocop.yml
をリポジトリルートに置かないケースはそれなりにあるのかなと思います。
まとめ
inherit_from
に書く相対パス
-
inherit_from
が書かれた設定ファイルからの相対パス
Include/Exclude
に書く相対パス
- それが書かれた設定ファイルが
.rubocop
で始まるファイル名の場合- その設定ファイルからの相対パス
- 設定ファイル名が
.rubocop
で始まらない場合-
rubocop
コマンドを実行したディレクトリからの相対パス
-
- 設定ファイルをリポジトリルートに置かない場合は、
.rubocop
で始まらない設定ファイル名のほうが楽
おまけ
https://speakerdeck.com/vividmuimui/anatafalsezhi-ranairubocopfalseshe-ding
今回の話は、社内LTでの内容をリライトしたものです。メイン部分は同じ話ですが、違う設定に関する話もちょっと書いてあるので、よかったら見てください