`NumberConverter::DEFAULTS` のネストされたHashをdeep freezeに変更

rails/rails

NumberConverter::DEFAULTS 内のネストされたHashに .freeze を追加し、定数全体をdeep freezeにしました。これにより、定数がRactor間で安全に共有可能(shareable)になります。

背景

この変更は、RailsをRactorと組み合わせて使えるようにするための一連の取り組みの一部です。Ractorの安全性(Ractor-safety)を確保するには、Ractor間で共有されるクラス・モジュールが持つすべての定数が「shareable」である必要があります。

先行する #57323 では、Style/MutableConstant Copを literals スタイルで有効化し、リテラルで定義された定数に対して外側のオブジェクトへの .freeze 適用を徹底しました。しかし、このCopが保証するのは 外側のHash のfreezeのみであり、ネストされた内側のHashまでは凍結されません。NumberConverter::DEFAULTS はまさにこのケースに該当し、外側のHashはfreezeされていたものの、内側のHashは可変のままでした。

Ractorのshareability検査は再帰的に行われるため、ネストされたオブジェクトのいずれかが可変であれば、定数全体がunshareable扱いになります。

技術的な変更

activesupport/lib/active_support/number_helper/number_converter.rb 内の DEFAULTS 定数に含まれる、ネストされたすべてのHashリテラルに .freeze を追加しました。

変更が加えられたのは以下の5箇所のネストされたHashです:

  • number キー配下のフォーマット設定Hash
  • currency キー配下のフォーマット設定Hash(および currency 自身のHash)
  • percentage キー配下のフォーマット設定Hash(および percentage 自身のHash)
  • precision キー配下のフォーマット設定Hash(および precision 自身のHash)
  • human キー配下のフォーマット設定Hash

代表例として currency の変更前後を示します:

変更前:

currency: {
  format: {
    precision: 2,
    significant: false,
    strip_insignificant_zeros: false
  }
},

変更後:

currency: {
  format: {
    precision: 2,
    significant: false,
    strip_insignificant_zeros: false
  }.freeze
}.freeze,

すべての変更は .freeze の付加のみであり、定数の値や構造自体には一切手が加えられていません。

設計判断

RuboCopのCopが自動的に保証できる範囲(リテラルの外側のfreeze)と、それだけでは不十分なケース(ネストされたHashのdeep freeze)を明確に分け、後者を手動で補完するアプローチが採られました。

DEFAULTS は数値フォーマットのデフォルト設定を保持する純粋な定数であり、実行時に変更されることを意図していません。そのため、deep freezeにすることによる機能上の副作用はなく、変更は安全です。Style/MutableConstant Copでカバーしきれないネスト構造のfreezeを個別に対処するという判断は、Ractor対応を段階的に進める上での現実的な手法といえます。

まとめ

本PRは、NumberConverter::DEFAULTS のネストされたHashすべてに .freeze を追加することで、定数をRactor-safeな状態に引き上げた変更です。外側のfreezeだけではshareabilityを満たせないというRactorの仕様上の制約を踏まえ、deep freezeによって定数ツリー全体の不変性を保証しています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
decdc60b

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

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

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

「総論→各論→結論」の構成が明確で、リード文、背景、技術詳細、まとめの必須要素がすべて含まれています。任意要素である「設計判断」も含まれており、記事の深みを増しています。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライト(```言語:ファイルパス)およびPR番号のリンク記法([#123](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

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

「Ractor-safety」「shareable」「deep freeze」といった用語が適切に使用されており、専門知識を持つエンジニアという対象読者に適合した内容になっています。

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

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

各セクションが総論→各論の構成になっており、各段落はトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が遵守されています。非常に読みやすい構成です。

Diff内容との照合 ✓ PASS

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

記事内で引用されているコード例は、提供されたDiffの内容とファイル名を正確に反映しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「deep freeze」「Ractor-safe」「shareable」などの技術用語が、PRの文脈および一般的な用法に沿って正しく使用されています。

説明の技術的正確性 ✓ PASS

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

Ractorのshareability検査の仕組みや、RuboCopのCopの挙動に関する説明は技術的に正確であり、PRの変更内容を論理的に裏付けています。

事実の突合 ⚠ WARNING

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

記事の主張の大部分はPR情報で裏付けられていますが、「設計判断」セクションにはPRに明記されていない技術的な洞察が含まれています。これは捏造ではなく妥当な解説ですが、PR情報から直接導出できない内容です。

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

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

PR番号(#57450, #57323)、定数名、ファイルパスなどの固有名詞はすべて正確に記載されています。

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

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

記事のタイトルはPRのタイトル「Deep-freeze `NumberConverter::DEFAULTS`」の内容を忠実に反映しています。

外部知識の正確性 ✓ PASS

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

バージョン情報やリリース予定など、PR情報に記載のない外部知識の追記は見られませんでした。

時間表現の正確性 ✓ PASS

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

「先行する」「既に...されていた」といった時間表現は、PR Descriptionの記述と一致しており、正確です。