メインコンテンツまでスキップ

ハンドラ

ハンドラはスクリプト内の_メッセージリスナー_です。オブジェクトはスクリプトを持ち、スクリプトはハンドラを持ちます。オブジェクトは特定のメッセージを受け取り、それを処理するためには、そのメッセージのハンドラへのアクセスを持つ必要があります。メッセージの詳細については、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

初期ハンドラ

toonfunctionキーワードで始まる明示的に宣言されたハンドラに加えて、スクリプトには初期ハンドラがあります。これはスクリプトの最初(スクリプトの最初の部分でのプロパティ宣言をスキップした後)から最初の明示的なハンドラまたはプロパティ宣言までの全てのステートメントで構成されます。初期ハンドラタイプは実際には最も一般的で、明示的なハンドラがない任意のスクリプトは初期ハンドラです。「スクリプト」と呼んでいるものは実際には初期ハンドラです。

初期ハンドラは、ジェネリックな 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つの数値の商を計算する基本的な関数ハンドラの例です。この例では、dividenddivisorという単語は商のハンドラ内でローカル変数として扱われ、最初の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)。パラメータ変数 ab、および 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 {propertyproperty**} propName

例:

getProp age -- 私の年齢(年)
return (the date - my direct birthDate) div 365.25 days
end age
ノート

directキーワードはmyと一緒にしか使用できず、そのため、オブジェクトが自身のプロパティにアクセスするのに制限されます。他のオブジェクトのプロパティへのアクセスは常にgetPropまたはsetPropの呼び出しを伴います。

HandlerNames関数

振る舞い: オブジェクトのスクリプト内の各ハンドラーの名前のリストを返します。ハンドラーがリストされる順序は未定義です。

構文:
{the} handlerNames of anObject
handlerNames( anObject )

例:

put handlerNames of Account