RuboCop RSpecからRuboCop CapybaraとRuboCop factory_botが切り出されたけど結局どうすればいいの?

こんにちは、 ydah です。最近はというと、料理への情熱が再燃してきました。一時期は作った料理を全て写真に残していたりとしていたのですが、いつの間にか記録を何も残さなくなっていました。何かしら記録を残すことで、前回よりも味も見た目も良くしようと思えるので、記録を残していくようにしたいと思います。やっていくぞ〜!!

トマトとタコのパスタの近影

はじめに

5/11-13 に長野県松本市 まつもと市民芸術館 で開催された RubyKaigi 2023 の Lightning Talks で、 RuboCop RSpec チーム*1RuboCop RSpec から、 RuboCop CapybaraRuboCop factory_bot を gem に切り出した話をしました。

rubykaigi.org

当日の発表スライドは以下です。

この記事では RuboCop RSpec を現在使っている方向けに、発表した内容をベースに補足も加えて説明します。 gem に切り出されたのは分かったけれど、結局どうすれば良いの?!という方に向けて記事を書いています。

gem に切り出すこととなった背景

RuboCop RSpec は前提として以下の通り、RSpec に特化した RuboCop の拡張機能を提供しています。

RSpec-specific analysis for your projects, as an extension to RuboCop.
RuboCop RSpec :: RuboCop Docs

RuboCop には部門という cop の種別によって束ねる概念があります。現状、RuboCop RSpec には次の 4 つの部門があります。

この 4 つを眺めていると Capybarafactory_bot については、RSpec に限らず、他のテストフレームワークでも利用することができるので RuboCop RSpec の一部門として管理するよりも、gem に切り出して汎用的に使える方がユーザーにとって価値があるのではないかと我々は考えました。

ただ現状でも他のテストフレームワークを使用している場合に、 FactoyBot 部門や、 Capybara 部門の cop のみを使用することは設定次第で可能ではあります。具体的には以下のような設定を .rubocop.yml に追加すれば可能です。

RSpec:
  Enabled: false
RSpec/FactoryBot:
  Enabled: true

しかし、 RSpec を使用していないプロジェクトで RuboCop RSpec を Gemfile に含めるだろうか...?ということもあり、 gem として切り出すのが良いだろうと考えています。

また、 factory_bot を使用していないプロジェクトで、 FactoryBot 部門の cop の誤検知による違反が上がるという Issue が上がっていました。 確かに RSpec しか使っていないケースで、 factory_bot や Capybara 向けの cop の誤検知出てしまうのは避けたいので、これも gem として切り出す要因の一つとなっています。

現在の状況

こちらのスライドに記載の通り、v2.18.0 で RuboCop Capybara が、v2.22.0 で RuboCop factory_bot がそれぞれ gem に切り出されています。 つまり、v2.17.1 以下のバージョンの場合には影響はありません。*2

尚、gem への切り出しをしたバージョンに上げたとしても一部警告は出ることがありますが、 RuboCop がエラーで終了してしまうことはないように後方互換性を保っています。 そのため、バージョンを上げたとしても何かが壊れてしまうということがないのが正しいので、もし何か問題があれば Issue で報告や、パッチを送って下さると非常に嬉しいです。

RuboCop の各種バージョンを調べるには以下のコマンドで調べることが可能です。*3

$ bundle exec rubocop -V
1.51.0 (using Parser 3.2.2.1, rubocop-ast 1.28.1, running on ruby 3.0.4) [x86_64-linux]
  - rubocop-capybara 2.18.0
  - rubocop-performance 1.18.0
  - rubocop-rails 2.19.1
  - rubocop-rspec 2.22.0

何をすれば良いか?

現状は後方互換性が保たれていますが、次のメジャーバージョンアップで RuboCop RSpec から RuboCop Capybara と RuboCop factory_bot への依存が切れます。 つまり、現状は後方互換性が保たれているので問題はないが、次のバージョンアップまでには移行に向けての対応が必要となります。 そこで、何をすれば良いかを説明します。大きく 2 パターンに分かれるので当てはまる方を読み進めてください。

FactoryBot 部門Capybara 部門を無効化している場合

たとえば、RSpec のみを使っている等の理由で RuboCop RSpec の FactoryBot 部門Capybara 部門を無効化している場合です。こちらの場合ですが...

何もする必要がありません。

ただし、次のメジャーバージョンアップデートで RuboCop RSpec からそれぞれの部門が消えるので、メジャーバージョンアップデートのタイミングで以下のように .rubocop.yml で Enabled: falseにしている箇所があれば削除する必要があります。

RSpec/FactoryBot:
  Enabled: false
RSpec/Capybara:
  Enabled: false

FactoryBot 部門Capybara 部門を使用している場合

こちらの場合も「何もする必要がありません。」と言えればいいのですが、次のバージョンアップより前にやっておくとスムーズに移行できることがあるので紹介したいと思います。

1. 切り出した先の gem を Gemfile に追加する

現状は後方互換性を保つために、切り出した先の gem に依存するようにしていますが、次のメジャーバージョンアップデートでその依存がなくなります。 つまり、切り出した先の gem を 忘れずに Gemfile に追加しておく必要があります。

gem 'rubocop-capybara', require: false
gem 'rubocop-factory_bot', require: false

2. .rubocop.yml に設定を追加する

Gemfile に追加するだけではまだ RuboCop 拡張の cop を有効にすることはできません。 RuboCop に拡張を読み込むように、次のように .rubocop.yml に設定を追加する必要があります。

require:
  - rubocop-capybara
  - rubocop-factory_bot

3. .rubocop.yml や .rubocop_todo.yml で cop 名を新しい名前に置き換える

gem への切り出しによって cop の部門が変わっています。そのため、新しい部門に置き換える必要があります。 もし、置き換えが必要な場合には次のような警告が出力されています。

$ bundle exec rubocop -A
.rubocop.yml: RSpec/Capybara/MatchStyle has the wrong namespace - should be Capybara
.rubocop.yml: RSpec/FactoryBot/ConsistentParenthesesStyle has the wrong namespace - should be FactoryBot
Inspecting 274 files
..................................................................................................................................................................................................................................................................................

274 files inspected, no offenses detected

実行時に毎回出力されるのですが、これはあくまで警告なので、 RuboCop の解析は途中で止まることなく最後まで実行されます。 こちらも現状は後方互換性を保つために、旧部門の cop でも動作するようにしているためです。

しかし、次のメジャーバージョンアップデートでは旧部門名では動作しなくなるので、切り替える必要があります。 FactoryBot 部門の cop を例に挙げると、以下の通り cop 名を変更すれば OK です。

-RSpec/FactoryBot/AttributeDefinedStatically
-RSpec/FactoryBot/ConsistentParenthesesStyle
-RSpec/FactoryBot/CreateList
+FactoryBot/ConsistentParenthesesStyle
+FactoryBot/AttributeDefinedStatically
+FactoryBot/CreateList

.rubocop_todo.yml は次のコマンドで再度生成することで置き換えは完了できます。

$ bundle exec rubocop --regenerate-todo

これで、今後のメジャーバージョンアップデートの時点で一気に変更する必要がなくなります。

まとめ

この手順を今のうちに実施しておくことで、 RuboCop RSpec の次のメジャーバージョンアップデートまでに緩やかに移行できます。 もし、この移行にあたって何か問題が発生した場合には、 Issue で報告やパッチを送って下さると非常に嬉しいです。

また、今年で RubyKaigi への参加は 2 回目で、昨年の初めて参加した RubyKaigi で凄まじい発表の熱量を感じました。 発表の内容は、最先端を走っている方の話で、理解できた部分は少なかったのですが、本当に楽しそうに自分の書いたコードについて話しているのを聞いていると、その熱量に引き込まれました。私はその時、いつか「自分も RubyKaigi で自身が取り組んだことについて発表してみたい」と思っていました。 なので、今年のRubyKaigiで発表することができて本当に嬉しかったです。

発表していた時の景色は今でも目に焼き付いています。本当に最高の景色でした。また来年もこの景色を見たいなと思いました。なので、また 1 年やっていこうと感じました。 RubyKaigi でお話しさせていただいた皆さんありがとうございました。また来年、沖縄でお会いできるのを楽しみにしています!!

おわりに

現在、アンドパッドでは一緒に働く仲間を大募集しています。
ご興味を持たれた方はカジュアル面談や情報交換のご連絡をお待ちしております。

engineer.andpad.co.jp

hrmos.co

*1:発表後に koic さんにフィードバックいただいたのですが、チーム名に誤りがありました。 RuboCop RSpec core team ではなく RuboCop RSpec teamが正しい名前です。

*2:とはいえ、誤検知や誤った自動修正などの問題も修正されていっているので、最新版にしておくことを個人的にはお薦めします。

*3:現状の RuboCop の最新版である 1.51.0 では RuboCop factory_bot のバージョンが出力されません。#11885の修正で master ブランチでは修正されていますので、次のリリースで出力されるようになります。