f

2016-08-20

Python "if __main__" in Node.js and WSH JScript

Pythonでは現在のプログラムが実行されていることを判別する構文がある。

if __main __ == "__main__":
print("module is runninng")
else:
print("module is included")

__main__という特殊変数に,そのファイルが実行されていれば,"__main__"という文字列が格納されていることを利用している。

これにより,ライブラリとして読み込んだ時と実行時とで処理を分けることができる。この構文により,例えば実行したらテストを動したり,サンプルの処理を行うことができ,そのファイル(ライブラリ)自体の動作の説明を行うことができる。ライブラリとして使うことを想定するプログラムでは便利だ。

この構文をJavaScript(Node.jsとJScript)で実現する。

if __main__ in Node.js

Node.jsでは以下のどちらかの構文により実現できるようだ。

if(require.main === module) {
  cocnsole.log('main module');
}
if(!module.parent) {
  console.log('main module');
}

参考:node.js equivalent of python's if __name__ == '__main__' - Stack Overflow

if __main__ in JScript

JScriptであれば,WScirpt.ScriptNameプロパティに現在実行中のプログラムのファイル名が入っているので,これを利用する。例えば,以下のように記述する。

// \file hi.js

if (WScript.ScriptName === "hi.js"){
WScript.Echo("Hello");
}

Node.jsでの例と違い,自分自身のファイル名をハードコード(直接入力)しなければならず,少しいまいちなやり方となってしまう。しかし,こうしなければならない。つまり,以下のようにNode.jsでの例と同じように変数名の有無で判定すると,親から読み込んだ場合でも実行されてしまう。

if (WScript.ScriptName){
WScript.Echo("Hello");
}

なぜなら,親から実行した場合には,WScript.ScriptNameには親のファイル名が入っているからだ。

これを確かめるには,以下のサンプルファイルを実行すればわかる。

/// \file is_sample_main.js

if (WScript.ScriptName){
  WScript.Echo('Failure');
}

if (WScript.ScriptName === "is_sample_main.js"){
  WScript.Echo("Not shown");
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- \file is_sample_main.wsf -->
<package>
  <job>
    <script language="JScript" src="is_sample_main.js"></script>
 </job>
</package>

上記2ファイルを作成して,is_sample_main.wsfをダブルクリックか以下のコマンドでコマンドプロンプトから実行する。

cscript.exe -nologo is_sample_main.wsf
Failure

is_sample_main.wsfでは,is_sample_main.jsを読み込んで実行しているので,is_sample_main.wsfは親ファイルとなる。そのため,WScript.ScriptNameで条件分岐させた処理は実行してほしくない。しかし,WScript.ScriptNameだけの条件分岐に入り,実行されてしまっていることがわかる。

参考:javascript - JScript - How to know if the script was activated using WSH or internally by another script? - Stack Overfl

Create Library

ここまでで,Node.jsとWSH JscriptでPythonのif __main__ == "__main__"を実現する方法を示してきた。ただ,毎回手作業で書くには少々長い。そこで,これを実現する関数を作ってライブラリ化してみる。

/****************************************************************************
 \file      is_main.js
 \author    SENOO, Ken
 \copyright CC0
*****************************************************************************/

function is_main(this_file_name){
    return (typeof(module ) !== "undefined" && !module.parent    ) ||
      (typeof(WScript) !== "undefined" && WScript.ScriptName === this_file_name)
}

if (typeof(print) === "undefined"){  // for SpiderMonkey
  function print(text){
    if      (typeof(console) !== "undefined") console.log(text );
    else if (typeof(WScript) !== "undefined") WScript.Echo(text);
  }
}

if (is_main("is_main.js")){
  print("Hello");
}

上記のis_main.jsでは,is_main関数を定義している。引数に自分自身のファイル名を渡せば,Node.jsとWSH Jscriptの両方のif __main__ "== __main__"を評価してその結果を返してくれる。汎用化させるために,条件式の最初にNode.jsやWScirptが使えるかどうかを判定している。

また,後半では以前以下の記事で作成したprint関数を再掲している。これにより,コード末尾の自分自身が実行されている時だけメッセージを表示させることを,Node.jsでもWSH Jscriptでも動作するようにしている。

参考:My Future Sight for Past: JScriptのWScript.Echo()とJavaScriptのconsole.log()の共通化

Conclusion

JavaScriptであるNode.jsとWSH JScriptで,ライブラリ自体が実行されているかを判別するPythonのif __main__ == "__main__"を実現する方法を紹介した。今後これらの言語でライブラリを作成するときは活用してみたいと思う。今回紹介したコードはgistでも公開しているので必要に応じてダウンロードしてほしい。

GitHub GIst: Python "if __main__" in Node.js and WSH JScript

0 件のコメント:

コメントを投稿