Zeitwerk で特別なパターンのモジュール/クラス名をオートロードする

Rails 6.0 から Zeitwerk がオートローダーとして導入されました。 Zeitwerk の README に書かれている通り、ファイルパスからモジュールやクラスを読み込みます。

github.com

モジュール/クラス名がファイルパスになっていれば良いのですが、特別なパターンだと名前を解決できない場合があります。

クラス名に頭字語を使っている場合

例えば、クラス名に頭字語を使っている場合です。

以下のログがその例で、lib/ridgepole/dsl_parser.rb というファイルパスを Zeitwerk は Ridgepole::DslParser と想定しています。 しかし、実際のクラス名は Ridgepole::DSLParser なので名前の解決に失敗しています。(bin/rails zeitwerk:check は Zeitwerk が使用できるかチェックするタスク)

% bin/rails zeitwerk:check
Hold on, I am eager loading the application.
expected file lib/ridgepole/dsl_parser.rb to define constant Ridgepole::DslParser,

対応方法

どうすればいいかというと、Rails ガイドのオートロードについて書かれているページには、config/initializers/inflections.rb をカスタマイズしましょうとあります。

If you need to customize any of these inflections, for example to add an acronym, please have a look at config/initializers/inflections.rb.

guides.rubyonrails.org

ActiveSupport::Inflector モジュールには活用形をカスタマイズする機構があるので、Zeitwerk もそれを参照する形になっているようです。 以下は Zeitwerk が ActiveSupport::Inflector の設定をテストしている箇所です。

rails/zeitwerk_integration_test.rb at d05f1f036ff4987918c907eb7e78ef8e8eedd6ea · rails/rails · GitHub

今回の場合は、dslDSL と解決したいので、config/initializers/inflections.rb を以下のように定義します。

ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.acronym "DSL"
end

再度 bin/rails zeitwerk:check を実行してみると、無事に解決できました。

% bin/rails zeitwerk:check
Hold on, I am eager loading the application.
All is good!

今回は Rails アプリ側で対応しましたが、理想を言うなら、ライブラリ側の名前を変更するほうが使う側にとって良いのでは、と思ったりもします。