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

属性に必要な値を計算するために、複数行ルールを作成する必要が生じることがよくあります。 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 ブロック

debugx ブロックは、 logfieldsの 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 です。 この結果は、6 行目で if.block内の 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

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

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

重要な制限事項

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