このレッスンでは、ルールとアクションを使ってコンポーネントの動作を実装する方法に集中します。
ルール
コンポーネントを作成する際、式と1つ以上のアクションからなるルールを書くことができる。アクションは、式が真である場合に実行される。ルールは3つの要素で構成される:
- ID:スコープ内で一意でなければならないルール識別子
- 式:このルールをトリガーする条件
- アクション:このルールがトリガーされたときに実行されるアクションの参照または定義
また、ルールは常にステートに割り当てられる:
州
<onenter>:
これはステップに入ったときの最初の状態である。この状態では、ユーザーインターフェースは利用できないので、UI関連のアクションは使えない。ただし、パラメータを初期化してUIマッピングに使用したい場合は、この状態が正しい。<onresume>:
<onenter>の
次の状態。この状態ではUIが利用可能で、UI更新アクションで読み込んだレイアウトを変更できます。<onpause>と
<onleave>です:
これらの状態は、step_transition
またはfinish_workflow
アクションを使用して、現在のステップまたはコンポーネント全体から離れるたびに発生します。トランジションは中断できないため、これらのアクションを使用するルールをここで使用することはできません。onpause
状態では、ステップのリソースはまだ存在しますが、onleaveでは
存在しません。<onevent>
である:これはおそらく最も重要なステートである。このステートで定義されたルールは、イベントが処理されるたびにチェックされる。ユーザーとのインタラクションに関連するルールはすべてこのステートで定義される。
ステート内のルールは任意の順序で評価されるため、あるルールの表現は、その前にチェックされる別のルールに依存してはならない。
一方、ルール内のアクションは書いた順番に実行される。
評価/実行の順序:
- ルールは任意の順番でチェックされる。
- ルール内のアクションは順番に実行される。
表現
式の一般的な構造は、他のプログラミング言語と同じように、オペランド(コンテキスト変数など)と演算子('='や'>'など)で構成されます。
サポートされている演算子+, -, &&, ||, !, /, ==, >, >=, <, <=, %, *, !=
任意の長さのテキストを複数のページに表示する「ページネーション・テキスト」コンポーネントの別の簡単な例を見てみましょう:
<onevent>
<rule id="next_page">
<expression><![CDATA[
#{event:command} == 'NEXT_PAGE' && #{page} < #{numberofpages}
]]></expression>
<actions>
<action ref="next"/>
<action ref="settext"/>
</actions>
</rule>
</onevent>
ヒントとコツ
-> そのため、式を読みやすくするために自由に改行を使うことができる。
->ボタン名="NEXT_PAGE "
が押され、現在のページが最終ページでないとき、この式は真になる。
-> 式を囲む<![CDATA[ ... ]]>
タグにお気づきだろうか。この場合、このタグは必須です。これはXMLのキーワードであり、パーサーにこの後に続くものがマークアップではないことを知らせるものです。<![CDATA[ ... ]]>
タグがなければ、この式はXMLで予約された文字&と
<を
含むため、コンポーネントのXMLを無効にしてしまいます。
-> すべての式に<![CDATA[ ... ]]>
タグを追加する。こうすることで、XML予約文字を使用しているかどうかを考える必要がなくなります。
イベント
ルールがステップの<onevent>
状態にあるとき、イベントに反応し、イベントのプロパティを式で使用することができる。イベントの構造は以下の通りである:
{
"command": "...",
"device":
{
"modality": "...",
"name": "...",
"source": "...",
"descriptor": "..."
},
"payload":
{
"...": "...",
"error": "..."
}
}
必要なのは、これらのフィールドのサブセットだけである:
1. コマンド: このイベントのコマンド。コマンドは例えば、コンポーネントのレイアウトやワークフロー記述のIDに対応する。例#イベント:コマンド} == 'CANCEL'
2.device.modality: イベントの発生源。このフィールドには短い表記でアクセスできる。
event(SPEECH):command=='NEXT'という式は、#{event:device.modality} == 'SPEECH' && #{event:command}='NEXT'という式と等価です。モダリティはイベントエミッターに依存します。例:#{event:device.modality} == 'MENU_SELECTION'
3. ペイロード :ペイロードの構造/フィールドは、イベントをトリガーするアクション/ハンドラに依存する。例、#{event:payload.amount}。
4. payload.error: エラーメッセージがあれば、それを含む。例、#{event:payload.error}。
イベントソースを制限することで、特定の入力モダリティによってイベントが発生したときのみ、ルールがトリガーされるようにすることができます。例えば、「NEXT(次へ)」という音声コマンドがあり、ワーカーが特定のタスクや製品の作業が終わったことを確認するために使用することができます。また、「NEXT」というコマンドでイベントをトリガーするデバイスを使うこともできる。ハードウェアのボタンが押されると、画面上の利用可能なオプションが回転します。ハードウェアボタンが使用されているときにルールを有効にしたくないので、モダリティを指定する:#イベント(SPEECH):コマンド} == 'NEXT'.
一般的なイベントソース(モダリティ):スピーチ、ジェスチャー、キーボード、バーコード、hw_keys、camera_picture、menu_selection、media_input
例
比較的よく登場するルール構成を見ていこう:
初期化とティアダウン
最初の例では、典型的なユースケースに取り組む:コンポーネントに出入りする際に自動的にアクションを実行する。
ヒントとコツいくつかのルールは無条件に実行される必要がある。このためには、式を<expression>1</expression>
に設定します。
<onresume>
<rule id="init">
<expression>1</expression>
<actions>
<action ref="reset_counter"/>
</actions>
</rule>
</onresume>
ルールの逐次実行
ステート内のルールは、任意の順序で評価される。状況によっては、同じステップ内でルールを連続して実行する必要があります。このような場合、タイマーを使用してルールを順次トリガすることができます。タイマ・アクションは、ユーザ定義のコマンドでイベントを手動でトリガします。
最初のルールの最後のアクションとして、タイマーアクションを追加する。次に、ユーザー定義コマンドを2つ目のルールの式に追加する。
<onevent>
<rule id="first_rule">
<expression><![CDATA[ #{event:command}=='VALID' ]]></expression>
<actions>
<action ref="do_something"/>
<setvar id="increment_counter">
<context_of>workflow</context_of>
<context_update>
<param name="counter" type="long">#{counter} + 1</param>
</context_update>
</setvar>
<timer id="check_counter_trigger" command="CHECK_COUNTER" delay="0"/>
</actions>
</rule>
<rule id="second_rule">
<expression><![CDATA[ #{event:command}=='CHECK_COUNTER' && #{counter} >= #{max_iterations} ]]></expression>
<actions>
<finish_workflow id="exit"/>
</actions>
</rule>
</onevent>
📌課題
課題1:
Choice "コンポーネントでは、<![CDATA[ ... ]]>
タグを使用していません。ベストプラクティスとして、潜在的なエラーの原因を取り除くために、すべての式でこのタグを使用することをお勧めします。
- 既存のルールに
<![CDATA[ ... ]]>
タグを追加する。
課題2:
ユーザーが自分の選択を確信できるようにしよう。例えば、「アップル」を選んだとたんにアップルパイが作られ始めたとしたら、ユーザーに再確認してもらいたい:
ワークフローのダウンロード(事前課題)
ヘルプ&リソース
- 課題2では、
ui_dialog
オプションの<command>に
反応する新しいルールを作成する必要があります。既存のルールのロジックの一部を新しいルールに移動する必要があります。
ソリューション
ダウンロード・コンポーネント(事後課題)
これで4回目のレッスンは終了です。第5回目のレッスンでは、XMLだけでワークフローを定義することの限界と、ワークフローでJavaScriptを使用してこれらの問題を解決する方法について見ていきます。