RuboCopが対象のRubyバージョンを決める方法は、探索順位によるため期待どおりランタイムの Ruby のバージョンと一致している場合以外に、条件によってはそうでないこともある。
.rubocop.yml の TargetRubyVersion
の値、.ruby-version の値、Gemfile.lock に記された Ruby のバージョンを順番に参照して、それらに設定がない場合は RuboCop でデフォルトの Ruby バージョンとなっている 2.2 が適用される。実装としては以下。
これらの探索順で最初に見つかった値が RuboCop が静的解析の Ruby バージョンとなる。
リポジトリに .ruby-version を置いていないかつ rbenv などではなく Docker の Ruby イメージを使って、.rubocop.yml にも Gemfile.lock にも Ruby のバージョンの指定がない場合は、ランタイムの Ruby バージョンに関係なくデフォルトの Ruby 2.2 での静的解析が適用される。
どう困ることがあるかというと 、Ruby 2.3 以上のラインタイム環境で frozen_string_literal: true
のマジックコメントがあるソースコードの定数に対して .freeze
メソッドを付加するよう警告が意図せず出るようになる。Style/MutableConstant
cop としては、Ruby 2.3 以上でそのマジックコメントがある場合は、警告を出さないのが本来の動き。
# frozen_string_literal: true FOO = 'foo'
Offenses: test.rb:3:7: C: Style/MutableConstant: Freeze mutable objects assigned to constants. FOO = 'foo' ^^^^^
対策として、特定の Ruby バージョンで動けば良い Rails アプリケーションであれば .rubocop.yml の TargetRubyVersion
に Ruby バージョンを指定すると良い。
それっぽい現象のレポートがあった事例としては、以下のイシューがある。
特殊な例だと (Ruby 2.2 以上の) 複数の Ruby バージョンをサポートする必要のある拡張 .rubocop.yml を複数の Ruby バージョンを Docker の Ruby イメージベースで動作検証したい場合 (例えば CircleCI 2 でのビルド) は、対象とする .ruby-version をビルド工程中に生成する設定を入れるなど考えられる。
これは盲点になりかねないので、ランタイムの Ruby バージョンとは別に、静的解析を適用する Ruby バージョンを利用者が分かるすべについては少し検討しているところ。