DTPab

印刷やデザイン、アドビ製アプリやスクリプトなど、雑多な技術ブログ

ESTKのtargetengineの挙動

ESTKのプリプロセッサディレクティブ、#targetengineについて少し調べたのでメモ。当然すべてInDesignでの検証です。

動的にエンジンを変更できるか

以下のコードをテスト。

#targetengine hoge
alert($.engineName);
var a = "Hello";

#targetengine fuga
alert($.engineName);
a += " World!";

#targetengine main
alert(a);

結果は、エンジン「main」で実行され、最後の行で問題なく?「Hello World!」と言われる。
また、#targetengine mainコメントアウトすると、動作するエンジンが「fuga」になるため、どうやらコード内に記述されたtargetengineは最後のものが優先されるらしい。

#targetengineevalしてはどうか?

#targetengine hoge
alert($.engineName);
var a = "Hello";

eval('#targetengine fuga');
alert($.engineName);
a += " World!";

eval('#targetengine main');
alert(a);

こうするとエンジン名は「hoge」となる。スクリプト実行前にコードが読み込まれた段階で、実行するエンジンは決定されるもよう。

全部evalだと?

eval('#targetengine hoge');
alert($.engineName);
var a = "Hello";

eval('#targetengine fuga');
alert($.engineName);
a += " World!";

eval('#targetengine main');
alert(a);

こうするとエンジンは「main」。コード内にtargetengineの指定がないと見なされ、mainで実行される。

prototype拡張がエンジンをまたぐか?

3つのスクリプトを用意して、InDesignから順に実行する。

hoge.jsx

#targetengine hoge
String.prototype.hoge = function (string){
    return this + string;
}

hogeAlert.jsx

#targetengine hoge
alert("ふが".hoge("ほげ"));

fugaAlert.jsx

#targetengine fuga
alert("ふが".hoge("ほげ"));

結果は、

  • hogeAlert>成功
  • fugaAlert>エラー

となるので、prototype拡張をしても、targetengineを分ければグローバルな汚染は防げる。想定した通りだったのでちょっと安心した。

まとめ

  • スクリプト内に#targetengineが複数定義してある場合、最後に記述されたものがそのスクリプトのエンジンになる
  • スクリプト内に#targetengineが定義されていなかった場合、mainエンジンになる(当然)
  • #targetengineは後から動的に変更できない
  • prototypeチェーンは#targetengineごとに保存される=エンジン間で汚染されない

動的にtargetengineが変更できればいろいろおもしろいなぁと思って実験したのですが、まぁそうですよね、という結果でしたね。
prototype拡張を行う場合はtargetengineを指定したほうが安全かなーという印象。まぁそもそも一回使っておしまいというのがDTPスクリプトなので、そこまでシビアに考えなくてもいいのかなという気はしますが。

今回は自分用のメモ書きなので部分部分の細かい説明は割愛させてもらいました。

追記【5/28 18:15】

またまたあるふぁ(仮)さんに追検証していただき、InDesignApplication.doScriptメソッドでは異なるtargetengineを指定できると教えていただきました。
その後自分でも検証を重ねていたのですが、なんだか妙なことになりました。

#targetengine 'hoge'
alert($.engineName); //hoge

app.doScript("""#targetengine 'foo'
alert($.engineName); //foo
""");

これは確かに動的にtargetengineを変更します。しかしdoScriptの中のtargetengineの前で改行してしまうと結果が変わります。

#targetengine 'hoge'
alert($.engineName); //foo

app.doScript("""
#targetengine 'foo'
alert($.engineName); //foo
""");

かなり怪しいです。ちなみに、似たようなことをevalメソッドでやると

#targetengine 'hoge'
alert($.engineName); //hoge

eval("""#targetengine eva
alert($.engineName);""") //hoge

に対して

#targetengine 'hoge'
alert($.engineName); //eva

eval("""
#targetengine eva
alert($.engineName);""") //eva

となります。
ここまでやって、僕はtargetengineは後から定義しないほうがよい、という結論に至りました。要するに、スクリプト冒頭でtargetengineを指定するオーソドックスなやり方以外は、書き方次第で結果が変わってしまう可能性があるので避けたほうが良いということです。

これは後からjsxincファイルをincludeする際にも同じことが言えて、jsxincファイルにはtargetengineなどは指定しないほうが(万が一不具合が起きた場合の検証のしやすさを鑑みて)良いだろうということです。後からtargetengineをどうこうするということを、スクリプトの設計として想定されていないのではないかな、と思いました。
したがって、僕個人は「targetengineを動的に操作する」ということを今後一切しないことにします。
首を突っ込んで調べてみるものですね。勉強になりました。