Hash.from_xml が `type="date"` の空白付与値で Date::Error を起こすバグを修正

rails/rails

Hash.from_xml は XML の type="date" 要素で、要素内容に前後の空白(改行・スペース)があると Date::Error をスローし、パース全体が失敗していました。今回の PR は、日付パーサーに strip を適用して空白を除去し、他の型キャストと同様の寛容性を持たせた修正です。

背景

Hash.from_xmltype="date" のノードで空白を含む文字列を処理すると、内部で ::Date.strptime(date, "%Y-%m-%d") が呼び出され、strptime が空白を許容しないため Date::Error: invalid date が発生していました。整数型(integer)や真偽値型(boolean)はそれぞれ to_ito_s.strip で前後空白を除去しているため、日付だけが例外的に扱われていた点が不整合の原因でした。この不整合は、インデントされた XML や整形済み XML を人が読むケースで頻出し、実務上の障壁となっていました。

技術的な変更

日付パーサーに文字列化と空白除去を追加しました。activesupport/lib/active_support/xml_mini.rbPARSING ハッシュ内で、"date" キーの Proc を次のように変更しています。

"date" => Proc.new { |date| ::Date.strptime(date.to_s.strip, "%Y-%m-%d") },

変更前は ::Date.strptime(date, "%Y-%m-%d") で、date がそのまま渡されていました。to_s.strip を付与するだけのシンプルな差分で、既存コードへの影響は最小限に抑えられます。空白がなくても to_s は無害に機能し、後方互換性は維持されます。

テストケースを追加し、修正の効果を検証しました。activesupport/test/core_ext/hash_ext_test.rb に新たに test_date_type_from_xml_with_surrounding_whitespace が導入され、インデントされた XML を渡した場合に正しく Date オブジェクトが生成されることを確認しています。また、activesupport/test/xml_mini_test.rb では既存の test_dateassert_raises(ArgumentError) に更新され、非文字列入力が to_s 後に ArgumentError として扱われることを明示しました。

def test_date_type_from_xml_with_surrounding_whitespace
  xml = <<-EOT
  <event>
    <starts-on type="date">
      2020-01-01
    </starts-on>
  </event>
  EOT

  assert_equal({ "starts_on" => Date.new(2020, 1, 1) }, Hash.from_xml(xml)["event"])
end

設計判断

一行の変更で型キャストの一貫性を確保するという方針が採られました。boolean パーサーが既に to_s.strip を使用している点から、日付パーサーでも同様の処理を導入することで API の振る舞いを統一し、利用者が期待する「空白は無視される」挙動を全型に対して提供しています。代替案として新しい設定キーや専用ラッパー関数の導入が議論された可能性がありますが、最小限の変更で既存コードとテストに影響を与えない選択が最も保守的で実用的と判断されました。

まとめ

この PR は Hash.from_xml の日付型パーサーに to_s.strip を追加し、インデントや改行を含む XML でも例外なくパースできるようにした修正です。既存の型キャストと振る舞いを揃えることで API の一貫性が向上し、利用者は余計な前処理なしに XML を安全に扱えるようになります。

記事メタデータ

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

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文・背景・技術的変更・設計判断・まとめの5セクションが揃っており、総論→各論→結論の流れが明確です。

カスタムMarkdown構文 ⚠ WARNING

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

コードブロックは正しい ``ruby:ファイルパス`` 形式ですが、PRリンクが `[PR #57670](URL)` となっており、要求された `[ #57670 ](URL)` 形式から外れています。

対象読者への適合性 ✓ PASS

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

Rails エンジニア向けの専門的な記述で、初心者向けの過度な説明はありません。

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

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

各セクションは総論・各論・結論のパラグラフ構成で、トピックセンテンスで始まり、1段落は1トピックに収まっており、長さも適切です。

Diff内容との照合 ✓ PASS

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

記事中のコード変更およびテスト追加は Diff の内容と完全に一致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

Date::Error、type="date"、to_s.strip などの用語は PR と合致しており、誤用はありません。

説明の技術的正確性 ✓ PASS

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

空白が原因で Date.strptime が失敗する理由や、他型キャストとの不整合が正しく説明されています。

事実の突合 ✓ PASS

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

記事の主張はすべて PR の説明・Diff・テストに裏付けられており、根拠のない数値や外部知識は含まれていません。

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

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

PR番号 #57670 とテストで使用した日付 2020-01-01 が正しく記載されています。

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

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

記事タイトルは PR の趣旨「Hash.from_xml が whitespace により Date::Error を起こすバグ修正」と一致しています。

外部知識の正確性 ✓ PASS

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

LTS やリリース日程等の外部情報は一切記載されていません。

時間表現の正確性 ✓ PASS

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

時間表現の歪曲はなく、PR の記述と整合しています。