複数行ルール実行プログラム

属性に必要な値を計算するために、複数行ルールを作成する必要が生じることがよくあります。 IBM® Verify シンプルな単一行ルールから、より高度な複数行ルールまで、さまざまなルールを設定することができます。

単一行の構文規則については、 「属性関数」 を参照してください。

複数行ルールの要素

複数行ルールは YAML 形式で記述されます。 これは、YAML 文書のフォーマット設定の要件によって制約されます。 使用される YAML パーサーは、YAML 1.1 および 1.2 の大部分をサポートします。

以下の用語を理解することが重要です。
ステートメント
ステートメントはルールのビルディング・ブロックであり、各種タイプのステートメントが存在します。 例えば、return ステートメントは、提供された式を計算し、ルール値として式を返します。
ブロック
ブロックは、複数のステートメントから成る限定されたコレクションです。 ルールは、statements と呼ばれる最上位ブロックから開始されます。 ブロックは、特定のステートメント・タイプの内部に存在できます。 例えば、if.block は、対応する if.match ステートメントが true と評価された場合に実行される、複数のステートメントから成るコレクションです。
ブロック・コンテキスト
ブロック・コンテキストは、そのブロック内で使用できる変数のコレクションです。 サブブロックは、親ブロックのコンテキストにアクセスできます。 親ブロックは、サブブロックのコンテキストにアクセスできません。
式は、単一行の式と同じ構文を使用するスニペットです。 「属性関数」 を参照してください。

サポートされるステートメント・タイプ

3 つのステートメント・タイプがサポートされています。
  • コンテキスト
  • Return
  • If

context ステートメント

context ステートメントは、値を初期化し、名前付き変数に割り当てるために使用されます。 これは 2 つの演算子をサポートします。
:=
この演算子は、ステートメントが評価されるコンテキスト・ブロック内で新規変数を初期化するために使用されます。 例えば、変数が if.block 内で初期化された場合、その変数は以降のステートメントでこのブロックの外部では使用できません。
=
この演算子は、値を既存の変数に割り当てるために使用されます。 変数は、現在のコンテキスト・ブロック内または親ブロック内に存在できます。
形式は context: {{varname}} := {{expression}} です。 使用法: context.{{varname}} は、以降のステートメントで同じブロック内またはサブブロック内の {{varname}} にアクセスします。

return ステートメント

return ステートメントは、実行を終了し、計算された値を即時に返すように、ルール・エンジンに指示するために使用されます。

形式は return: {{expression}} です。

if ステートメント

if ステートメントは、条件付きブロックを作成するために使用されます。 このステートメントは、前の 2 つのステートメントとは異なり、いくつかのプロパティーから成り立っています。

表1.
名前 説明 フォーマット
match この条件が true と評価された場合は、対応する block が実行されます。 match: 1 == 2
block match が true と評価された場合に実行される必要がある、複数のステートメントから成る限定されたブロック。 ステートメントの標準 YAML 配列
elsifs match が true と評価されなかった場合に評価される、else-if 条件の配列。 ネストされた if ステートメントである YAML 配列
else match およびすべての elseifs.match が true と評価されなかった場合に実行される、複数のステートメントから成るブロック。 ステートメントの YAML 配列

トレース・ロギング

複数行ルールにトレースログ機能を追加することで、デバッグログを送信することができます。 トレースログのプロパティは、トレースモードが有効な状態でルールが実行された場合に適用されます。 トレースの記録は debug 、 および debugx プロパティを通じてサポートされています。

debug 記述

この debug ステートメントは、指定された式を実行し、返された値をログに記録するために使用されます。 この式は常に文字列として評価される必要があります。

形式 - debug: {{expression}}

debugx ブロック

fieldsこの debugx ブロックは、 log とという2つのプロパティで構成されています。

名前 説明 フォーマット
ログ 指定された式が評価され、返された値がログに記録されます。 この式は常に文字列として評価される必要があります。 log: {{expression}}
フィールド ログと共に送信されるカスタムメタデータフィールド。 キーと値のペアとして提供されます。 各ペアの値は式であり、その評価結果は文字列でなければなりません。 {{field_key}}: {{expression}}

トレースログの記録を説明するサンプル関数については、該当のセクションを参照してください。

スニペット

以下のスニペットのリストは、包括的ではなく、ルールのすべての可能な使用法を示しているわけではありません。 しかし、このリストで提供されるいくつかのサンプルは、そのまま使用するか、拡張して使用することができます。

注: 複数行の構文は 形式 YAML に従うため、カスタムルールが正しく機能するには、適切なインデントが不可欠です。

マネージャーの表示名の取得

statements:
  - context: manager := user.getManager()
  - context: userExists := has(context.manager.name)
  - context: >
      givenNameExists := context.userExists
      && has(context.manager.name.givenName) 
      && context.manager.name.givenName != ""
  - context: familyNameExists := context.userExists && has(context.manager.name.familyName) && context.manager.name.familyName != ""
  - context: formattedExists := context.userExists && has(context.manager.name.formatted) && context.manager.name.formatted != ""
  - if:
      match: context.formattedExists
      block:
        - return: context.manager.name.formatted
      elseifs:
        - match: context.givenNameExists
          block:
            - if:
                match: context.familyNameExists
                block:
                  - context: managerName := context.manager.name.familyName + ", " + context.manager.name.givenName
                  - return: context.managerName
                else:
                  - return: context.manager.name.givenName
        - match: context.familyNameExists
          block:
            - return: context.manager.name.familyName
- return: string("Not Available")

E メール・ドメインの変換

statements:
  - context: "workEmails := has(user.emails) ? user.emails.filter(e, e.type == 'work') : []"
  - context: "workEmail := size(context.workEmails) > 0 ? context.workEmails[0].value : ''"
  - if:
      match: context.workEmail != ""
      block:
        - context: cn := context.workEmail.substring(0, context.workEmail.lastIndexOf('@'))
        - if:
            match: context.cn != ""
            block:
              - return: context.cn + "@github.com"
  - return: ""

変数のスコープ設定

statements:
    - context: ret := 3 + 4
    - if:
        match: 2 > 1block:
          - context: ret := 5
          - if:
              match: 3 > 2block:
                - context: ret = 0
    - return: context.ret

結果は 7 です。 if.blockこの結果は、6行目で が ret 内で再初期化されるためです。 後続のネストされたステートメントは、この変数を認識します。 しかし、ルール・エンジンは、if.block を終了した後に 2 行目で初期化された変数にアクセスできます。

トレースログの例

この例では、トレースログ出力文の使用方法を説明します。

statements:
  - context: uid := user.id
  - context: userEmail := "user@test.com"
  - debug: '"This is an example of a trace log at time " + string(now)'
  - debugx: 
      log: '"The user id obtained: " + context.uid'
      fields:
          flow: '"login"'
          time: 'string(now)'
          userEmail: context.userEmail
  - return: context.uid  + ", " + context.userEmail

"This is an example of a trace log at time <timestamp>"この debug ステートメントでは、指定された式が評価され、としてログに記録されます。

"The user id obtained: <user id>"ブロック debugx では、指定された式が評価され、としてログに記録されます。 以下のカスタムメタデータフィールドが、ログとともに送信されます。
キー
"flow" "login"
"time" "<timestamp>"
"userEmail" "user@test.com"

重要な制限事項

  • context フレームで初期化された変数は、そのフレームおよびそのサブフレーム内でのみ存続します。 前出のルール例の場合、変数 managerName は、その変数を初期化した if フレームの外部からはアクセスできません。
  • elseifs フレームおよび else フレームは、if フレームが同じレベルにある場合にのみ使用できます。
  • if フレームおよび elseifs フレームはすべて、常にブール値を返す match 式が必要です。
  • ルール評価フローに return ステートメントがない場合は、ヌル値が返されます。 エラーはスローされず、想定し得るすべてのフローに return があることを確認するための構文検査も実行されません。 ルールの作成者は、ルールのすべてのフローが許容可能値を返すことを確認する必要があります。