マルチラインテンプレートアノテーションに対応したセミコロン区切りによる行抽出
#2541で導入されたテンプレートアノテーション行の削除処理に不具合があり、Railsのマルチライン形式のアノテーションに対応できていませんでした。本PRは行全体の抽出方式をセミコロン区切りに変更し、テンプレートアノテーションを確実に除去できるようにしています。
背景
#2541では、Ruby coverage有効時にセグメンテーションフォールトが発生する問題を解決するため、コンパイル済みテンプレートソースから最初のテンプレートアノテーション行を削除する処理が追加されました。この処理は sub(/\A[^\n]*\n/, "") による正規表現で最初の改行までを削除していました。
しかし、Railsで導入されたテンプレートアノテーションは複数行にまたがる構造になっており、単純な改行区切りでは不完全な除去となっていました。その結果、不正なRubyコードが eval されてエラーが発生していました。
技術的な変更
lib/view_component/template.rb 内で、テンプレートのコンパイル済みソースを扱う compiled_source メソッドの処理が変更されました。正規表現による改行区切りから、セミコロンを基準とした文字列分割に置き換えられています。
変更前:
def compiled_source
result = super
# Strip the annotation line to maintain correct line numbers when coverage
# is running (avoids segfault from negative lineno)
result = result.sub(/\A[^\n]*\n/, "") if @strip_annotation_line
result
end
変更後:
def compiled_source
result = super
# Strip the annotation line to maintain correct line numbers when coverage
# is running (avoids segfault from negative lineno)
result = result.partition(";").last if @strip_annotation_line
result
end
partition(";") メソッドは文字列を最初のセミコロンで3分割し、[前方, 区切り文字, 後方] の配列を返します。last を取ることで後方部分のみを取得し、テンプレートアノテーション全体を確実に除去できます。
Railsのコンパイル済みERBテンプレートは、アノテーションがセミコロンで終わる構造になっているため、この方式でアノテーション部分のみを分離できます。改行の有無に依存しない抽出方式により、マルチライン形式のアノテーションにも対応しています。
設計判断
セミコロン区切りによる分割方式 が採用されました。
PR本文では「テンプレートアノテーションを簡単に除去するため」と説明されています。正規表現による改行ベースの抽出は、Railsのコンパイル出力形式の詳細に依存しており、複数行にまたがるアノテーションに対応できませんでした。セミコロンを区切りとすることで、アノテーションの構造変化に対してより堅牢な実装になっています。
partition メソッドは Ruby の標準メソッドであり、正規表現よりもシンプルで可読性の高いコードになります。Railsのコンパイル出力がセミコロンで区切られている前提に依存しますが、ERBテンプレートのコンパイル形式は安定しているため、この依存は許容範囲と判断されたと考えられます。
まとめ
本PRは、テンプレートアノテーションの除去処理を改行ベースからセミコロンベースに変更した修正です。Railsのマルチラインアノテーション形式に対応し、不正なRubyコードの eval を防いでいます。partition による単純な文字列分割により、アノテーション構造の変化に強い実装を実現しました。