DTPab

DTPにまつわるあれこれ

もくもく会#2のおさらい

dtpmkmk.connpass.com

本日、無事に「DTPerのスクリプトもくもく会 #2」が開催されました。
会場をお貸しくださったMD5500さん、そして参加してくださった皆様、ありがとうございました。
次回は9月開催の予定です。近づいた頃Twitterやブログで告知しますので、よろしくお願いします。

さて、以下は今日いただいた質問のおさらいです。

スクリプトを実行する際に変数を覚えておきたい

例えば以下のような単純なスクリプトを例にみてみます。

var myDoc = app.activeDocument;
var myTxtPref = myDoc.textPreferences;
var myHighlightOption = {
    "subFonts": myTxtPref.highlightSubstitutedFonts,
    "subGlyph": myTxtPref.highlightSubstitutedGlyphs,
    }

/* 処理A */

with (myTxtPref){
    highlightSubstitutedFonts = false;
    highlightSubstitutedGlyphs = false;
    }

alert("代替フォント:"+myTxtPref.highlightSubstitutedFonts+"\r代替字形:"+myTxtPref.highlightSubstitutedGlyphs);

/* 処理B */

with (myTxtPref){
    highlightSubstitutedFonts = myHighlightOption.subFonts;
    highlightSubstitutedGlyphs = myHighlightOption.subGlyph;
    }

これは組版ハイライト機能の一部のオン・オフを切り替えるスクリプトです。
まず最初にactiveDocumentの「代替フォント」と「代替字形」の組版ハイライト設定をmyHighlightOptionという変数に代入しています。変数をそれぞれ用意してあげる形でも当然よいのですが、今回はJSONJavaScriptオブジェクト記法)を用いて変数の管理をすっきりさせてみました(JSONについては後ほど)。
そして現在の設定を変数myHighlightOptionに覚えさせたら、一旦ふたつをfalseにします。本来やりたい処理が間に入っているという想定です。確認のためにalertで設定値を覗いています。
最後に、スクリプトの処理を終えたらドキュメントの設定を元に戻してあげる、という命令を入れておしまいです。ふたつの設定を予めオンにしてから実行すると処理の流れが分かりやすいと思います。

ただ、これは1つのスクリプトで完結させる場合を想定したものです。
コード中の「処理A」と「処理B」が同一のスクリプトでなかった場合にはまた違った処理が必要です。要するに、前半の「ドキュメント設定に手を加える処理」と後半の「元の設定に戻す処理」が別々のスクリプトだった場合です。

というわけで、先程のスクリプトを2つに分割してみます。

/*-- script A --*/
var myDoc = app.activeDocument;
var myTxtPref = myDoc.textPreferences;
var myHighlightOption = {
    "subFonts": myTxtPref.highlightSubstitutedFonts,
    "subGlyph": myTxtPref.highlightSubstitutedGlyphs,
    }

/* 処理A */

with (myTxtPref){
    highlightSubstitutedFonts = false;
    highlightSubstitutedGlyphs = false;
    }
/*-- script B --*/
var myDoc = app.activeDocument;
var myTxtPref = myDoc.textPreferences;

/* 処理B */

with (myTxtPref){
    highlightSubstitutedFonts = myHighlightOption.subFonts;
    highlightSubstitutedGlyphs = myHighlightOption.subGlyph;
    }

こんな感じにして、InDesignからスクリプトAのあとにBを実行してみてください(ESTKから実行すると変数が保持されて違う結果になる場合があります)。
結果はスクリプトBがエラーで実行できないはずです。エラーは変数myHighlightOptionが存在しないというものですが、宣言していないので当然です。

では、今度はこの2つのスクリプトの1行目に、以下の1文を加えてください。

#targetengine "testScript"

その上で、改めてInDesignからふたつのスクリプトを実行してみてください。今度はエラーなく実行できたと思います。
変数の宣言をしていないスクリプトBがエラーなく実行できるのが少し不思議かもしれませんが、これが「ターゲットエンジン」の指定です。

ターゲットエンジンを「main」以外に指定すると、スクリプトは処理が終わってもメモリを解放しません。要するに、一度定義した変数などをわざわざ解放(≒削除)しない限り、ずっと覚えておくようになります。また、同じターゲットエンジン間で変数を共有できるようになるのです。
このお陰で、スクリプトAで宣言した変数を、スクリプトBで呼び出す、といったことが可能になります。

ただ注意してもらいたいのは、変数が使い回せるということがリスクになる可能性もあるということです。同じエンジンで動くスクリプトが複数あると、たまたま同じ名前の変数を定義してしまった、ということが起こり得ます。また、同じエンジンのスクリプト同士で変数の宣言があったりなかったりするために、後々見返した際に変数の宣言場所が分からなくなったりします。とにかく変数の扱いには細心の注意を払い、変数の出どころ=宣言元をコメントアウトするなどして対応する必要があるでしょう。

JSONについて

今日のもくもく会ではJSONについての詳しい説明は省いてしまいました。基本的にはWikipedia等を参考にしてもらいつつ、大事なところだけ。
JSONとは以下のような形でオブジェクトを指定します。

var myCar = {"maker": "HONDA", "name": "ODESSEY", "color": [255, 255, 255]}

これを取り出すには、

$.writeln (myCar.maker); //HONDA
$.writeln (myCar["color"]); //255,255,255

オブジェクトのプロパティのように取り出す方法(前者)と、連想配列のように取り出す方法(後者)があります。
このときの「maker」「name」「color」をキー(key)、「HONDA」「ODESSEY」「white」をそのキーに対する値(value)といいます。
JSONではキーを文字列型として宣言する必要があります。例えば、

var myCar = {maker: "HONDA", name: "ODESSEY", color: [255, 255, 255]}

このように宣言することも可能ですが、これは厳密にはJSONとして誤りです。キーは文字列型、ということは意識しておいてください。
連想配列と先述しましたが、このmyCarオブジェクトは下記のように宣言することもできます。

var myCar = {};
myCar["maker"] = "HONDA";
myCar["name"] = "ODESSEY";
myCar["color"] = [255, 255, 255];

普通の配列と連想配列が違うところは、連想配列lengthプロパティを持たないということです。つまり普通のfor文で順繰りに中身を取り出すといったことができません。連想配列の中身を取り出す場合は、for…in文を使います。

for (key in myCar){
    $.writeln (key + " : " + myCar[key]);
    }

ここで注意すべきなのは、定義した順で取得できるかどうかは担保されないという点です。
この例では「maker」「name」「color」という順で定義しましたが、for…in文は順番を考慮しません。取り出す際に定義した順番で取り出せるかどうかは保証されていないのです。

このfor…in文は、何も連想配列のためのものではなく、その他のあらゆるオブジェクトのプロパティを取得することができます。例えば、

for (key in app){
    $.writeln(key + " : " + app[key]);
    }

こうするとappのプロパティをまとめて取得できる、という具合です。

うむむむ、想定していたよりも長くなっていまいました^^;;
もくもく会の成果もついでに発表しようかとも思っていたのですが、それはまた今度のエントリーに譲りたいと思います。

改めまして、次回もくもく会もどうぞご贔屓に〜♪