ExtendScript Isolator (ただしコンセプトデザイン)

たとえばJavascriptでCSアプリのなにかしら処理を書く場合.「こういうデータがあって,こういうふう(みための変更だったりテキスト出力ファイルだったり)にしたい」というインプットとアウトプットがあるわけです.実際の処理をかくときはこのインプットからアウトプットまでの道程をコードという断片でつないであげるということになるんだとおもいます.つまりスクリプト処理ってものは小さなスクリプト処理のあつまりととらえられるといえるかもしれません.

唐突なのですが以下の動画をまずは.

ミキサー(したの段にあるUREIとかいてあるもの)とアイソレータ(うえの段に鎮座する3つのツマミがついてるやつ)をいじくってる動画なんですが,"High", "Mid", "Bass"のそれぞれのツマミをいじくると特定の音域が無くなったり強調されたりしちゃってますよね.

あんまり詳しいことをかくとなんの記事だかわからなくなっちゃうので省略しますが,アイソレータは「音域を分離するもの」と考えていただければいいかとおもいます.つまり「高い音」「まんなかの音」「低い音」の3つにわけて,それを個別にあつかえるものです.

(ちなみにイコライザってものもあるのですが,もともと音色って幅広い周波数の波形をもっているので,それを個別に調整するってものです.アイソレータはその特定音域の逆位相の波形を使って打ち消したり・もちあげたりするので根本的な仕組みが異なります)

前おきが長かったんですが,今回のおはなしではこの「分離する」ってのがキーです.

つまりスクリプト処理そのものを小さなスクリプト処理ごとに分離して書けるようにしてしまおうというおはなしです.まずはInDesign向けのこんなソースをば.

sample1.jsx

//step1
"組版単位とかマージン・段組などのアプリケーションの初期設定をする"

//step2
"ドキュメントがなければ新規で作成,開いているドキュメントがあればそれを処理の対象にする"

//step3
"対象になるドキュメントのページ数を表示する"

jsxとありますがテキストが書いてあるだけです.これが分離された状態.このファイルをつぎのように書きかえまっせ.

sample2.jsx

#target InDesign
#include "/path/to/isolator.jsx"

//step1
"組版単位とかマージン・段組などのアプリケーションの初期設定をする".define("/path/to/初期設定.jsx");

//step2
"ドキュメントがなければ新規で作成,開いているドキュメントがあればそれを処理の対象にする".define(function(){
	var doc;
	return doc
});

//step3
"対象になるドキュメントのページ数を表示する".define(function(doc){
	alert(doc.pages.length+"ページあるよ");
});

EasyScript.execScript();

おや? なにかがヘンですね.で,気にせずこんなかんじにします.

sample3.jsx

#target InDesign
#include "/path/to/isolator.jsx"

//step1
"組版単位とかマージン・段組などのアプリケーションの初期設定をする".define("/path/to/初期設定.jsx");

//step2
"ドキュメントがなければ新規で作成,開いているドキュメントがあればそれを処理の対象にする".define(function(){
	var doc;
	if(app.documents.length==0){
		doc = app.documents.add();
		alert("新規ドキュメントを追加したよ")
	}else{
		doc = app.activeDocument;
		alert("いま開いているドキュメントを対象にするよ");
	}
	return doc
});

//step3
"対象になるドキュメントのページ数を表示する".define(function(doc){
	alert(doc.pages.length+"ページあるよ");
});

EasyScript.execScript();

しれっとisolator.jsxをincludeすると,こんな具合にかけますよ.sample1.jsxの段階のものを実際にはスクリプトがかけないオペレータさんから「こんなことやりたいな」とこんなかんじでもらえればそれを埋めながらスクリプトをかいていけます.しかも小さい処理の内容はコメントじゃなくてテキストそのまま.おーDSLじゃん!! defineの引数にはコードをそのまま書いたり,外部ファイルを指定したりもできるように.

分離できるとはいうけれど,分離する基準は様々です.難易度であったり使いまわしするってのが基準だったり.つかい方いろいろな「めんつゆ」状態ですね.

こんな邪悪なことができるislator.jsxのソースは以下です.

//Extend Script Isolator
//すこしだけDSLっぽくindesign javascriptをかけるようにする

EasyScript = {};
var FUNCS = this.FUNCS = {};

//コメント兼関数名を定義するのに
String.prototype.define = function(fn){
	var name = this;
	if(fn instanceof Function){
		FUNCS[name] = fn;
	}
	//Functionオブジェクトじゃなければファイルパスとして扱う
	else{
		var file = new File(fn);
		if(file.open("r")){
			try{
				var c = file.read();
				FUNCS[name] = eval("("+c+")");
				file.close();
			}catch(e){alert(e);alert("'"+name+"'は実行エラーっぽいから無視したよ")}
		}else{alert("'"+name+"'はファイルを読み込めなかったぽいから無視したよ");}}};

//定義されたすべての関数を実行
EasyScript.execScript = function(arg){
	var p = null;
	if(arg!=null) p = arg;
	for(var k in FUNCS){
		if(p!=null){
			p = FUNCS[k](p);}
		else{
			p = FUNCS[k]();}}};

//defineした関数の中でつかうことで途中でとめることができるよ
EasyScript.interrupt = function(){
	alert("EasyScript: 中断しました");
	exit();}

どちらかというと「ざっくりとスクリプト処理のプロトタイプをつくりたい」みたいなときにつかえたりするかもしれません.じぶんはそうしてます.

あともっと重要なのはこれがDTPスクリプティングアジャイル開発へのヒントになるかもってことです.つかいまわしできるものはモジュールに,DTPDRY原則でいきまっしょいというアイデアの出発点だとおもっております.