2016-04-06T22:11:33+09:00

AppleScript : ハンドラにレコードを渡そう

AppleScript の位置パラメータ形式のハンドラの引数としてレコードを用いると、

という話をします。

AppleScript のハンドラの復習

まず、AppleScript のハンドラの復習から始めましょう。AppleScript の用語では、他のプログラミング言語で関数やサブルーチンと呼ばれているものは、ハンドラと呼ばれます。AppleScript のハンドラは、大きく分けて二つの形式で定義できます。

位置パラメータ形式のハンドラ

on handler_positional_param(param1, param2)
(* some code *)
end handler_positional_param

これは、説明するまでもないですね。引数は、その定義した順番で特定されます。

ラベル付きパラメータ形式のハンドラ

on handler_labeled for param1 given a_label:param2
(* some code *)
end handler_labeled

引数の前にラベルを配置して、位置パラメータ形式のように順番ではなく、ラベルでパラメータを特定します。ラベルとしては、定義済みのラベルとして、for, above など幾つかの英語の前置詞が定義されています。given 以降では、ユーザー定義のラベルを使用することができます。

ラベル付きパラメータ形式のハンドラは難しい

位置パラメータ形式では、パラメータの数が増えると、各パラメータの意味と順番が不明瞭になります。そこで、ラベル付きパラメータ形式を使って、英語として意味が通って可読性の高いハンドラを定義したいと試行錯誤するのが、アップルスクリプターの一度は通る道だと思います。僕も、かつてはそんな幻想を抱きましたが、もう諦めました。これから、ラベル付きパラメータ形式は不恰好で、使いにくい代物であるので、ラベル付きパラメータ形式のハンドラは棄て去りましょう、という話をします。

まず、定義済みのラベルである前置詞群だけで英語風のハンドラを定義するのは至難の技です。というか、無理です。AppleScript Language Guide にはかっこいいサンプルがありますが、あのように都合良く定義できることは稀です。ほとんどのケースでは不恰好なものしかできず、試行錯誤に無駄な時間を費やすのがオチです。

given を使って、ユーザー定義ラベルのみを使えば、若干ましな気がします。でも、given って冗長ではないですか?後述する位置パラメータにレコードを渡す方式のほうがシンプルです。

もう一つ、ラベル付きパラメータ形式を避ける理由があります。あるハンドラの返り値がスクリプトオブジェクトであるとします。ラベル付きパラメータ形式の場合、ハンドラの返り値のスクリプトオブジェクトのハンドラを実行するのが煩雑になります。

handler2 of (handler1 of a_scrpt for param1) for param2

位置パラメータ形式の場合、's でハンドラの呼び出しを数珠つなぎにできるので書くのも読むのも、こちらのほうが明快です。

a_script's handler1(param1)'s handler2(param2)

このように、ラベル付きパラメータ形式には多くの欠点が存在し、後述する位置パラメータへレコードを渡すことで位置パラメータ形式の欠点を克服できます。僕は、XModules で公開している AppleScript モジュールのいくつかで、ラベル付きパラメータ形式を使っていますが、激しく後悔しています。全部、位置パラメータ形式に直してしまいたい衝動にかられます。

あなたは、まだ、それでもラベル付きパラメータ形式のハンドラを使いますか?まあ、余計なお世話ですね(^_^;A。

位置パラメータにレコードを渡す

次のように、位置パラメータ形式のハンドラにレコードを渡すようにすれば、引数の意味が不明瞭という位置パラメータ形式の欠点を克服することができるとおもいませんか?さらに、呼び出し側の見た目だけではなく、ハンドラの定義側でも引数の定義にレコードを設定することができます。こうすれば、レコードの中から値を拾ってくる手間がなくなります。

on say_hello({name:nm, message:msg})
return msg & ", I'm " & nm
end say_hello

say_hello({name:"Taro", message:"Hello"})
--resut: Hello, I'm Taro

ちなみに、この書き方は僕のオリジナルだと思っていましたが、そうではないようで AppleScript Language Guide で、Handlers with Patterned Positional Parameters としてドキュメント化されていました。昔の AppleScript Language Guide には、ありませんでした。いつ頃から登場したのだろう。

AppleScript Language Guide では、結構複雑な Patterned Positional Parameter が紹介されていますので、参照されることをお勧めします。

擬似オプション引数

オプション引数とは、サブルーチン側で引数のデフォルト値をもち、省略可能な引数のことです。AppleScript には引数の数を可変にする機能はないので、類似の機能を求めれば、リストやレコードなどのコレクションをパラメータとすること他ありません。

レコードをパラメータとすると、そのラベルに対応したデフォルト値の定義とレコードからの値の取り出しが、とてもスマートに行えます、というのが本邦初公開のオリジナルテクニックです。

サンプルを見ていただければわかるように、引数のデフォルト値をレコードで定義します。そのレコードと引数を結合することにより、引数に不足しているラベルをデフォルト値から補います。そのレコードをさらに、レコードに代入することにより、レコードからの値の取り出しを一気に行えます。

on say_hello(args)
set {name:nm, message:msg} to ¬
args & {name:"Taro", message:"Hello"}

return msg & ", I'm " & nm
end say_hello

say_hello({})
--resut: Hello, I'm Taro

say_hello({name:"Jiro"})
--result: Hello, I'm Jiro

say_hello({name:"Jiro", message:"Hey"})
--result: Hey, I'm Jiro

ハンドラの書き方に大きな影響を及ぼすテクニックだと思うのですが、いかがでしょうか?すくなくとも、無様なラベル付きパラメータ形式のハンドラとオサラバできるきっかけになれば幸いです。