`titleize`がUnicode小文字を正しく大文字化するよう修正
Inflector#titleizeのASCII限定の正規表現を修正し、đ・é・ü・ñ・ćなどのUnicode小文字も正しくタイトルケースに変換できるようになりました。
背景
Inflector#titleize は、単語の先頭文字を大文字化するために正規表現 [a-z] を使用していましたが、これはASCII範囲の小文字のみを対象としていました。そのため、ć・đ・é・ü・ñといったラテン拡張文字を含む単語の先頭文字は、大文字化の対象として認識されずにそのまま小文字で出力されるという問題がありました。
PR本文の例が示すように、titleize("ćasim đipa") は "Ćasim Đipa" を返すべきところ、"ćasim đipa" のまま変化しないという動作になっていました。多言語対応が求められるアプリケーションでは、この挙動はサイレントな不具合として現れます。
技術的な変更
activesupport/lib/active_support/inflector/methods.rb の gsub 正規表現パターンを1文字変更することで修正が行われました。
変更前:
humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w[''\'`()])[a-z]/) do |match|
match.capitalize
end
変更後:
humanize(underscore(word), keep_id_suffix: keep_id_suffix).gsub(/\b(?<!\w[''\'`()])\p{Lower}/) do |match|
match.capitalize
end
Rubyの正規表現エンジンが対応するUnicode文字クラス \p{Lower}(別名 \p{Ll})は、ASCII小文字を含むすべてのUnicode小文字カテゴリの文字にマッチします。[a-z] の26文字からUnicode全域の小文字へと対象が広がります。既存の否定後読み (?<!\w[''\'()])や\bによる単語境界の判定ロジックはそのまま維持されており、アポストロフィ付き単語(Fred's` など)の処理も引き続き正しく動作します。
テストケースには "über ñoño" => "Über Ñoño" が追加され、ü・ñ・Ü・Ñ といったラテン拡張文字でのタイトルケース変換が期待どおりに動作することが検証されています。
設計判断
最小差分での修正方針 が採られており、変更はパターン文字列の [a-z] を \p{Lower} に置き換える1行のみです。
この変更はあくまで正規表現パターンの修正であり、humanize や underscore などの前処理ステップ、あるいは capitalize を呼び出すブロック自体は変更されていません。修正以前は「正規表現がマッチしないためにブロック自体が実行されない」ことが問題の本質であり、大文字化ロジックそのものには問題はありませんでした。
まとめ
1文字のパターン変更により、titleize のUnicode対応が完成しました。[a-z] という暗黙のASCII前提が \p{Lower} に置き換わることで、ラテン拡張文字を含む多言語テキストに対しても正しいタイトルケース変換が保証されます。