ハンドラ
ハンドラはスクリプト内の_メッセージリスナー_です。オブジェクトはスクリプトを持ち、スクリプトはハンドラを持ちます。オブジェクトは特定のメッセージを受け取り、それを処理するためには、そのメッセージのハンドラへのアクセスを持つ必要があります。メッセージの詳細については、Messagesを参照してください。
オブジェクトの動作は、それが送信される可能性のある異なるメッセージをどのように処理するかによって定義されます。オブジェクトがメッセージを受け取ると、それは応答し、スクリプト化されたアクションを実行しますが、それは特定のメッセージのための_ハンドラ_を持つスクリプトを持つ場合に限ります。すべてのスクリプトは、オブジェクトが処理に興味を持つさまざまなメッセージのための1つ以上のハンドラで構成されています(スクリプトの_初期ハンドラ_を含む、これはスクリプトと同じ名前のメッセージを処理します)。オブジェクトが一致するハンドラを持たないメッセージを受け取る場合、それはそのメッセージを無視します。
SenseTalkスクリプトは_ハンドラ_で構成されています。ハンドラは、スクリプト が特定のメッセージが送信されたときに何をするかを定義するスクリプトの一部です。主なハンドラのタイプは3つあります:コマンドハンドラ(時々_on_ハンドラと呼ばれます)、関数ハンドラ、および_汎用ハンドラ_(または_to_ハンドラとも呼ばれます)。また、特殊なタイプのハンドラである_getProp_と_setProp_ハンドラもあります。これらはPropertiesで説明されています。
ハンドラの種類
コマンド、関数、および汎用ハンドラ
メッセージハンドラの主要なタイプは3つあります:汎用、コマンド、関数ハンドラ。汎用ハンドラは to handle
(または単純に to
)で始まり、コマンドと関数のメッセージを両方処理できます。簡単にするために、コマンドと関数のメッセージを異なる方法で処理する特別な必要がある場合を除いて、常に汎用ハンドラを使用してください。コマンドハンドラは on
という単語で始まり、コマンドによって送信されたメッセージを処理します。コマンドハンドラは通常、一連のアクションを実行します。関数ハンドラは function
という単語で始まり、関数呼び出しのメッセージを処理し、値を返します。
コマンドハンドラも値を返すことがあり、関数ハンドラも値を返すことに加え てアクションを実行することがあることに注意すべきです。ハンドラのタイプ間の唯一の実質的な違いは、それらが処理するメッセージの種類です:コマンドハンドラは関数メッセージの結果として決して実行されませんし、関数ハンドラはコマンドメッセージによって決して呼び出されません。
スクリプトが同じメッセージ名のための汎用ハンドラ(to
)と特定のハンドラ(on
またはfunction
)の両方を含む場合、特定のハンドラが常に優先され、メッセージを受け取ります。 to
ハンドラはまだ他のタイプのメッセージを受け取ります。スクリプトが特定のメッセージに対してすべての3種類のハンドラを含む場合、 on
ハンドラはその名前のコマンドメッセージを受け取り、 function
ハンドラは関数メッセージを受け取り、 to
ハンドラは決して呼び出されません。
以下に、 greetTheUser
メッセージのための非常に単純なハンドラを示しま す:
to greetTheUser
put "Welcome to SenseTalk. Happy scripting!"
end greetTheUser
To*
, To Handle
キーワード
動作: to
またはto handle
キーワードは、コマンドメッセージと関数メッセージの両方を受信できる一般的なハンドラを宣言します。ハンドラが呼び出された方法によって異なるアクションを取る必要がある場合、messageType
関数を使用してハンドラがコマンドとして呼び出され たか、関数として呼び出されたかを調べることができます。
スクリプトが_messageName_に一致するコマンドメッセージまたは関数メッセージを受信すると、このハンドラの_statements_が実行されます。ハンドラに渡される入力パラメータの値は、_messageName_に続いて宣言された対応するパラメータ名(paramName1 , paramName2, paramNameN)に割り当てられます。
構文:
to {handle} messageName {{with | of | given} {a | an | the} paramName1 {, paramName2 ...} }
statements
end [messageName | handler | to {handle}]
例:
to handle increaseSize given amount
if amount is empty then add 1 to my size else add amount to my size
end increaseSize
On キーワード
動作: on
キーワードはコマンドハンドラを宣言するために使用され、end
キーワードはそれを終了します。
オブジェクトが_handlerName_に一致するコマンドメッセージを受信すると、そのハンドラのステートメントが実行されます。ハンドラに渡される入力パラメータの値は、_handlerName_に続いて宣言された対応するパラメータ名(paramName1 , paramName2, paramNameN)に割り当てられます。
構文:
on handlerName {{with | of | given} {a | an | the} paramName1 {, paramName2 ...} }
statements
end [handlerName | handler | on]
以下の例では、addToTotal
コマンドハンドラを定義しています。メッセージでパラメータが渡されると、その値はnewAmount
変数で利用可能です、それ以外の場合はその変数は空になります。
例:
on addToTotal newAmount
add newAmount to global total -- Store total in a global variable
end addToTotal
Function
キーワード
動作: function
キーワードは関数ハンドラを宣言します。スクリプトが_functionName_に一致する関数メッセージを受信すると、このハンドラの_statements_が実行されます。ハンドラに渡される入力パラメータの値は、_functionName_に続いて宣言された対応するパラメータ名(paramName1 , paramName2, paramNameN)に割り当てられます。_returnValue_は関数呼び出しの値として呼び出し元のスクリプトに返されます。
構文:
function handlerName {{with | of | given} {a | an | the} paramName1 {, paramName2 ...} }
statements
return returnValue
end [handlerName | handler | function]
例:
function getTotal
return global total
end getTotal
初期ハンドラ
to
、on
、function
キーワードで始まる明示的に宣言されたハンドラに加えて、スクリプトには初期ハンドラがあります。これはスクリプトの最初(スクリプトの最初の部分でのプロパティ宣言をスキップした後)から最初の明示的なハンドラまたはプロパティ宣言までの全てのステートメントで構成されます。初期ハンドラタイプは実際には最も一般的で、明示的なハンドラがない任意のスクリプトは初期ハンドラです。「スクリプト」と呼んでいるものは実際には初期ハンドラです。
初期ハンドラは、ジェネリックな to handle
タイプのハンドラとして扱われ、スクリプトと同名(拡張子と不正な文字を除く)の任意のメッセージを処理し、コマンドメッセージと関数メッセージの両方に応答することができます。名前が無いオブジェクト(スクリプトファイルからロードされるのではなく、スクリプト内のプロパティリストとして作成されるもの)の場合、初期ハンドラは run
コマンドまたは関数を使用して呼び出すことができます。スクリプトファイル以外のオブジェクトには、初期ハンドラは <initialHandler>
という名前が割り当てられます。
初期ハンドラにパラメータを宣言する唯一の方法は、params declarationを使用することです。
スクリプトが実際にスクリプトと同名のハンドラ(たとえば "to handle scriptFileName
")を含む場合、そのハンドラが優先され、最初の名前付きハンドラに至るまでのスクリプトの初期行は無視されます。
メッセージがディスク上のスクリプトオブジェクトに送信されると、SenseTalkはそのスクリプトファイルを読み込み、スクリプトをメモリにキャッシュします。その後、オブジェクトが別のメッセージを受け取ると、SenseTalkは非常に素早くそのメッセージのハンドラがあるかどうかを確認することができます。稀に(かなり稀ですが)、実行中でSenseTalkにスクリプトの更新をチェックさせたい場合があります。このような状況では、the watchForScriptChanges
グローバルプロパティを true に設定することができます(デフォルト設定は false です)。これにより、オブジェクトがメッセージを受け取るたびにSenseTalkがファイルの更新をチェックします。ファイルが更新されている場合、再度読み込まれ、新しいハンドラが使用されます。ハンドラの実行バージョンは、実行中は変更されません。
受け渡されたパラメータの受信
ハンドラが呼び出しスクリプトからパラメータを受け取ることを期待している場合、それはメッセージ名の後(またはハンドラ内の最初の行にある params
declaration に)これらのパラメータの変数をリストアップすることができます(特に初期ハンドラで役立ちます)。
パラメータは、順番に、または名前付きパラメータとして受け取ることができる key:value ペアを使用して渡すことができます。シーケンシャルなパラメータはあなたが期待するように動作します - それらはパラメータを順番に渡し、呼び出されたハンドラはその順番でこれらの値を受け取るように設定されている必要があります。名前付きパラメータは、ハンドラ内でその名前でプロパティ値を参照できる key:value ペアを使用します。これにより、その方法で情報にアクセスします。異なるパラメータがどのように渡されるかについての詳細は、Parameters and Resultsを参照してください。
例:
以下は、ゼロ除算を最初に確認した後、2つの数値の商を計算する基本的な関数ハンドラの例です。この例では、dividend
とdivisor
という単語は商のハンドラ内でローカル変数として扱われ、最初の2つの連続したパラメータからすでに初期値が割り当てられています。
function quotient of dividend, divisor
if divisor is zero then return zero
else return dividend/ divisor
end quotient
例: 連続したパラメータの受け取り**
この例では、連続して渡された3つのパラメータが、呼び出されたハンドラの宣言で3つの対応するパラメータ変数に受け取られる方法を示しています:
castSpell "sleep", 12 hours, "deep" --これは、3つのパラメータを連続して渡す呼び出しコマンドです
to castSpell spellName, duration, potency --連続して渡されたパラメータは順番に受け取られ、対応するパラメータ変数に挿入されます
//スペルを発動するための作業:
Put duration and potency into Cauldron
Stir Cauldron --スペルを実行するカスタムコール
Log "Alakazam!: " & spellName --スペルが発動されたことを確認するメッセージ
end castSpell
連続したパラメータの割り当てについての詳細は、Sequential Parameter Assignmentをご覧ください。
例: 名前付きパラメータの受け取り**
この例では、単一のプロパティリストがby name
に続いて渡される方法を示しています。この方法では、各キーの値がハンドラの宣言行で対応するプロパティ変数に挿入されます:
castSpell {spellName:"sleep", potency:"deep", duration:15 minutes} by name --これは、単一のプロパティリストを名前で渡す呼び出しコマンドです
to castSpell spellName, duration, potency --ここで設定されたパラメータ変数は、対応するプロパティキーの値を参照します。順序は問題ではありません。"sleep"はspellName変数に、"deep"はpotencyに、そして15分はdurationに挿入されます。
//スペルを発動するための作業:
Put duration and potency into Cauldron
Stir Cauldron --スペルを実行するカスタムコール
Log "Alakazam!: " & spellName --スペルが発動されたことを確認するメッセージ
end castSpell
名前付きパラメータの割り当てについての詳細は、Named Parameter Assignmentをご覧ください。
可変数のパラメータの受け入れ
SenseTalkでは、コマンドや関数はパラメータの数に関係なく呼び出すことができます。ハンドラが期待するよりも少ない値が呼び出しスクリプトから渡された場合、初期値がない宣言済みパラメータは空に設定されます。
ハンドラに渡される値が宣言した名前付きパラメータの数を超えた場合、追加の値はハンドラ内でparam
またはparameterList
関数を使用してアクセスできます。渡されたパラメータの数はparamCount
関数で取得できます。以下は、これらの関数を使用して、渡されたすべてのパラメータ値の中から中央値(中間の値)を見つける例です。この例では、数字でない値は無視されます:
to handle medianNumber
set numList to be an empty list
n = 1からparamCountまで繰り返す -- 全てのパラメータを通過します
if param(n) is a number then insert param(n) into numList
end repeat
numListの項目を数値順に並べ替えます
return numListの中央の項目
end medianNumber
ハンドラへの可変数のパラメータの処理の別の方法は、ハンドラ名の後(または params
宣言の中)に1つ以上の変数名をリストし、最後の変数名の後に省略記号または3つのドット(...
)を続けることです。これにより、その変数は追加のパラメータすべてを含むリストに設定されます:
put quoteandjoin(",", Elizabeth, Aditi, Ricardo, Carrie, Eggbert)
to quoteAndJoin given joiner, namesToJoin... -- この場合の結合子は、最初のパラメータとして渡されたカンマです。最後の省略記号により、ハンドラは最初の1つを超える任意のパラメータを、その変数(ここではnamesToJoinと呼ばれる)へのリストとして受け入れます。
put namesToJoin -- 最初のプロパティの後に渡されたすべてのプロパティを含むリストを表示します:["Elizabeth","Aditi","Ricardo","Carrie","Eggbert"]
get namesToJoin joined by (quote & joiner & quote)
return quote & it & quote -- Prints: "Elizabeth","Aditi","Ricardo","Carrie","Eggbert"
end quoteAndJoin
デフォルトのパラメータ値
ハンドラは、それに渡された任意の数のパラメータ値で呼び出すことができます。しばしば、一部の期待される(宣言された)パラメータはオプショナルと考えられ、ハンドラへの呼び出しでそれらのパラメータに対する値が渡されるかどうか。このような場合、これらの値のいずれかに空以外のデフォルト値を宣言すると便利です。
デフォルト値は、そのパラメータ宣言に対して順序付けられたパラメータまたは名前付きパラメータが受け取られない場合にのみ適用されます。ハンドラが呼び出されると、その宣言されたパラメータ変数は、最初のものから順に値が与えられます。その変数のために呼び出しスクリプトによって順序付けられたパラメータ値が指定されていた場合、それが使用されます。もし指定されていないが、名前付きのパラメータ値が指定されていた場合、それが使用されます。パラメータ変数は順序付けられるため、前の変数の値を後の変数のデフォルト値の定義に使用することが可能です。
パラメータのデフォルト値を宣言するには、パラメータ宣言の後にコロン(:)とデフォ ルト値を続けます。
例:
この例では、 c
のみが指定されています(Yes
)。パラメータ変数 a
、 b
、および d
は、呼び出しスクリプトが値を提供しない場合はデフォルトで空になります。
to handle GuestRegistration with a, b, c:Yes, d
--
end GuestRegistration
例:
ここでは、 to reconnect
ハンドラは3つのパラメータを受け入れます。パラメータなしで呼び出された場合、 server
パラメータ変数は currentServer
関数の呼び出しによって返される値に設定されます。 attempts
変数は3に設定さ れ、 disconnectFirst
変数は Yes
に設定されます。
to reconnect server: currentServer(), attempts:3, disconnectFirst: Yes
--
end reconnect
デフォルト値としての式
デフォルトのパラメータ値は、単純な値または任意の式にすることができます。その式は、順序付けられたパラメータまたは名前付きパラメータによってそのパラメータ変数に値が提供されない場合にのみ評価されます。順序付けられたパラメータと名前付きパラメータについての情報は、 Parameters and Resultsを参照してください。
例:
この例では、スクリプトの呼び出し行でハンドラにパラメータが渡されていないため、両方のパラメータ宣言でデフォルト値が使用されます。
Greet -- Greetハンドラを呼び出し、パラメータは渡されません。
to greet user:"Mysterious One", salutation: !"Greetings, [[user]]!" -- パラメータが渡されなかったため、両方のデフォルト値が使用されます
put salutation -- Prints: "Greetings, Mysterious One!"
end greet
高度なメッセージハンドリング
任意の (<any>
) メッセージの処理
各ハンドラーは一つの名前のみのメッセージを処理します。したがって、to drive
ハンドラーは drive
メッセージが送信されたときのみ呼び出されます。稀に、任意の名前のメッセージを受信できるハンドラーを作成することが有用な場合があります。これは、メッセージ名の代わりに <any>
を指定することで行うことができます。この機能は、getProp
ハンドラーや frontScripts
のスクリプトで特に役立つ可能性があります。
これらの <any>
ハンドラーには特殊なルールがいくつかあります。スクリプトが特定のメッセージのハンドラーを持っている場合、そのハンドラーが <any>
ハンドラーではなく呼び出されます。<any>
ハンドラーは、そのスクリプトでは処理されないメッセージに対してのみ呼び出されます。<any>
ハンドラーが来るメッセージすべてを処理する特異な能力のため、SenseTalk はそれ自身を呼び出すことから特別にブロックします。そうでなければ、on <any>
ハンドラーの各コマンドがそれ自体を呼び出す原因となり、すぐに再帰的な悪夢になるでしょう。
<any>
ハンドラーの使用は、メッセージが意図せずにブロックされることを避けるために注意深くアプローチするべきです。param(0)
関数を使用して実際に送信されたメッセージの名前を取得し、適切なアクションを選択したり、ハンドラーが対処する意図がないメッセージをパスすることができます:
on <any>
if param(0) does not begin with "x_" then pass message
// Put code here to handle commands beginning with x_
end on <any>
配送されないメッセージの処理
ハンドラーが見つからずメッセージが送信された場合、エラーをすぐに発生させるのではなく、SenseTalkは元の未処理のメッセージの対象にundeliveredMessage
メッセージを送信します。オブジェクトはundeliveredMessage
ハンドラーを実装して、元のメッセージを処理できる可能性のある他のオブジェクトにパスしようと試みる(pass original message to ...
commandを参照)、または他の方法で問題を処理します。undeliveredMessage
ハンドラーがpass undeliveredMessage
コマンドを実行すると、通常のエラーが発生します。
pass original message to object
コマンドは、未配送のメッセージを他のオブジェクトにパスしようとするために使用できます。そのオブジェクトがメッセージを処理する場合、それがそれの終わりとなり、現在のハンドラの実行は終了します。そのオブジェクトが元のメッセージを処理しない場合、実行は続行します。このようにして、undeliveredMessage
ハンドラーは、元のメッセージを処理できる可能性のある他の一つまたは複数のオブジェクトに配送しようと試みることができます。
to handle undeliveredMessage
repeat with friend = each item in my friends
pass original message to friend
end repeat
pass undeliveredMessage -- Give up and let it fail
end undeliveredMessage
GetProp, SetProp ハンドラー
標準のコマンドハンドラーと関数ハンドラーに加えて、オブジェクトのスクリプトには、オブジェクトのプロパティと連携するための2つの特別なタイプのハンドラーが含まれている場合があります:プロパティの値を提供するためのgetProp
ハンドラーと、プロパティの新し い値を受け取るためのsetProp
ハンドラー。
オブジェクトのプロパティが読み取られるとき、そのプロパティのためのgetProp
メッセージがオブジェクトに送信されます。メッセージを処理すると、その返り値がそのプロパティの値として使用されます。プロパティの値が変更されると、新しい値をパラメータとして持つsetProp
メッセージがオブジェクトに送信されます。そのメッセージのためのsetProp
ハンドラーがオブジェクトにある場合、それは呼び出されます。そうでなければ、プロパティは直接設定されます。
たとえば、ここには、その長さと幅に基づいてオブジェクトのarea
プロパティを提供するハンドラーがあります:
getProp area
return my length * my width
end area
オブジェクトはまた、プロパティの設定を制御したい場合があります。ここでは、オブジェクトのarea
を設定すると、実際にはその長さが変更されます:
setProp area newArea
set the length of me to newArea
my width
end area
オブジェクトがそのプロパティのgetProp
またはsetProp
ハンドラー内から自身のプロパティにアクセスする場合、SenseTalkはgetProp
/setProp
ハンドラーを再帰的に呼び出すのではなく、プロパティに直接アクセスします。
My Direct Property
振る舞い: オブジェクトが任意の関数やgetProp
/setProp
メッセージを送信せずに自身のプロパティにアクセスすることを可能にします。これは、特殊な構文my direct propName (またはmy direct property propName)を使用して行うことができます。
構文:
my direct {property} propName
例:
getProp age -- 私の年齢(年)
return (the date - my direct birthDate) div 365.25 days
end age
direct
キーワードはmy
と一緒にしか使用できず、そのため、オブジェクトが自身のプロパティにアクセスするのに制限されます。他のオブジェクトのプロパティへのアクセスは常にgetProp
またはsetProp
の呼び出しを伴います。
HandlerNames
Function
振る舞い: オブジェクトのスクリプト内の各ハンドラーの名前のリストを返します。ハンドラーがリストされる順序は未定義です。
構文:
{the} average of numList
handlerNames( anObject )
例:
put handlerNames of Account