もともとWSH実行環境下では、WScript.Argumentsでコマンドライン引数にアクセスできるが、ちょっと使いづらい(特に名前付き引数)。
なので、感覚的に使いやすいJavaScriptオブジェクトに展開してみる。(要:prototype.js)
WScript.Argumentsプロパティ(=WshArgumentsオブジェクト)には、Namedプロパティ(WshNamedオブジェクト)とUnnamedプロパティ(WshUnnamedオブジェクト)があり、それぞれ名前付き引数と名前なし引数へのアクセスを提供している。
名前付き引数は、たとえば「/f:ファイルパス」のようにスラッシュから始まるスイッチと引数の値をコロンで区切った形式で提供される。
名前なし引数はそのまんまで、スイッチを伴わず値のみで提供される。エクスプローラ上で.jsファイルにファイル/フォルダをドラッグドロップすると、そのパスが名前なし引数として渡される。
WshNamed/WshUnnamedオブジェクトはコレクションオブジェクトで、たとえばlengthプロパティはあるがfor/for...inでアクセスできないなど、結構使いづらい。
このようにActiveXで提供されるコレクションを操作する場合は、JScriptの独自拡張であるEnumeratorオブジェクトを使用する。Enumeratorの使い方は以下のような感じ。
// コレクションオブジェクトを引数にしてEnumeratorをnewする
var enumerator = new Enumerator( WScript.Arguments.Unnamed );
// atEnd()がtrueを返すまで、moveNext()して列挙を繰り返す
for(; ! enumerator.atEnd(); enumerator.moveNext()) {
// 要素へアクセスするにはitem()メソッドを使う
WScript.Echo( enumerator.item() );
}
このままじゃ使いづらいし、せっかくprototype.jsを使うんだからEnumerableとして使えるラッパーのファクトリを考えてみる。
ま、別に$Eじゃなくてもいいんだけど、仮ということで。
function $E(collection) {
var en = new Enumerator( collection );
return Object.extend( {
_each : function(iterator) {
// ここでリセットしておかないと繰り返し使えない
en.moveFirst();
for(; ! en.atEnd(); en.moveNext()) {
iterator( en.item() );
}
}
}, Enumerable );
}
_eachさえ実装できればEnumerableになるのはありがたい。
ようやっと準備が整ったので、引数を展開する関数を作る。
function parseArguments() {
// 引数が展開されたオブジェクト
var result = {
named : {},
// Unnamedは単純なコレクションなので一発で展開
unnamed : $E( WScript.Arguments.Unnamed ).toArray()
}
// NamedはEnumerateしてもキーしか列挙されないのでベタにまわして展開
$E( WScript.Arguments.Named ).each( function(key) {
result.named[ key ] = WScript.Arguments.Named.item( key );
} );
return result;
}
使い方は単純で、
var args = parseArguments();と呼び出すだけ。 コマンドラインから
cscript test.js /f:C:\test.txtと呼ばれた場合、
args.named["f"] // → C:\test.txtのようにアクセスできる。
セコメントをする