AppleScript Programming Tips (5) Posted 2010-02-03 12:54:56 +0900
AppleScript Programming Tips (4) の続きを受けて、ユーザーが定義した命令(handler、ハンドラ)について書こうかと思いましたが、先に「オブジェクトの指定」について書こうと思います。オブジェクトを指定しないことには命令も送れないことですし。なんだか、順番が無茶苦茶だなとは思いますが...。
この文章は AppleScript Language Guide を基にしています。おかしな表現や間違い、文責は私にあります。
object specifier...なんて訳せばいいのでしょう。とりあえず、「object specifier」、もしくは「オブジェクトの指定」でいきます。AppleScript でどのようにオブジェクトを指定するのか?また、指定したオブジェクトを AppleScript がどのようにして認識するか?といったことについての話です。
オブジェクトの指定ということですが、オブジェクトの参照形式(reference form)とは違い、オブジェクトの指定は「オブジェクトの種類 + オブジェクトの場所 + オブジェクトの参照形式」の組み合わせからなります。
まず、基本的な事として AppleScript のオブジェクトは、たいていの場合他のオブジェクトに内包されています。オブジェクトを内包しているオブジェクトの事をコンテナ(container)といいます。例えば、file は folder に内包されていますし、folder は disk に内包されています。また、character や word、paragraph は text に内包されています。
object specifier は処理対象オブジェクトを同定するのに必要な情報を明示することです。
object specifier はスクリプトの実行時に評価(解決)されます。スクリプトのコンパイル時ではありません。例えば、以下のスクリプトはコンパイルはできますが、実行時にはエラーになります。
window 10000 of application "Finder"
また、アプリケーションは命令の結果として object specifier を返します。
window 1 of application "Finder"
--> Finder window id 858 of application "Finder"
オブジェクトのトップレベルのコンテナ(top-level container)はアプリケーションです。AppleScript がオブジェクトの指定を解決する時、命令の時と同じようにオブジェクトの継承関係をたどり、どのオブジェクトが指定されているのかを評価します。
object specifier はオブジェクトの種類(クラス)、オブジェクトの場所(オブジェクトを含むコンテナ)、そして、オブジェクトを識別する方法(参照形式、reference form)から成り立っています。
tell application "Script Editor"
paragraph 1 of document 1
end tell
このスクリプトはまず、オブジェクトの種類(paragraph)を指定しています。次にオブジェクトを含むコンテナ(document 1)を指定しています。が、tell でアプリケーションが指定されています。トップレベルのコンテナはアプリケーションですので正確にはアプリケーション Script Editor の document 1 がコンテナになります。そして、オブジェクトを識別する方法がクラスとインデックス参照の組み合わせになっています(paragraph 1)。
これらが評価されて「アプリケーション Script Editor の最前面のドキュメントの 1 行目」が指定されることになります。
AppleScript のオブジェクトはコンテナ(container)に含まれているものですが、コンテナもまたオブジェクトです。コンテナは 1 つ、または複数のオブジェクトや属性を持っています。目的のオブジェクトを探すにはコンテナを指定します。コンテナは of(または、in)で指定します。
例えば、Finder で Applications フォルダを指定するにはコンテナ(startup disk)を指定し、folder クラスを名前参照形式と組み合わせます(もちろん、他にも方法はあります)。
tell application "Finder"
folder "Applications" of startup disk
folder "Applications" in startup disk -- 上の行と同じ意味
end tell
一連のコンテナを指定して目的のオブジェクトを探すにはコンテナの一番深い部分から指定します。Application フォルダ内の Safari.app を指定したいなら以下のようになります。
tell application "Finder"
application file "Safari" of folder "Applications" of startup disk
(*
application file "Safari"
- クラスの種類と名前参照形式の組み合わせ
~ of folder "Applications" of startup disk
- コンテナの指定
コンテナは一番深いコンテナから指定し、上の階層を of(in) でつなぐ
*)
end tell
上記の of を使った指定は一番最初に「目的のオブジェクト」が記述され、そのあとに「コンテナ」、「コンテナ」...と続きます。
所有格(英語の「's」)をコンテナに用いることで一番深いコンテナから記述することもできます。
tell application "Finder"
startup disk's first folder's first file
startup disk's folder 1's file 1 -- こちらでも可
end tell
どちらがいいかは好みの問題です(個人的には同じことを様々な書き方で指定できることには疑問を覚えます。AppleScript の初心者がつまずきやすい部分だと思います)。
オブジェクトの参照形式(reference forms)についても触れておきます。AppleScript の参照形式は特定のオブジェクトを識別するためのもので、object specifier とともに使われます。参照形式には以下のものがあります。
- 任意参照
- 全要素参照
- フィルタ参照
- ID 参照
- インデックス参照
- 中央参照
- 名前参照
- 属性参照
- 範囲参照
- 相対参照
任意参照形式は複数のオブジェクトの中から任意のオブジェクトを参照します。
Syntax - Reference form Some(例文の記述法について)
some class
Parameters
- class
- 任意のクラス識別子。
tell application "Finder"
some file of folder "Applications" of startup disk
end tell
このスクリプトは実行の度に結果が変わると思います。任意参照は複数のオブジェクトの中からランダムにオブジェクトを指定する参照形式です。StandardAdditions.osax にランダムな数値を返す random number 命令がありますが、AppleScript を使う人たちの間ではいまいち人気がない。なぜかというと、スクリプティングアディションの呼び出しには時間がかかるから。頻繁にスクリプティングアディションの命令を呼び出すなら、代替方法を探す...というのは AppleScript 高速化 Tips のひとつですが...今もやっぱり有効なのかな?
全要素参照形式は、コンテナの中から指定したクラスのオブジェクトを全て参照します。
Syntax - Reference form Every(例文の記述法について)
every class
Parameters
- class
- 任意の class。もしくは class の複数形。
構文は some と同じように every の後にクラスを指定し、結果は指定したクラス(のオブジェクト)を含んだリストです。指定したクラスがなかったら空のリストを返します。
tell application "Finder"
every file of folder "Applications" of startup disk
end tell
AppleScript では頻繁に使う参照形式です。一括処理のときにお世話になります。全要素参照形式は every を使わず指定するクラスを複数形にする事もできます。
tell application "Finder"
files of folder "Applications" of startup disk
end tell
全要素参照形式を使うとリストの複製もできます(あまり使わないですが)。
set the_list to {1, 2, 3}
set new_list to items of the_list
set item 1 of the_list to "A"
{the_list, new_list}
フィルタ参照形式は、指定したコンテナの中から条件にあったオブジェクトを参照します。
Syntax - Reference form Filter(例文の記述法について)
whose | where | that) boolean_test
Parameters
- object_specifier
- 対象となるコンテナ内のオブジェクト。
- boolean_test
- 真偽値を返す式。
Result
リストの中から boolean_test を通ったオブジェクトのリスト。 boolean_test を通るオブジェクトがない場合、空のリストが返る。
条件式は真偽値を返すものになります。whose、where、that はどれを使っても同じです。返ってくる結果は条件に合致したオブジェクトのリストになります。
tell application "Finder"
files of folder "Applications" of startup disk that ¬
name starts with "A" -- 名前が「A」で始まる全てのファイル
end tell
このように全要素から条件式で一致するものだけを抽出します。強力なフィルタ参照なのですが、AppleScript のオブジェクト(リスト、レコード、テキスト...)には利用できません。利用できるのはアプリケーションのオブジェクトに対してだけです。また、アプリケーション側でも対応している必要があります。
-- Finder でズームしているウィンドウを戻す
tell application "Finder"
set zoomed of (windows whose zoomed is true) to false
end tell
このようにオブジェクトの属性を変更するときにも使えます。また、コンテナの指定を後置きにしてフィルタ参照の部分を簡潔に記述する事ができます。
tell application "Finder"
-- フィルタ参照を () で囲み、in でコンテナを指定
(files whose name extension is "scpt") in desktop
end tell
フィルタ参照形式は基本的に以下のような動きで処理を行っています。
- 対象となるコンテナ内の指定されたクラスのオブジェクトを全て取得する
- 上記の結果がリストとして返ってくる
- このリストの中からオブジェクトをひとつずつ取り出し、条件に照らし合わせる
- 全てのオブジェクトについて照合が終わる
- 条件に合致したオブジェクトをリストとして返す
例文として紹介しているスクリプトは省略した書き方です。省略部分を記述すると上記の流れが分かりやすくなります。
tell application "Finder"
files of desktop whose (name extension of it) is "scpt"
(*
- files of desktop を取得
- 結果のリストからひとつずつ取り出す
- it(記述を省略していた部分)が取り出されているオブジェクト
- 「name extension of it」は、 desktop の「ファイル某」の拡張子を取得している
- name extension of it is "scpt" が false のものは除去
- フィルタリングされた結果が返る
*)
end tell
「it」を省略していたのですが、あるとスクリプトが多少分かりやすくなります。
ID 参照形式は、オブジェクトの ID でオブジェクト参照します。最初にオブジェクトの ID の値が分かっていないと使えないもの参照形式でもあります。
Syntax - Reference form ID(例文の記述法について)
id expression
Parameters
- class
- 任意のクラス識別子。
- expression
- オブジェクトの id を表す値。
tell application "Finder"
disk id -100
--> startup disk of application "Finder"
name of disk id -100
--> "Macintosh HD"
end tell
AppleScript 2.0 以降なら ID 参照形式でアプリケーションと文字列を参照することができます。ID は数値で表される事が多いのですが、実際は決まっていません。アプリケーションオブジェクトは固有の ID を持っていますが、それは文字列です。
-- アプリケーション ID でアプリケーションを指定
if not (running of application id "com.apple.Mail") then
activate application id "com.apple.Mail"
end if
-- 文字列を id で取得
set the_text to "Hello, World"
set text_ids to id of the_text
--> {72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100}
--id からテキストを取得
string id text_ids
--> "Hello, World"
インデックス参照形式はコンテナ内の要素を数値で指定する参照形式です。
Syntax - Reference form Index(例文の記述法について)
integer (
st | nd | rd | th) class(
first | second | third | fourth | fifth | sixth | seventh | eighth | ninth | tenth) class(
last | front | back) class
Parameters
- class
- 任意のクラス識別子。
- integer
- 数値。
st|nd|rd|th- 1st、2nd、3rd...といった指定を行いたい時の用語。
set the_list to {"A", "B", "C"}
item 1 of the_list
--> "A"
tell application "Finder"
file 1 of desktop
end tell
set the_text to "Hello, World"
word 1 of the_text
--> "Hello"
word -1 of the_text
--> "World"
インデックス参照形式は数値にマイナス(-)をつける事で要素の最後から取得する事ができます。インデックス参照形式は絶対的な参照ではなく、相対的な参照です。状況により結果は変わります。
中央参照形式はコンテナの中から中央のオブジェクトを参照します。
Syntax - Reference form Middle(例文の記述法について)
middle class
Parameters
- class
- 任意のクラス識別子。
正直、使っているとこを見た事もないし、どういったときに使うといいのか分からないのですが...。
tell application "Finder"
middle file of desktop
end tell
名前参照形式は名前でオブジェクトを参照します。
Syntax - Reference from Name(例文の記述法について)
Parameters
- class
- 任意のクラス識別子。
- name_text
- オブジェクトの名前属性の値。
オブジェクトの名前というのはファイルならファイル名、ウィンドウならウィンドウのタイトル、フォルダならフォルダ名...といったようにそのオブジェクトが持っている固有(Finder 等が表示している)の名前の事です。
tell application "Finder"
window "書類"
end tell
絶対参照になるので例えば上記のスクリプトなら「書類」というタイトルのウィンドウがない場合、エラーになります。
属性参照形式はオブジェクトの属性を取得する時に使う参照形式です。
Syntax - Reference form Property(例文の記述法について)
Parameters
- property_label
- オブジェクトが持っているプロパティ(属性)。
tell application "Finder"
zoomed of window 1
--> false
end tell
オブジェクトがどのような属性を持っているかはアプリケーションの「用語説明」を見て確認します。
tell application "Script Editor"
properties of word 1 of paragraph 2 of front document
--> {class:text, color:{0, 0, 65535}, size:12.0, font:"Courier"}
end tell
オブジェクトの全ての属性を取得するには properties を使います。しかし、properties は AppleScript のオブジェクトには使えません。
範囲参照形式はコンテナの中から範囲を指定してオブジェクトを参照形式します。
Sytax - Reference form Range(例文の記述法について)
thru end_index of object_specifier
Parameters
- class
- 任意のクラス識別子。
- start_index
- 要素の始まりの位置を表す整数値。
- end_index
- 要素の終わりの位置を表す整数値。
- object_specifier
- コンテナオブジェクト
記述はいろいろありますが、構文確認時に上記の形式に変換されるのでこれを覚えておくといいと思います。
set int_list to {101, 31, 49, 98, 56, 71}
integers 2 thru 4 of int_list
--> {31, 49, 98}
この範囲指定をよく使うのは文字列から部分文字列を取り出す時でしょう。
tell application "Finder"
set the_file to name of file 1 of desktop
--> "Active.app"
set num to offset of "." in the_file
text 1 thru (num - 1) of the_file
--> "Active"
end tell
相対参照形式は、あるオブジェクトからの相対でオブジェクトを参照します。
Syntax - Reference form Relative(例文の記述法について)
before | [in] front of) base_specifier[class] (
after | [in] back of | behind) base_specifier
Parameters
- class
- 任意のクラス識別子。
- base_specifier
- 基準となるオブジェクト。
tell application "Finder"
file before file 3 of desktop
file in front of file 3 of desktop
end tell
あまり使う事がないのですが...(というか、使う事のない参照形式の方が多いのですが)。
AppleScript では以上のような参照形式を使って特定のオブジェクトを指定します。
最後に オブジェクトの指定と reference オブジェクトについて。reference オブジェクトというのはいわゆる「ポインタ」で、object specifier を reference オブジェクトでラップしたものです。
reference オブジェクトは a reference to 演算子で作成します。
on run
set file_list to desktop_files()
--> every file of desktop of application "Finder"
tell application "Finder"
-- 利用したいときに中身を取り出す
file_list as text
name of file_list
set file_list to contents of file_list
repeat with this_file in file_list
contents of this_file
end repeat
end tell
end run
on desktop_files()
tell application "Finder" to a reference to files of desktop
end desktop_files
reference オブジェクトは実際に利用したいときに中身を取り出してから利用するので、その時までの動作を軽くする/速くする効果があります。ただ、オブジェクト指定やオブジェクトの参照を保持しているだけなので実行時に対象オブジェクトが変わる事があります。以下のスクリプトでは iTunes で同じ曲名が表示されると思います。
tell application "iTunes"
activate
set current_track to current track
display dialog (get name of current_track)
--> "Head Down"
next track
display dialog (get name of current_track)
--> "Head Down"
end tell
しかし、reference オブジェクトを使うと正しい曲名が表示されます。
tell application "iTunes"
activate
set current_track to a reference to current track
display dialog (get name of current_track)
next track
display dialog (get name of current_track)
end tell
reference オブジェクトから中身を取り出すには reference オブジェクトの属性 contents を利用します。
tell application "Finder"
set window_ref to a reference to Finder window 1
-- Finder window 1 of application "Finder"
-- object specifier
contents of window_ref
-- Finder window id 460 of application "Finder"
-- object specifier を評価した結果
get window_ref
-- Finder window 1 of application "Finder"
-- object specifier
end tell
get 命令では object specifier を評価しません(reference オブジェクトが得られる)。