Erubis を使ってみる (2) … ERB と Erubis の挙動の違い
先日の続き。 tDiary で Erubis を動かすとエラーになる件を調べてみた。
エラーの箇所は TDiaryBase::do_eval_html (tdiary.rb の1129行目付近) 。
r = ERB::new( rhtml.untaint ).result( binding ) r = ERB::new( r ).src
ソースを読むと、(理由は分からないけど) tDiary はERBを2回変換しているみたい。 そこで、一度目の変換の結果をファイルに出力して、 ERB と Erubis での変換結果の違いを比べてみた。 結果はこれ。
<div class="day"> -<h2><%= title_proc( Time::at( 1224428400 ), "" ) %></h2> +<h2><%= title_proc( Time::at( <%=@date.to_i%> ), "" ) %></h2> <div class="body"> -<%= body_enter_proc( Time::at( 1224428400 ) ) %> +<%= body_enter_proc( Time::at( <%=@date.to_i%> ) ) %>
Erubis を使った場合は、 @date.to_i が変換されずに残っている。 これがエラーの原因みたい。
ERB と Erubis の挙動の違い
どうやら「<%%=」の挙動が違うようなので、サンプルプログラムで問題を切り分け。
str = "<%%= Time::at( <%= @date.to_i %> %>" @date = Time.now puts ERB.new(str).result(binding) puts Erubis::Eruby.new(str).result(binding) puts Erubis::TinyEruby.new(str).result(binding)
結果は以下の通り。
ERB は内側の @date.to_i を変換している。 変換結果は有効な eRuby フォーマットなので、もう一度 eRuby を通しても大丈夫。
<%= Time::at( 1227412425 ) %>
Erubis::Eruby は内側の @date.to_i をそのままにする。 変換結果は eRuby フォーマットとして不適切なので、もう一度 eRuby を通すとエラーになる。
<%= Time::at( <%= @date.to_i %> ) %>
Erubis::TinyEruby はコンパイルエラーになった。
example2.rb:13: compile error (SyntaxError) example2.rb:13: syntax error, unexpected tIVAR, expecting $end _buf = '';%= Time::at( <%= @date.to_i ; _buf << ' ) %>'; ^ from example2.rb:13
eRuby の仕様としては、どの挙動が正解なんだろうか。
- Erubis のバグなので、解消されれば tDiary でも Erubis がそのまま動くようになる。
- 仕様は不定なので、 tDiary の実装を変えないと Erubis は動かせない。
調べてみた (ERB)
Rubyinst Magazine - 標準添付ライブラリ紹介 【第 10 回】 ERBに説明があった。
<%% … 「<%」をその場に挿入 (「<% ... %>」の中ではそのまま)
「<% ... %>」や「<%%」の挙動は明記されているけど、「<%% ... %>」の挙動は明記されていない。 単純に考えると、「<%%」は「<%」に置き換わるだけなので、内部の「<% ... %>」は変換するのが正しいように思えるけど。うーん。
調べてみた (Erubis)
Erubis の動作はErubis User's Guideに書かれていた。
Since 2.6.0, '<%% %>' and '<%%= %>' are converted into '<% %>' and '<%= %>' respectively. This is for compatibility with ERB.
ERB との互換性のために 2.6.0 から対応したと。 互換性が目的だったら、パッチを送れば ERB と同じ動作になるように修正される可能性が高いかな。
追記
そんなに簡単な問題じゃないかも。 Erubis は <% ... %> を String#scan でマッチさせて処理しているみたい。 <%%= ... <%= ... %> ... %> のようにネストした構造に対応するには難しいのかも。 ERB はどうやってるんだろ。