DTPab

DTPにまつわるあれこれ

InDesign 15.0.2 コミュニティスクリプトを紐解く 4

仕事が「霧の中を航行する船が突然海賊に襲われた」みたいな状態になっていて毎日やばいです。こんばんは。

仕事がそんななので遅くなってしまいましたが、今回は下記の記事の続きになります。

はじめに

Adobeのヘルプだけでは心許ないので、中身をざっと解読してみました。その上でなるべく条件を整理してみたものです。間違いがあればご指摘ください。

InsertTypographerQuoteシリーズ

機能の説明

選択したテキストの前後に引用符を挿入します。
挿入される引用符がスクリプトごとにそれぞれ異なります。

スクリプト名末尾 引用符 左 引用符 右
Double_CH » «
Double_DE
Double_EN
Double_FR « »
Single_CH
Single_DE
Single_EN
Single_FR

また、選択したテキストの末尾が改行文字(CR:U+000D)の場合はその手前に引用符が入るようになっています。

前提条件

テキストを選択した状態でスクリプトを実行します。

注意点

  • 選択したテキストの末尾が改行文字以外の分割文字の場合(例えば強制改行 LF:U+000Aとか)は分割文字の後ろに引用符が入ります
  • 挿入される引用符は、選択したテキストの末尾のスタイルが適用されます f:id:uske_S:20200320230303p:plain

InsertTypographerQuoteシリーズへの雑感

実は言語ごとにこんなに引用符にバリエーションがあるとは知りませんでした*1
それはそれとして、中身を書き換えるとテキストを鉤括弧「」などで括ることができます。

f:id:uske_S:20200321224358p:plain

お好みカスタマイズ

60〜102行目にその設定があって、下記のように設定が並んでいます。

//French
//SetQuotes.QUOTES_START = "\u2039";  //  < 
//SetQuotes.QUOTES_END = "\u203A";  // >

// English
SetQuotes.QUOTES_START = "\u2018"; 
SetQuotes.QUOTES_END = "\u2019"; 

これらの中で、先頭が//始まらない行が設定として生きている*2ので、その部分をまず探してください。末尾 _EN であれば// Englishの部分のどちらか(ダブルクォーテーション用とシングルクォーテーション用の2つがあります)*3がコメントアウトされていない状態になっています。
そのコメントアウトされていない行を見つけたら、SetQuotes.QUOTES_STARTSetQuotes.QUOTES_ENDに好きな値を設定することで、好みの括弧で括るスクリプトにカスタマイズできます。

括弧
"\u301C"
"\u301D"
"\uFF08"
"\uFF09"
"\u300E"
"\u300F"

ご覧のように、各文字のコードポイントを""で囲み、先頭に\uを付けてもらえればOKです。
起こし括弧をSetQuotes.QUOTES_START、受け括弧をSetQuotes.QUOTES_ENDに設定してもらえれば、お好みの括弧で括るスクリプトにできます。

SetQuotes.QUOTES_START = "\u301C";  // 「 
SetQuotes.QUOTES_END = "\u301D";  // 」

末尾にコメント(上記例文の// 「など)を残しておくとあとで確認しやすいのでおすすめです。

コードの話

以下、技術的な話になるので興味のない方は末尾の「おわりに」まで飛ばしてください。ここからは僕のお気持ち表明です。

このスクリプト、すごくがんばって実装したって感じがしてそこは好感を持ちました。僕がこの作者だったら、初めてこれが動いたとき感動したはず。それくらい苦労の跡が見えるスクリプトです。
ただどうしても「どうしてこんな実装を?」みたいなところがあります。これはコードをこき下ろすためではなくて、このスクリプトが半ばAdobe公式のものとして手に入る現状、これをお手本にスクリプトの勉強をしてほしくないという思いから書きます。

コンストラクタ呼び出しを使う意図が読めない

このスクリプトにはnew演算子を付けて関数を呼び出す、コンストラクタからインスタンスを生成する方法が使われています。オリジナルなコンストラクタを用意してそこからインスタンス化することで、プロパティやメソッドを継承してオブジェクトを生成できたり、instanceofメソッドでインスタンスを比較できたりとまぁ確かにメリットはあるのです。ただこのスクリプトに関してはコンストラクタを作ってそれを呼び出すこれらのメリットがほとんど生きていません(と、僕は感じました)。

if文の入れ子がもったいない

if (hoge){
    if (fuga){
        // 必要な処理
    } else {
        alert("fugaではないエラーです");
    }
} else {
    alert("hogeではないエラーです");
}

if文でこういう例外処理が行われているのが非常にもったいないと感じました。これをやるとネストがどんどん深くなるし、どの警告文がどの条件分岐に対応したメッセージなのかも分かりにくくなります。

if (!hoge){
    alert("hogeではないエラーです");
    return;
}
if (!fuga){
    alert("fugaではないエラーです");
    return;
}
// 必要な処理

関数内なので、こういう形で条件に合致しないものは適宜returnで処理を終わらせてしまいます。そのほうがシンプルで読みやすいはずです。
蛇足ですが、コミュニティスクリプトの中ではUnicodeInjectorが例外処理のやりかたが効率的で面白かったです*4

オレオレprototype拡張

スクリプトの冒頭でArray.exists()メソッドをプロトタイプ拡張しているのですが、それってやっていることはArray.some()メソッドやArray.includes()メソッドですよね…。すでにそうしたメソッドが新しいECMAScriptで定義されているので、せっかくならそうしたものをポリフィルするほうが自分の勉強にもなるしおすすめです。

Array.prototype.exists = function (x) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] == x) return true;
    }
    return false;
}

このコードの何が問題かというと、if (this[i] == x) return true;です。そもそも厳密比較演算子すら使ってない。いや、意図的にそうしている可能性もなくはないのですが、それでもexistsなんてメソッド名なので、配列の中に任意の要素が存在するかどうかを判定したいわけですよね。であればfalse0や空の文字列が横並びに真と判定されるこのコードは問題と言わざるを得ません。
あとこれはお作法になりますが、Adobeから大規模に配布されるようなケースが想定できなかったとはいえ、このコードをコピペして誰かが使わないとも限りません。そういうときのために、同じ名前のプロトタイプ拡張がすでに実装されているかどうかは予防線を張っておいたほうが良いです。

if (!Array.prototype.exists) {
    Array.prototype.exists = function (x) {
    ……

という形で実装したほうがいいのかなと思います。

おわりに

本旨から逸れるので最後の部分はあまり書きたくなかったのですが、このスクリプトについてはちょっと目に余るものがあったので触れる程度に書かせてもらいました。
そうはいっても使い方次第(特にカスタマイズしちゃうと)便利に使えるスクリプトなのでぜひお試しください。
これも蛇足になりますが、特定の括弧文字でテキストを括るスクリプトとエクステンションをよそいちさんが公開されています。

blue-screeeeeeen.net

僕はエクステンション版を使ってますが、とても便利です。

それではまた次回。

*1:I Love Typesetting: InDesignによる欧文組版の基本操作その4
コントヨコさんのブログ記事。非常にわかりやすく引用符を説明してくださっています

*2:より正確には、// 以降はコメントアウトになるので読み込まれないということです

*3:CH:Swiss、DE:German、EN:English、FR:French

*4:最後にまとめて例外メッセージを設定しておき、switch文で分岐させています。あとからエラーメッセージを変更するとか追加する際も、最後にまとまっているのでメンテしやすいなと思いました