Scripting Bridge

Scripting Bridge 面白い。普通(?)の AppleScript に飽きた人はぜひ。以下、覚え書き(環境は Mac OS X Leopard。当然だけど...)。なんで Python なのかは秘密です。

Terminal.app を起動して、

$ python

と、打ち込む。インタープリタが起動するので、まず、以下の呪文を唱える。

>>> from ScriptingBridge import *

これで、Scripting Bridge に関するモジュールが取り込まれるので、次に操作したいアプリケーションオブジェクトを作成する。

>>> finder = SBApplication.applicationWithBundleIdentifier_("com.apple.finder")

Python: unknown type name "ICN#"... と、ずらずら出てくるけど、気にしない。Finder の home にあるフォルダを取得してみる。

>>> homeFolders = finder.home().folders()
>>> for thisFolder in homeFolders:
...     thisFolder.name()
... 
u'Applications'
u'backup'
u'Desktop'
u'Documents'
u'Downloads'
u'Library'
u'Movies'
u'Music'
u'Pictures'
u'Public'
u'Sites'

おほぅ(おほぅって...)。でました。って、ここまでくるのに結構時間がかかっていたり。ちょっと、違和感がある。name() なんて書かれてると、属性を取得しているように見えない。なぜか分からないし、調べてもいないのだけど、Python では属性の取得でも () が必要みたい。

フォルダでも作ってみる。まず、Foundation を取り込む。

>>> from Foundation import *

まず、フォルダの属性を辞書で作る。

prop = {'name' : 'testing'}

この属性からオブジェクトを作る。

>>> folder = finder.classForScriptingClass_("folder").alloc().initWithProperties_(prop)

これは、Objective-C ですね。init で作っているけど、メモリとかどうなるのか知らない。ガベージコレクションがあるからいいか。そして、作る。

>>> finder.desktop().folders().addObject_(folder)

ここではデスクトップに作ってみました。Finder には make 命令があるのに、なぜ make 命令を使わないか?

実は、Scripting Bridge では操作するアプリケーションのオブジェクトを作れないのです。folder を作ったではないか、と思うかもしれませんが、Finder のオブジェクトではないのです。

>>> type(folder)
<objective-c class SBProxyByClass at 0x19e15e0>

SBProxyByClass というものなんですね(SB という接頭辞は Scripting Bridge のこと)。で、結局、Finder のデスクトップにあるフォルダのリスト(配列。SBElementArray)を、まず、取得するのです。そして、このリストに追加するのです。すると、Finder でフォルダが作成されるのです。なぜか。

Objective-C マジックですな。

しかし、insertObject:atIndex: が使えないんですね。iTunes のサンプルでは使えるようですが。だから、ここでは addObject:。

先の name() ではないですが、Objective-C のメソッドを使うのに Python では、アンダースコアを使う必要があるみたい。

insertObject_atIndex_(folder, 0)
addObject_(folder)

といった感じ。コロンをアンダースコアに置き換えるのかな(ちゃんとドキュメント読みなさいって)?

Finder で一番使うものって selection でしょう(勝手に決めつけていますが)。この selection は悩みました。だって、リストが返ってくると思うじゃないですか。

>>> curSelection = finder.selection()
>>> type(curSelection)
<objective-c class SBObject at 0x19e1560>

なんで、SBObject なの?

selection を取得して繰り返しで処理...みたいなことをどうやって書くのか悩んだね。全く。結局、以下のようにすればいいのでした。

>>> for thisItem in curSelection.get():
...     print thisItem.name(),
... 
music top testing

SBObject の get メソッドを使ってオブジェクトの参照を取得するとタプルで選択項目が返ってくるので、これを使って処理をすればいいということみたい。

繰り返して処理するためには set 命令が使えないといけない。が、set 命令はそもそも使えない。どうやるのかといえば、以下のようにする。

>>> curSelection = finder.selection()
>>> for thisFolder in curSelection.get():
...     thisFolder.setLocked_(1)
... 
>>>

オブジェクトが持っている属性(locked)に set をくっつけて続く属性の先頭文字を大文字にする。setLocked_(value) となる。name 属性なら setName(value)、label index 属性なら setLabelIndex(value) となる。value はそれぞれ、真偽値や整数値などの属性が受け取る事ができる値になります。

とりあえず、オブジェクトの作成と属性の取得、変更ができました。最低限はいちおう分かったのですが、ScriptingBridge で使えることができるアプリケーションの命令やオブジェクトなどはどうやって調べるといいのか?

Script Editor で表示される用語辞書だと楽でいいのですが、利用できるものに違いがあるのでそうもいきません。スクリプタブルアプリケーションがもっている用語辞書を Objective-C のヘッダファイルに変換することで Scripting Bridge で利用できるオブジェクトや属性を調べる事ができます。

Terminal.app を起動し(先ほどの Python インタープリタのままなら Control - D でインタープリタを終了させます)。おもむろに、以下のようにタイプ。

$ sdef /System/Library/CoreServices/Finder.app | sdp -fh --basename Finder --bundleid com.apple.Finder

これでカレントディレクトリに Finder の Objective-C ヘッダファイルが作成されます。このファイルを開くとクラスやメソッドが確認できます(他のスクリプタブルアプリケーションの場合は...って上記を見ればだいたい分かる...かな?)。

以上、Python での Scripting Bridge でした。コードをいろいろ見てみましたが、Objective-C でも Ruby でもそんなに大差はないような感じですね。しかし、上記のような Python のサンプルの少ないこと、少ないこと。PyObjCappscript はたくさんあるのに...。

参考

思い出

高木重朗の「マジック入門」は思い出深い書籍である。

この書籍を読んでいなければ、手品に興味を抱くこともなかったと思う。

しかし、小学生にとってこの書籍はあまりにも難しすぎた。だって、1980 年頃だべ。地方都市だべ。近くにそれを実演して見せてくれる人もいないのだべ。

クラシック・パームなんて本当にできるのか?本当に手品の種がこんなものなのか?これが、本当の手品の秘密なのか?といった疑問に答えてくれる人など周辺には皆無だった。

案の定、長い間クラシック・パームのやり方を間違えていた...。

今ならこれら全ての疑問に答えることはできるし、この書籍の価値も分かる。だからこそ思うのだけど、子供には高度だよな、と。

だけど、この書籍で覚えて今でもよく行う手品がある。輪ゴムを使ったものとキー・カードを使ったそれである。

子供の頃にいろんな人に行った。こちらがびっくりするほどに見せた相手は驚愕する。「なんでこんな当たり前のことがふしぎなんだろう?」。「なにが不思議なんだろう?」と、子供心に奇妙に思ったことを良く覚えている。

手品の種ってそんなものなんだけど。

(明かしたくなる誘惑はあったけど)種は明かさなかった。

この書籍、本当に内容が高度で難しかった。本当にこんなことできるのか?とたびたび考えては飽かず読んでいた。しかし、子供のことである。興味は次第に他のことに移り、読む頻度も少なくなり、いつか、捨ててしまった。

今、思えば「すげー、もったいない」ことをしたものである。本当の価値が分からなかったのである。今、読みたいと思っても既に絶版になっている(わりと手に入りやすい古書の部類だけど)。

私にとって思い入れの深い書籍なのである。いまなら、インターネットが身近なものになり、手品の専門的な書籍だって簡単に手に入れる事ができるし、実演だって YouTube などで簡単に見る事ができる。

素朴にうらやましいと思う。

この書籍と出会った小学生のあの頃、どれだけこれらの情報に渇望していたことか。隔世の感がある...。

現在の情報過多に批判的な向きもあるけど、情報が無いよりはいいのである。情報をどう利用するかは使う人の問題であって、情報それ自体に良いも悪いもない。

とはいうものの、現在の自分がこの情報過多の中にあって子供の時より手品に情熱を燃やしていたり、満足したりしているのかといえば、そうでもなかったりするのが「言ってることとやってることが無茶苦茶じゃん」というところなのだけど。この辺りが人間という生き物の面白いところでもある。

人間を「矛盾を内包しているもの」と表現したのは誰だっかか?

...と、とりとめもないことを書いたけど、たまにはこういうのもいいかな?

Language Guide

新版の AppleScript Language Guide は、内容としては Mac OS 9 から Mac OS X 10.4 でも通用するものだけど、Mac OS X 10.5 Leopard 以降の AppleScript 2.0 をベースに書き直されている。

用いられている説明は AppleScript 2.0 でのもので、以前のバージョンのことと対比しながらの説明は行われていない。このドキュメントが対象としているのは Leopard 上の AppleScript 2.0。もし、以前のバージョンの詳細を知りたければ、AppleScript Release Notes (Mac OS X 10.4 and earlier) を見よ、とある。

のっけから愕然としてしまいますね。

さて、新版の最初の章は Introduction というタイトルで AppleScript の紹介を行っていますが、先に書いたようにこのドキュメントが AppleScript 2.0 以降を対象にしていることを確認しておけば十分ですね。

次の章が AppleScript Lexical Conventions。AppleScript 言語の概観といった体裁になっています。以下、駆け足で。

まず、AppleScript が扱うキャラクターセットのことについて書かれています。どんな文字を使って AppleScript を記述する事ができるか?ですが、ご存知の通り AppleScript 2.0 はユニコードに対応してしまったので『正しく全世界の文字を扱う事ができる』らしいです。

つまり、スクリプト内のコメントや文字列定数に各国の言語を使うことができるということですね。もちろん、私は信じませんが。

AppleScript の構文は半角アルファベットと、いくつかの特殊記号で記述します。特殊な記号というのは文の継続を表すソフトリターンとか、AppleScript で定義されていない生のデータを表す «» とかのことです。

AppleScript で変数やクラス、属性のラベルを識別する文字列について。これらは半角英数字とアンダースコアで定義します。

AppleScript では変数の大文字小文字を区別しないので以下のような変数は全て同じものを表します。

myName
MyName
myname

ところで、Script Editor で以下のようなスクリプトを書いて構文確認を行います。

set myName to "Alan"

一度 myName として変数を定義し構文確認を行うと、以降スクリプトの他の場所で myname と小文字で書いておいても構文確認時に myName と変数名を最初に出てきた変数名にあわせてくれます(大文字小文字を変換し、最初に出てきたものに合わせるのです)。これは、便利な反面、面倒な自体も引き起こします。

もし、MyName と変数を定義しておいてから myName に変更したいと思っても構文確認時に MyName に変換してしまいます。MyName を myName に変えたいなら、スクリプトの中に出現する全ての MyName を削除してから Script Editor を終了し、再度スクリプトを開き、myName をタイプしていかないといけない。変数名の後からの変更ってちょっと面倒なのです(そんなことない?)。

閑話休題。また、数字で始まる変数は利用できません。以下は、利用できない変数の一例です。

9th_item
C-
Try&Error
Do^and^Don't

しかし、AppleScript にはどんな文字列でも変数に利用してしまうことができる秘密の方法があります。縦棒(|)を文字列の前後に付け加えると、半角英数字とアンダースコア以外の文字や記号でも変数として扱うことができます。

|9th_item|
|C-|
|日本語|
|Love\|and\|Peace|

日本語でも構いません。これらは全て変数として扱えます(実際に使うかどうかは別にして)。変数の中に縦棒(|)を含みたい時は、最後の例のようにバックスラッシュでエスケープします。

こんなもの使う場面があるのか?とお思いになるかもしれません。時々見かけるのは、レコードのラベル名での利用。また、既に他のアプリケーションでその語彙がクラスとして定義されている場合など、衝突を避けるために利用したりします。

Script Editor で開く

tell application "Finder"
    set |folders| to folders of home
end tell

このサンプルはサンプルのためのサンプルですが、スクリプトオブジェクトを作っているとこういう場面がままあります。

そして、予約語。AppleScript では全ての予約語がアルファベット小文字だけで構成されています。また、いくつかの予約語は aside from のように単語のペアになっているものがあります。以下、予約語の一覧。

apart from, and, against, after, above, about, before, back, at, aside from, as, around, between, beside, beneath, below, behind, beginning, contains, contains, contain, considering, by, but, else, eighth, does, div, copy, continue, exit, every, error, equals, equal, end, from, fourth, for, first, fifth, false, ignoring, if, global, given, get, front, its, it, is, into, instead of, in, my, mod, middle, me, local, last, or, onto, on, of, not, ninth, ref, put, property, prop, over, out of, second, script, returning, return, repeat, reference, tell, some, sixth, since, seventh, set, through, third, then, the, that, tenth, true, transaction, to, times, timeout, thru, with, whose, while, where, until, try, without

AppleScript のコメントについて。PDF の方の AppleScript Language Guide 間違ってますね。

コメントには複数行のコメントと一行だけのコメントの 2 種類あります。

Script Editor で開く

(*
    This is the comment.
    AppleScript Guru?
    Ha, ha, No!!
    I am a AppleScript fanatic believer!
*)

これが複数行にわたるコメントの書き方でコメントの前後を (* と *) で囲みます。

一行コメントは文頭にマイナス記号を 2 つつけます。

Script Editor で開く

-- one liner

AppleScript 2.0 以降ではシャープも一行コメントに使えます。

Script Editor で開く

# 一行コメント
#!/usr/bin/osascript

シャープ(#)が使えるのは最後の例のようにシェバングとしての利用を考慮したものだと思われます。このコメントは AppleScript 2.0 以前でもコンパイル済みスクリプトを実行するだけならそのまま利用できます。しかし、Script Editor などでスクリプトを開き、編集などを行うとこのコメントはエラーを発生させます。実際に確認はしていませんが、シャープで始まるコメントがあるスクリプトを Mac OS X 10.4 などに持っていても実行する分には支障はないのですね。ただ、編集時にはエラーになると。

コメントはネストさせることができます。

Script Editor で開く

(*
This is the comment.
AppleScript Guru?
Ha, ha, No!!
I am a AppleScript fanatic believer!
-- one liner
# 一行コメント
#!/usr/bin/osascript

    (*
        これもコメント
    *)
*)

コメントってネストできました?知りませんでした。

AppleScript は、冗長です。或は、冗漫といってもいいかもしれない。冗長と冗漫。どちらも同じような意味かもしれない。

AppleScript は、英語に似た文法を持つため、どうしても一行の記述が横に長くなっていきます。こういうときにソフトリターンを使って一行を分割する事ができます。

Script Editor で開く

tell application "Finder" to ¬
    folders of home

最初の行の最後にある「¬」が次の行の継続を表すソフトリターンです。見た目は二行ですが、AppleScript は一行として解釈します。「¬」は、Option + l(小文字の L )で入力できます。

ちなみに、この継続を表すリターンは Option + Return で入力できるはずなのですが、日本語環境では化けた文字が挿入されます。これは、継続を表すものではないのでエラーになります。

だから、Option + l で継続行を挿入。その後に実際に Return キーで改行とする必要があります。二度手間です。むかしは、Option + Return が使えたのに...。

以降、この章はもう少し続くのだけど、あくまでこの章は全体的な概観なので詳しいことはそれぞれ別の章に記述されている。後々、重複してくることになるし、AppleScript 2.0 だからといって見るべきところはないので割愛。