Template クラスにフォーマット検証・正規化ヘルパーを抽出

rails/rails

この PR は Template::Types への直接依存を排除し、フォーマットのバリデーションと正規化ロジックを Template クラスに移譲すると同時に、autoload の重複と順序を整理しました。結果として、Action Dispatch がロードされているか否かに関わらず同一のインターフェースで利用でき、コードベースの可読性が向上します。

背景

Template::Types は Action Dispatch がロードされている環境では別実装になるため、LookupContext から直接呼び出すと環境依存の振る舞いが発生していました。そのため、フォーマット検証ロジックを Template に切り出すことで、実装差異を隠蔽し一元管理する必要がありました。また、eager_autoload ブロック内で同一クラスが二度 autoload されている箇所があり、将来的なメンテナンスでミスが起きやすい状態でした。

技術的な変更

Template クラスに validate_formatsnormalized_formats の二つのクラスメソッドが追加されました。validate_formats は渡された配列が Types.symbols に含まれるか検証し、違反があれば ArgumentError を送出します。normalized_formats は有効なシンボルだけを抽出し、無効な場合は nil を返すシンプルな正規化ユーティリティです。

class Template
  class << self
    def validate_formats(formats)
      return if Types.valid_symbols?(formats)
      invalid = formats - Types.symbols
      raise ArgumentError, "Invalid formats: #{invalid.map(&:inspect).join(", ")}"
    end

    def normalized_formats(formats)
      formats & Types.symbols unless Types.valid_symbols?(formats)
    end
  end
end

LookupContext の実装が二か所で更新されています。DetailsKey.details_cache_key では、従来 Template::Types.valid_symbols? を呼び出していた箇所を Template.normalized_formats に置き換え、正規化されたフォーマット配列をキャッシュキーに使用するようにしました。また、LookupContext#formats= では、手動でシンボル検証とエラーメッセージ生成を行っていたロジックを Template.validate_formats に委譲しています。

# 変更前
unless Template::Types.valid_symbols?(values)
  invalid_values = values - Template::Types.symbols
  raise ArgumentError, "Invalid formats: #{invalid_values.map(&:inspect).join(", ")}"
end

# 変更後
Template.validate_formats(values)
# 変更前
if formats = details[:formats]
  unless Template::Types.valid_symbols?(formats)
    details[:formats] &= Template::Types.symbols
  end
end

# 変更後
if normalized = Template.normalized_formats(formats)
  details[:formats] = normalized
end

Templateautoload 順序が整理され、重複していた autoload :Types エントリが削除されました。さらに、RawFileRenderableHandlers などのロード順がアルファベット順に揃えられ、将来的な追加や削除が視認しやすくなります。

@@
-      autoload :RawFile
-      autoload :Renderable
-      autoload :Handlers
+      autoload :HTML
+      autoload :Handlers
+      autoload :Inline
+      autoload :RawFile
+      autoload :Renderable
       autoload :Sources
       autoload :Text
-      autoload :Types
+      autoload :Types

設計判断

Template へロジックを移行した最大の意図は、外部からの呼び出し側が Template::Types の実装詳細を意識せずに済むようにすることです。validate_formatsnormalized_formats は内部で Types のメソッドを利用していますが、公開インターフェースは Template のみで統一され、既存コードは Template.validate_formats へ置換えるだけで機能が保たれます。autoloader の整理は、名前空間のロード順序を一貫させることで、将来的なリファクタリング時のヒューマンエラーを防止する設計選択と言えます。

まとめ

本 PR はフォーマット処理を Template に集約し、環境依存を排除すると同時に autoload の重複・順序問題を解消しました。公開 API の変更はなく、既存の呼び出し側は同等の振る舞いを維持しつつ、コードの意図が明確になるという副次的効果も得られています。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
613a4ca5

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文、背景、技術的変更、設計判断(任意)、まとめの全要素が揃っており、総論→各論→結論の流れが明確です。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックは正しい `言語:ファイルパス` 形式ですが、PRリンクが `[PR #57780](URL)` となっており、仕様の `[ #123 ](URL)` 形式とずれています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Rails の内部実装に関する記述が中心で、エンジニア向けの適切な技術レベルです。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションは総論・各論・結論の構成を保ち、段落はトピックセンテンスで始まり、一段落一テーマで長さも適切です。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは Diff 内容と一致しており、ファイル名・変更点・追加メソッドすべて正しく反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

用語は PR 説明と一致し、Rails のコンテキストで正しく使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的主張は Diff と PR の記述に基づき、論理的かつ正確です。

事実の突合 ⚠ WARNING

PR情報による主張の裏付け(ハルシネーション検出)

「コードベースの可読性が向上します」や「副次的効果」などの効果は PR に明示されておらず、根拠のない推測と見なされます。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR 番号 #57780 の記載は正確です。数値的な誤りはありません。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルは PR の趣旨(ヘルパー抽出)を適切に要約しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

バージョン情報やリリーススケジュール等、PR 以外の外部知識は含まれていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現は使用されておらず、PR と食い違いはありません。