いろいろあってWSH/Jscriptを使い続けていますが、先につながるように以下のような点に気を付けるようにし始めました。
・CommonJS(風)のモジュールの仕組みを取り入れる。
・MS/WSH固有のことは極力避ける。やむなく使う場合は極力隠蔽する。
・なるべくCommonJSとかnode.jsとかを意識するよう心掛ける。
まず第一歩として、WSHにはないrequireを用意することにしました。
具体的にはnode.jsの仕様を参考にして、とりあえずは必要最小限の機能から始めて、まずは自分用の「モジュール化の基盤」を作ることからスタートする。今までの自分の小物資産をどんどんモジュール化していく。
そしてrequireも少しずつ強化していく。
こんな感じでぼちぼちやっていこうかな。と。
で、なんちゃってrequireの初版がこちらになります。
// Function( 'context', 'path', これ )
// wsh用commonjs(風)対応のなんちゃってrequire
var fso = WScript.CreateObject("Scripting.FileSystemObject");
var libpath = fso.GetAbsolutePathName(path)+"\\";
context.require = function(path) {
var fso = WScript.CreateObject("Scripting.FileSystemObject");
var file_path = libpath + path + ".js";
var input_stream = fso.OpenTextFile(file_path, 1, false);
var module_code = input_stream.ReadAll();
input_stream.Close();
var eval_code = "(function(){" +
"var module = {};" +
"module.exports = {};" +
module_code + ";" +
"return module.exports;" +
"})()";
return eval(eval_code);
}
context.require.libpath = libpath || '';
return libpath;
使い方ですが、どこかにライブラリ用のフォルダを作り、そこにこれとモジュールファイルを置きます。利用する側は以下のようなテンプレートを用意しました。「requireおび」と命名しました。
///////////////////////////////////////////////////////////////////////////////
var global = Function("return this")(); // globalを設定&require 拡張。
var libpath = "./".replace("/","\\"); //←←←
(Function( 'context', 'path', (new ActiveXObject("Scripting.FileSystemObject")).
OpenTextFile( libpath + "require.js",1).ReadAll() ))(global,libpath);
///////////////////////////////////////////////////////////////////////////////
// ここからコードを書く。
←←←の左側に、自分のライブラリのパスを入れておきます。上の例はとりあえずカレントを見るようにしてあります。テンプレートを用いて書いたスクリプトと、require.jsと、モジュールファイルとを一緒のところにおいておけばとりあえず動く、と。
もしきちんと使い続けるのであれば、きちんとライブラリのフォルダを作った方がいいと思います。本当はカレント優先でライブラリと両方見るようにする、とか、ライブラリのパスを環境変数から取ってきてテンプレートに書かなくてもよくする、とかいろいろ課題はありますが、追ってぼちぼち。
実例としまして、先日の今更だが JScript で VBScript の Inputbox を使う
でご紹介したWSC(Windows Script Component)のvbsWrapper2.wscをモジュール化して使う例をご紹介します。まずはラッパーモジュール。
// vbsの InputBox とか MsgBox とかをラップするWSC
// vbsWrapper2.wsc をCommonJS(風)モジュール化。
var vbs = GetObject("script:"+require.libpath+"vbsWrapper2.wsc" );
module.exports = {
InputBox: vbs.method_InputBox,
MsgBox: vbs.method_MsgBox
};
実にシンプルですね。ここで「なんちゃって」な部分を説明しておきます。
・exports非対応。module.exportsのみに対応。
・ライブラリのパスが欲しい時用にrequireにlibpathプロパティを追加してある。
require.libpathを使ってライブラリに置いたwscをインスタンス化してexportsにつないでます。
つづいてこのモジュールのテストプログラムです。
// JScript で VBScript の Inputbox を使う
///////////////////////////////////////////////////////////////////////////////
var global = Function("return this")(); // globalを設定&require 拡張。
var libpath = "./".replace("/","\\"); //←←←
(Function( 'context', 'path', (new ActiveXObject("Scripting.FileSystemObject")).
OpenTextFile( libpath + "require.js",1).ReadAll() ))(global,libpath);
///////////////////////////////////////////////////////////////////////////////
InputBox = require("vbsWrapper2").InputBox;
MsgBox = require("vbsWrapper2").MsgBox;
var data = InputBox("何か入力してくだされ。", "WSCサンプル2改", "ほげほげ");
MsgBox( data + " でござるか。", 32+2, "WSCサンプル2改" );
etude_wsc2.jsの頭にrequireおびを足して、コードを整理しました。
とりあえずおびはただの模様だと思えば、かなりすっきりしたと思います。
MS/WSHっぽさを薄めるには以下のように書いた方がいいかもしれません。
var vbs = require("vbsWrapper2").InputBox;
var data = vbs.InputBox("何か入力してくだされ。", "WSCサンプル2改", "ほげほげ");
vbs.MsgBox( data + " でござるか。", 32+2, "WSCサンプル2改" );
おまけにもうひとつモジュールのサンプル。これもシンプルですが大変重宝しています。
eval( (new ActiveXObject("Scripting.FileSystemObject")).
OpenTextFile( require.libpath + "json2.js",1).ReadAll() );
module.exports = JSON;
もちろんライブラリにjson2.jsが要りますが。
こんな感じで、今まで自分がいろいろ書いてきた小物をどんどんモジュール化して喜んでいるところです。そのうち数が増えて収拾がつかなくなるので、簡易ヘルプの仕組みなんかもあわせて考えていきたいと思っています。