`rails stats`が任意のディレクトリから実行可能に
この変更により、bin/rails statsをアプリケーションルート以外のディレクトリから実行しても、specファイルの統計情報が正しく表示されるようになりました。これにより、開発時のディレクトリ移動を気にせずコード統計を確認できます。
背景
これまで bin/rails stats をアプリケーションルート以外のディレクトリから実行すると、RSpecのテストコードが統計に含まれず Test LOC: 0 と表示される問題がありました。#2862 で報告されたこの問題は、コード統計の登録処理が Dir.pwd に依存していたことが原因です。
Rails 8.0で導入された Rails::CodeStatistics.register_directory を使用したコード統計登録は、Railtieクラス本体で Dir['./spec/**/*_spec.rb'] のように相対パスを使用していました。このパターンは現在の作業ディレクトリ(Dir.pwd)を基準に展開されるため、/tmp などの別ディレクトリから実行すると、specファイルが見つからなくなります。
技術的な変更
lib/rspec-rails.rb のコード統計登録処理が、Railtieクラス本体からイニシャライザ内に移動され、Rails.root を基準とした絶対パス解決に変更されました。
変更前:
if ::Rails::VERSION::STRING >= "8.0.0"
require 'rails/code_statistics'
dirs = Dir['./spec/**/*_spec.rb']
.map { |f| f.sub(/^\.\/(spec\/\w+)\/.*/, '\\1') }
.uniq
.select { |f| File.directory?(f) }
Hash[dirs.map { |d| [d.split('/').last, d] }].each do |type, dir|
name = type.singularize.capitalize
::Rails::CodeStatistics.register_directory "#{name} specs", dir, test_directory: true
end
end
変更後:
if ::Rails::VERSION::STRING >= "8.0.0"
initializer "rspec_rails.code_statistics" do
require 'rails/code_statistics'
root = ::Rails.root
dirs = Dir[root.join('spec', '**', '*_spec.rb').to_s]
.map { |f| f.sub(%r{^#{Regexp.escape(root.to_s)}/(spec/\w+)/.*}, '\\1') }
.uniq
.select { |f| File.directory?(root.join(f)) }
Hash[dirs.map { |d| [d.split('/').last, d] }].each do |type, dir|
name = type.singularize.capitalize
::Rails::CodeStatistics.register_directory "#{name} specs", root.join(dir).to_s, test_directory: true
end
end
end
主な変更点は3つです。まず、処理全体を initializer ブロック内に配置することで、Railsアプリケーションの初期化時に Rails.root が確定した後に実行されるようになりました。次に、Dir['./spec/**/*_spec.rb'] を Dir[root.join('spec', '**', '*_spec.rb').to_s] に変更し、相対パスから絶対パスベースの検索に変更しています。最後に、ディレクトリの存在チェックとパス登録も root.join(f) と root.join(dir).to_s を使用して絶対パス化されました。
テストケースは features/rails_stats.feature に追加され、/tmp ディレクトリに移動してから bin/rails stats を実行するシナリオで検証されています。
設計判断
コード統計の登録を Railtieクラス本体からイニシャライザへ移動 する方式が採用されました。
Railtieクラス本体で実行されるコードは、Railsアプリケーションの初期化が完了する前に評価されます。この時点では Rails.root がまだ確定していない可能性があるため、相対パスに依存した実装が選択されていました。しかし、この設計は作業ディレクトリへの依存という脆弱性を生んでいました。
イニシャライザに移動することで、Rails.root が確実に利用可能な状態で処理が実行されるようになり、絶対パス解決が可能になります。この変更により、Rails本体が想定する「アプリケーションルートを基準とした動作」に統一され、作業ディレクトリに依存しない堅牢な実装になりました。
まとめ
本PRは、コード統計登録のタイミングを変更することで、rails stats の実行場所への依存を解消した改善です。Railtieの初期化フローを適切に活用し、Rails.root による絶対パス解決を導入することで、開発時の利便性を損なわずに堅牢性を向上させています。