前回までの AppleScript Programming Tips を読み返していて...こりゃだめだと反省。リファレンスはいらないですね。ということでリファレンスじみたことはやめます。すいませんが記事を修正、削除しました。リファレンスの方は別にまとめようかと画策中です。今回は load script 命令。run script、store script とくれば、load script 命令にも触れないわけにはいきません。
load script 命令というのは既にあるスクリプトを読み込んでスクリプトオブジェクトとして利用するための命令...言い換えると、既存のスクリプトを使い回して楽をするために必須の命令です。
少し、話が横道にそれますが...基本的には AppleScript のスクリプトって使い捨てだと思います。動けばそれでいいし、目的を達成できればそれで十分です。多くの人にとって AppleScript はそういうもので、既存のスクリプトを使い回すという概念があまり浸透していないように思えます。
多くのスクリプトが使い回すことを前提に組み立てられていません。多くのスクリプトは以下のような感じではないでしょうか。
tell application "Finder"
set selected_items to selection
if selected_items is {} then return
try
repeat with this_item in selected_items
set locked of this_item to not (locked of this_item)
end repeat
end try
end tell
Finder で選択している項目のロックを ON/OFF するスクリプトです。直線的なスクリプトです。もちろん、これでいいですし、エラー処理はしていませんがきちんと動きます。私の環境でもこのようなスクリプトが大部分を占めています。
AppleScript のいいところは、このような気楽な書きなぐりのようなスクリプトで十分目的を達成できるというところです。目的を達成できれば、これ以上スクリプトを保守/管理する気は起きません。次にこのスクリプトを開いて中身をみるのはいつになることか...。
また、AppleScript というのは個人の環境に強く依存するプログラム言語です。私に必須のスクリプトが必ずしもあなたに必須のスクリプトではないのです。なぜなら、AppleScript がアプリケーションを操作するための言語だからです。私は OmniOutliner を使ってこの書類を書いています。しかし、あなたは違うでしょう。私が何らかのアプリケーションを欲するとき、AppleScript に対応しているかどうかを気にかけますが、あなたはそうではないでしょう。
個人の環境に強く依存する AppleScript は、同時にスクリプトの書き方にも影響しています。
ハンドラの記述の仕方、参照の記述の仕方、命令の使い方、文字列の組み立て方、繰り返しの使い方、変数の命名方法、グローバル変数を多用するかどうか、ローカル変数を明示するかどうか等々...、様々なスクリプトを見てきましが、多種多様です。
AppleScript は同じことでも複数の書き方ができるため個性的なスクリプトが多いです。個性的なスクリプトを記述する人ほど、他人のスクリプトをそのまま使うことに忌避感を覚えます。このことが、使い回せるスクリプト(ライブラリ、モジュール)が公開されても利用されることがないことの遠因なのでは?思います。
駄法螺ですが。少なくとも自分自身にはそのような傾向があるかなと思います。
閑話休題。上記の Finder 項目のロックのトグル処理のスクリプトを開いて中身をみることがいつになるかは分かりませんが、Finder の選択項目に何らかの処理を施すスクリプトはそのうちにまた作ると思います。例えば、選択項目をゴミ箱に移動する、選択項目にラベルを付ける、選択項目の名前を変更する...。
スクリプトを使い回せるようにするにはどうすればいいのか、Finder の選択項目の処理を例に少し考えてみましょう。
tell application "Finder"
set selected_items to selection
if selected_items is {} then return
repeat with this_item in selected_items
set label index of this_item to 1
end repeat
end tell
このスクリプトは選択項目のラベルをオレンジ色にするスクリプトです。このスクリプトを見て、いくつかのことに気がつくと思います。
- 繰り返しの中身だけがロックのトグル処理のスクリプトと異なる
- 選択項目の処理というのは(エラー処理を入れていないものの)定型文だ
これらの部分です。スクリプト再利用の鍵となるのは処理の細分化です。個々の処理をハンドラで切り離せるかどうかを考えることがスクリプト再利用の第一歩です。まず、繰り返しの中身の処理はハンドラにすることができます。
tell application "Finder"
set selected_items to selection
if selected_items is {} then return
repeat with this_item in selected_items
my label_orange(this_item)
end repeat
end tell
on label_orange(this_item)
tell application "Finder"
set label index of this_item to 1
end tell
end label_orange
on toggle_lock(this_item)
tell application "Finder"
set locked of this_item to not (locked of this_item)
end tell
end toggle_lock
ロックのトグル処理もハンドラにしました。たかだか一行の処理をハンドラにすることもないのでは?と思うかもしれませんが、ハンドラとはこういうものなのです。では、「選択項目の処理というのは定型文」という部分を考えてみましょう。選択項目の処理に毎回毎回この定型文をコピペするなり、記述するなりするのでしょうか?
それはなんだか面倒だ、と思ったならこの部分もハンドラにしてしまってください。
on process_Finder_selection()
tell application "Finder"
set selected_items to selection
if selected_items is {} then return
repeat with this_item in selected_items
my label_orange(this_item)
end repeat
end tell
end process_Finder_selection
on label_orange(this_item)
tell application "Finder"
set label index of this_item to 1
end tell
end label_orange
on toggle_lock(this_item)
tell application "Finder"
set locked of this_item to not (locked of this_item)
end tell
end toggle_lock
単にハンドラにしただけです。ですが、これでは使い勝手が悪いです。繰り返しの部分を毎回書き変える必要があります。この部分を目的に応じてほかのハンドラに差し替えれるようにできれば、もう少し使い勝手がいいものになります。
property action : missing value
on run
set action of me to label_orange
my process_Finder_selection()
set action of me to toggle_lock
my process_Finder_selection()
end run
on process_Finder_selection()
tell application "Finder"
set selected_items to selection
if selected_items is {} then return
repeat with this_item in selected_items
my action(this_item)
end repeat
end tell
end process_Finder_selection
on label_orange(this_item)
tell application "Finder"
set label index of this_item to 1
end tell
end label_orange
on toggle_lock(this_item)
tell application "Finder"
set locked of this_item to not (locked of this_item)
end tell
end toggle_lock
これで個々のハンドラはそれぞれ単一の処理を行うようになりました。今のところ、このことがどのような意味を持っているのかが分かりにくいかもしれません。しかし、使い回すことを考えながらスクリプトを作っていると、その利点が分かってくることと思います。
上記のスクリプトをデスクトップに FinderUtility.scpt として保存しておきます。load script 命令を使ってスクリプトを読み込んでみます。
load script 命令は AppleScript ファイルを引数にとり、file 参照か alias で指定します。ファイルはコンパイル済みスクリプトかアプリケーション形式で保存したスクリプトファイルです。実行専用で保存されたアプリケーションでもかまいません。返り値はスクリプトオブジェクトです。
set the_object to load script (choose file of type {"scpt", "app", "scptd"} without invisibles)
--> «script»
では FinderUtility.scpt を読み込み、選択項目の処理をしてみましょう。
set the_folder to path to desktop as text
set the_file to the_folder & "FinderUtility.scpt"
set FinderUtility to load script file the_file
tell FinderUtility
-- 選択項目のラベルをオレンジに
set action of it to label_orange of it
process_Finder_selection()
delay 1
-- 選択項目のラベルをなしに
set action of it to label_none of me
process_Finder_selection()
end tell
on label_none(this_item)
tell application "Finder"
set label index of this_item to 0
end tell
end label_none
FinderUtility.scpt を読み込んで、action 属性に実際の処理を記述したハンドラを設定し、processFinderselection ハンドラを呼べばいいだけです。action 属性に設定するハンドラは別段どこのスクリプトにあってもかまいません。ここでは同一のスクリプト内に書いていますが、ハンドラだけを別のスクリプトに保存しておき load script 命令を使って読み込んだものでもかまいません。
ちなみに、ハンドラに引数としてハンドラを渡さないのはどうしてなのか?
on run
my process_Finder_selection(label_orange)
end run
on process_Finder_selection(action)
tell application "Finder"
set selected_items to selection
if selected_items is {} then return
repeat with this_item in selected_items
try
my action(this_item)
on error m number n
display dialog {n, return, return, m} as text
end try
end repeat
end tell
end process_Finder_selection
on label_orange(this_item)
tell application "Finder"
set label index of this_item to 1
end tell
end label_orange
これだとエラーになるからです。このエラーを回避するためにハンドラをいったんスクリプトオブジェクトの属性におさめ、その属性を参照するようにしています。スクリプトの実行時にハンドラを動的生成し、処理を切り替えるときによく使われるテクニックです。他にもハンドラにスクリプトオブジェクトを渡して処理を行うというのもよく使われるテクニックです。
script FinderAction
on do_action(this_item)
tell application "Finder"
(* 何らかの処理 *)
log "Call do_action of FinderAction"
end tell
end do_action
end script
script SEAction
on do_action(this_item)
tell application "System Events"
(* 何らかの処理 *)
log "Call do_action of SEAction"
end tell
end do_action
end script
on run
tell application "Finder"
set selected_items to selection as alias list
if selected_items is {} then return
repeat with this_item in selected_items
my do_action(this_item, SEAction)
my do_action(this_item, FinderAction)
end repeat
end tell
end run
on do_action(this_item, this_object)
this_object's do_action(this_item)
end do_action
このような使い方は AppleScript ではあまりしませんが、トリッキーなものではありません。知っていると、スクリプトでできることの幅が広がりますし、保守/管理も楽になります。
0 件のコメント :
コメントを投稿