2008-07-27

Bloggerの改行タグ設定をOFFにしてみた

過去の投稿まで<br />タグが付かなくなった...。
まだBloggerを使い始めて間もないので、手作業で地道に修正。

2008-07-22

(x == undefined)と(typeof x == 'undefined')は同じだと思ってた

単純な比較結果で満足してた。
>jrunscript
js> var a = undefined;
js> if (a == undefined) {println('a == undefined');}
js> a == undefined
js> if (typeof a == 'undefined') {println("typeof a == 'undefined'");}
js> typeof a == 'undefined'
後で変数aをnullにしてみて、気が付いた。
js> a = null;
js> if (a == undefined) {println('a == undefined');}
js> a == undefined
js> if (typeof a == 'undefined') {println("typeof a == 'undefined'");}
js> (変数aは未定義ではないので、何も出力されない)
ちなみに、undefined変数は、Java6付属のRhinoでも書き換え可能だった。
なので、結果が確実そうな(typeof 変数 == 'undefined')を使うとして、文字列比較のパフォーマンスを気にする必要はあるんだろうか?
今はちょっとした書き捨てスクリプトに使っている程度なので、特に問題なさそうだ。

Rhinoのソースファイルを見ると、同じオブジェクト参照同士の同値比較ならJavaの==で片付けてもらえたと思うので、事前に(typeof 変数名)の返す文字列をキャッシュしておいて、以降の比較に使えば速いのかな、とか思ったものの、そんな細工が必要になるほどシビアな使い方をすることは無い...と思う。

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

RhinoでcloseStream関数に相当するものが欲しかった

// 入出力例外をスローしないclose()
function doClose(stream) {
    if (stream) {
        try {
            stream.close();
        } catch(e) {
            // 入出力例外をダンプ?
            java.lang.System.err.println(e);
        }
    }
}
JavaScriptはJavaよりも幅広くcatchするということを忘れていた。
function doClose(stream) {
    // 使い方次第ではCloseableかどうか調べた方が確実かも
    if (stream) {
        try {
            stream.close();
        } catch(e if e.javaException instanceof java.io.IOException) {
            // 入出力例外だけcatchして出力する
            var err = java.lang.System.err;
            err.println(e.message);
            err.println(e.stack);
        }
    }
}
今使っている書き捨てスクリプトで問題なく動いている。
(2012-09-19: 条件付きcatchを使うように変更した。変更前は、スローされたオブジェクトを全てcatchして目的外のオブジェクトなら再スローするように記述していたが、これは冗長だった)

2008-07-20

load関数は除かないで欲しかった

従来のRhino(js.jar)からJava6のスクリプトエンジンに切り替えた時に一番ビビった。
いずれ標準的な方法にまとまるのだろうけれど、それまでの間はjs.jarとの互換性からいってもload()みたいな機能が標準で残っていた方がありがたいわけで。

Using JavaScript code modules
http://developer.mozilla.org/ja/docs/Using_JavaScript_code_modules

ScriptEngine#eval(Reader)を使えば20行程度で自作できるものの、一度標準っぽく搭載されていた機能をスクリプトエンジンの利用者それぞれにコピペやら再実装させるのは、悩ましいやり方の気がする。
※jrunscript経由でスクリプトを実行する場合は、スタートアップスクリプトのお陰で使える。スクリプトエンジンからロードできると助かるのだけれど、出来るのかどうか分からない。

Mozilla Rhinoを使ってみて、とりあえずハマったこと(と、その対策)

問題1. Javaクラスのコンストラクタがambiguousとかいうエラーが発生する
問題2. Javaクラスのメソッドがambiguousとかいうエラーが発生する
問題3. Javaの文字列とJavaScriptの文字列が混在した時に、JavaScript向けの関数でエラーが発生する

(2012-09-16更新: mozilla.orgに上記3つの対応方法を説明したページがあったのだが、いつのまにか無くなってしまったようだ。http://www.mozilla.org/js/liveconnect/lc3_method_overloading.html)

対策1. new java.io.File["(java.lang.String)"](fileName); のように直接シグネチャを指定する
対策2. java.lang.String["valueOf(java.lang.Object)"](null); のように直接シグネチャを指定する
対策3. String(obj).replace(/regex/, "repstr"); のようにString(変数)でJavaScriptの文字列に変換する

どこまで厳密に対応するかは、作るスクリプトの役割次第。

細々と初めてみました

まだBlogger自体の使い方とか手探り状態ですが、
まあ、書いた日本語が表示できてれば何とかなるんじゃないかと。