JsDoc Toolkitを調べてみた2007年06月28日 19時39分26秒

ともかく調べてみた

昨日のエントリで書いたJsDoc Toolkit、激しく興味があったので、Eclipse環境を整えるついでに調べてみた。

ざっとソースを見ただけでも、外部スクリプトのロード機能を使っているみたいなのでWSH環境は無理と判断、htaで使うことを目標にしよう。

で、どうよ?

結論から言うと、まだドキュメント出力まで辿りつけていない。Rhino依存・JavaScript(非ECMAScriptっていう意味ね)依存の部分が大杉。

まぁ、これだけじゃ記事にする価値がないので、以下にヒントというかメモを残しておく。 依存オブジェクトのスケルトン定義くらいなのですぐに役立つわけではないが、自分でなんとかしてみようという物好きな方には参考になるかも。

足りない機能をでっち上げる

まずは依存関数や依存オブジェクトを定義するところからはじめる。

大まかなアウトラインはmalさんのコメントを参考にして、Java依存部分を探してみた。というか、JsDoc.jsの1040~1061行目で名前空間のチェックしてたのね。これ、else条件がないけどifにしてる意味あるのかな?

で、Java関連のでっち上げ定義のスケルトンは以下の通り。

// これはスケルトンコード。ホスト環境に合わせてここから実装していくとよいかも。
// 各メソッドの動作はJavaのAPIリファレンスで調べてね。
var Packages = {
	java : {
		// java.io 名前空間(javaはパッケージって言うのかな?)
		io : {
			// データ書き込み用のストリームライタークラス
			FileWriter : function(path) {
				// contentsを出力する
				this.write = function(contents) {
					// 書き込み処理
				}
				
				// ストリームを閉じる
				this.close = function() {
					// バックエンドストリームを閉じる処理
				}
				
				// バッファの内容を実体へ出力
				this.flush = function() {
					// フラッシュ処理
				}
			},
			
			// ファイルクラス。ディレクトリも兼用するのでなかなか難儀
			File : function(path) {
				// このオブジェクトがディレクトリかを示すbool値
				this.directory = false;
				
				// このディレクトリ内のファイル・ディレクトリの名前を配列で返す
				this.list = function() {
					// ディレクトリ名とファイル名をかき集める処理
				}
				
				// このディレクトリの直下にディレクトリを作成する
				this.mkdir = function(path) {
					// サブディレクトリを掘る処理
				}
			}
		},
		
		// java.lang 名前空間
		lang : {
			System : {
				// プロセスを終了する
				exit : function(exitCode) {
					// プロセス終了処理。未実装でも大丈夫でしょ。
				}
			}
		}
	}
}

// パスの区切文字を保持する静的フィールド
Packages.java.io.File.separator = "\\";

// 「Packages.」を省略してアクセスしてる部分があるのでショートカット定義
var java = Packages.java;

Java依存の他に、Rhino依存のコードもあるので、実際に動かしながら調べてわかった関数定義。環境によってはいらないものもある。

// 指定パスのファイルの内容を返す
function readFile(path) {
	// pathのファイルの内容を返す
}

// 指定パスのスクリプトをロードする。実行環境のホストオブジェクトが同等の機能をもってないとしんどい。
function load(path) {
	// 読み込んでグローバル空間へ適用。って無理やん。
	// ホストオブジェクトがHTMLならscriptタグ差し込んでなんとかならんこともないが、
	// そうやって差し込まれたスクリプトから別にload()されるとお手上げ。
}

// コンソールへのメッセージ出力。
// SpiderMonkeyとかは定義しなくてよいかな。
function print(msg) {
	// どっかへ出力
}

// これは特殊な用途で呼び出されてる。詳細は後述。
function fail() {
	// fileNameプロパティを持つ例外をスローする。
}

fail()だが、これはJsDoc.jsが自分自身のパスを取得するために使用している。具体的には、JsDoc.jsの1008~1009行目で、キャッチした例外のfileNameプロパティがJsDoc.js自身のパスを返すことを期待して使ってる。まあ、ご本人もコメントに書いてるように、もうちょっとなんとかしたほうがよい使い方だな。

これだけじゃないっす

これでどうよ?と、思ったがエラーがでる。Array#filterメソッドとやらを使ってやがる。ちくしょう。 なので、JScriptなどの場合は以下の要領で拡張。

Array.prototype.filter = function(iterator, thisObj) {
	var result = [];
	for(var i = 0; i < this.length; i++) {
		if( iterator.call( thisObj, this[i], i ) ) result.push( this[i] );
	}
	return result;
}

さて、これでどうだ!と思ったが、今度はテンプレートスクリプト側でエラーが発生。テンプレートにHTMLを指定した場合はまだ追っかけきれてないが、XMLを指定した場合は、テンプレート中でFunction#getParam()とかいうメソッドで引っかかる。困ったもんだ。

その他の注意点

冒頭で述べたとおり、今回の調査ではスクリプトの動的ロードをなんとかするためにhtaにした。また、メインスクリプトのJsDoc.js自体も即時実行コードになるため、それ自体も動的ロードで実行させるようにしていた。 これでなにが問題か、というと、JsDoc.jsの処理中にJsPlate.jsを「load()」しにいくが、このロード結果が現在実行中の空間にはまだ反映されないのだ。 なので、プラグインロードはしないと割り切って先にJsPlate.jsをタグでロードしておくようにする必要があった。

プラグインロードまで見越すとなると、JsDoc.jsの最終の2行をコメントアウトして先にロードしておき、イベントハンドラなどから同様の実行コードを実行するように改変する必要がある。

また、Rhino環境ではどうかわからないが、JsDoc.jsの1071行目から定義されている「ReadFile」関数が値を返さない実装になっている点も注意。これ、ほんとに動作するのか?

あと、for-inループに依存しすぎてるので、ことによるとfor-in内でメンバの除外処理が必要になるかも。だって最低限Array#filterは実装しなきゃなんないからね。

まとめ

外部依存の洗い出しは大方できたが、JScript系の実行環境で使用するのは厳しそう。SpiderMonkeyとかJSDBならなんとかできる可能性アリ。

根性が残ってたら続けるかも。