2008-07-21

RhinoのContext.evaluateString()は行番号を設定できたのだが

ScriptEngine.eval()に行番号を渡すオーバーロードがなかったので、ちょっとしたフィルタプログラムを作ろうとした時に困った。

自分のWebサイトのHTMLファイルを、埋め込みスクリプトのやり方で静的に生成したいと思った時、当初は埋め込みタグをScriptEngine.eval(java.lang.String)で再帰的に評価する方法を考えていた。

<% //内側の埋め込みスクリプトの結果を外側でさらに利用する
    var ret = "<%=内側のスクリプト%>";
    ...
%>
これは変なやり方だし、フィルタプログラムのソースも込み入ったものになるのだけれど、当時は、わざわざ自作するならC言語のマクロとかでいわれた「プリプロセッサの結果をプリプロセッサに書けることはできない」に対応する必要があるんじゃないかと思っていた。
また、こっちの方が評価される範囲が明示的で、スクリプト例外の起こりうる箇所を(埋め込みタグを飛び越えてforやwhileなどの制御構文を使うよりは)特定しやすい、とも思っていた。

問題は、埋め込みタグを評価する度に行番号が初期値に戻ってしまうので、スクリプト例外が発生した時、問題の発生箇所を示す行番号がファイル全体から見た行番号になっていない、ということだった。

これに対応しようとあれこれ調べたものの、
  • 評価するスクリプトの行番号(のオフセット)をContext.evaluateString()みたいに渡すことはできない
  • ScriptExceptionがコンストラクタの時点で行番号付きメッセージを作成しちゃってる
ので、泥臭い対処法としては、ScriptExceptionのメッセージを取得した後、「行番号っぽい箇所」を本当の行番号で置換してから表示すれば何とかなるようだ。うーん。

結局、最終的に作ったフィルタプログラムは、よくある埋め込みスクリプトと同じものになった。
日付: <%=new java.util.Date()%>
=> g_out.print('日付: ');g_out.print(new java.util.Date());g_out.print(' ');
=> 日付: Mon Jul 21 13:27:17 JST 2008

このやり方だと、(JSPみたいに)うっかり床を踏み抜いた時の問題があるものの、今の使い方はテキストの一部を変数で置き換えたりファイルの日付を自動取得したりしているだけなので、まあ、滞りなく使えている。

0 件のコメント:

コメントを投稿