Exécuteur de règle multiligne

Il est souvent nécessaire de créer des règles multilignes pour calculer une valeur recherchée pour un attribut. IBM® Verify permet de configurer aussi bien des règles simples à une seule ligne que des règles plus avancées à plusieurs lignes.

Pour les règles de syntaxe sur une seule ligne, voir « Fonctions d'attribut ».

Eléments d'une règle multiligne

La règle multiligne est écrite au format YAML. Elle est soumise aux exigences de formatage d'un document YAML. L'analyseur YAML utilisé prend en charge la plupart des formats YAML 1.1 et 1.2.

Il est important de comprendre les termes suivants.
Instruction
Une instruction est le bloc fonctionnel de la règle. Il peut être de différents types. Par exemple, l'instruction de retour traite l'expression fournie et renvoie l'expression en tant que valeur de la règle.
Bloc
Un bloc est une collection limitée d'instructions. La règle débute par un bloc de niveau supérieur appelé statements. Des blocs peuvent exister dans certains types d'instruction. Par exemple, if.block est la collection d'instructions à exécuter lorsque l'instruction if.match correspondante a pour résultat la valeur true.
Contexte de bloc
Un contexte de bloc est une collection de variables disponibles dans ce bloc. Les sous-blocs peuvent accéder au contexte des blocs parent. Les blocs parent ne peuvent pas accéder au contexte des sous-blocs.
Expression
Une expression est un fragment qui utilise la même syntaxe que les expressions à ligne unique. Voir « Fonctions d'attribut ».

Types d'instruction pris en charge

Trois types d'instruction sont pris en charge.
  • Contexte
  • Renvoyer
  • Plus

Instruction context

Une instruction context est utilisée pour initialiser et affecter des valeurs à des variables nommées. Elle accepte deux opérateurs.
:=
Cet opérateur est utilisé pour initialiser une nouvelle variable dans le bloc de contexte où l'instruction est évaluée. Par exemple, si une variable est initialisée dans un bloc if.block, elle n'est pas disponible en dehors de ce bloc dans les instructions suivantes.
=
Cet opérateur est utilisé pour attribuer une valeur à une variable existante. La variable peut exister dans le bloc de contexte en cours ou dans un bloc parent.
Le format est context: {{varname}} := {{expression}}. La syntaxe context.{{varname}} permet d'accéder à {{varname}} dans les instructions suivantes des mêmes bloc ou sous-blocs.

Instruction return

L'instruction return est utilisée pour demander au moteur de règles de mettre fin à l'exécution et de renvoyer immédiatement la valeur calculée.

Le format est return: {{expression}}.

Instruction if

L'instruction if est utilisée pour générer des blocs conditionnels. Elle se compose de plusieurs propriétés à la différences des deux instructions précédentes.

Tableau 1.
Nom Descriptif Format
match Si cette condition a pour valeur true, le block correspondant est exécuté. match: 1 == 2
block Bloc limité d'instructions qui doivent être exécutées si match a pour résultat true. Tableau d'instructions YAML standard
elsifs Tableau de conditions else-if évaluées si match n'a pas pour résultat true. Les tableaux YAML sont des instructions if imbriquées
else Bloc d'instructions exécutées lorsque match et tous les elseifs.match n'ont pas la valeur true. Tableau d'instructions YAML

Consignation de trace

Il est possible d'ajouter la journalisation des traces à une règle multiligne afin d'envoyer des journaux de débogage. Les propriétés de journalisation des traces sont appliquées si une règle est exécutée avec le mode de trace activé. La journalisation des traces est prise en charge via les debug propriétés et debugx .

debug STATEMENT

Cette debug instruction sert à exécuter l'expression fournie et à enregistrer la valeur renvoyée. L'expression doit toujours donner une chaîne de caractères.

Format - debug: {{expression}}

debugx bloc

Le debugx bloc comprend deux propriétés : log et fields.

Nom Descriptif Format
journal L'expression fournie est évaluée et la valeur renvoyée est enregistrée. L'expression doit toujours donner une chaîne de caractères. log: {{expression}}
Zones Champs de métadonnées personnalisés envoyés avec le journal. Fournie sous forme de table de paires clé-valeur. La valeur de chaque paire est une expression qui doit donner une chaîne de caractères. {{field_key}}: {{expression}}

Consultez cette section pour découvrir un exemple de fonction illustrant la journalisation des traces.

Fragments

Cette liste de fragments n'est pas exhaustive et ne couvre pas toutes les utilisations possibles des règles. Elle fournit toutefois des exemples qui peuvent être utilisés en l'état ou développés.

Remarque : la syntaxe sur plusieurs lignes respectant le YAML format, une indentation correcte est indispensable pour que la règle personnalisée fonctionne correctement.

Obtention du nom d'affichage du gestionnaire

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")

Transformation du domaine d'e-mail

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: ""

Portée des variables

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

Le résultat est 7. Ce résultat est dû au fait que la ligne 6 réinitialise ret dans if.block. Les instructions imbriquées suivantes voient cette variable. Cependant, une fois que le moteur de règles a quitté if.block, il peut accéder à la variable initialisée sur la ligne 2.

Exemple de journalisation des traces

Cet exemple montre comment utiliser les instructions de journalisation de trace.

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

Dans cette debug instruction, l'expression fournie sera évaluée et enregistrée sous la forme "This is an example of a trace log at time <timestamp>".

Pour le debugx bloc, l'expression fournie sera évaluée et enregistrée sous la forme "The user id obtained: <user id>". Les champs de métadonnées personnalisés suivants seront envoyés avec le journal.
Clé Valeur
"flow" "login"
"time" "<timestamp>"
"userEmail" "user@test.com"

Restrictions importantes

  • Les variables initialisées par le cadre context ne peuvent se trouver que dans ce cadre ou ses sous-cadres. Dans l'exemple de règle précédent, la variable managerName n'est pas accessible en dehors du cadre if dans lequel elle a été initialisée.
  • Les cadres elseifs et else ne peuvent être utilisés que si un cadre if se trouve au même niveau.
  • Tous les cadres if et elseifs doivent comporter une expression match qui renvoie toujours une valeur booléenne.
  • Si le flux d'évaluation de règles ne rencontre pas d'instruction return, une valeur NULL est renvoyée. Aucune erreur n'est renvoyée et aucune vérification de syntaxe n'est effectuée pour s'assurer que tous les flux possibles comportent une instruction return. L'auteur de la règle doit s'assurer que tous les flux de la règle renvoient une valeur acceptable.