Saltar a contenido

Parsing de Variables

El parsing de variables en Clarive le permite insertar valores dinámicamente y realizar operaciones sobre datos dentro de reglas. Esta característica poderosa le permite crear configuraciones de reglas flexibles y reutilizables al referenciar variables, realizar transformaciones y acceder a estructuras de datos anidadas.

Sintaxis Básica de Variables

Las variables en las reglas de Clarive usan la sintaxis ${variable_name}. Cuando una regla es procesada, estos marcadores de posición son reemplazados con sus valores correspondientes.

Sustitución Simple de Variables

La forma más básica de parsing de variables es la sustitución directa:

# Rule configuration
name: "Deploy to ${environment}"
description: "Deploying application ${app_name} to ${target_server}"

Si las variables están definidas como:

environment: "production"
app_name: "my-web-app"
target_server: "web-01.example.com"

El resultado sería:

name: "Deploy to production"
description: "Deploying application my-web-app to web-01.example.com"

Múltiples Variables en una Cadena

Puede usar múltiples variables en una sola cadena:

# Multiple variables
message: "${foo} ${bar}"
# If foo = "hello" and bar = "world"
# Result: "hello world"

# Variables with surrounding text
path: "before${foo}after"
# If foo = "|"
# Result: "before|after"

Tipos de Variables y Estructuras de Datos

Las variables pueden contener varios tipos de datos, y el parser los maneja apropiadamente:

Variables de Cadena

# Simple string substitution
message: "Hello ${user_name}!"
# Result: "Hello John!"

Variables de Array

# Array substitution
files: ${file_list}
# If file_list = ["config.yml", "app.js", "style.css"]
# Result: ["config.yml", "app.js", "style.css"]

Variables de Hash/Diccionario

# Hash substitution
config: ${app_config}
# If app_config = {port: 8080, host: "localhost"}
# Result: {port: 8080, host: "localhost"}

Variables de Referencia

# Scalar references
value: ${scalar_ref}
# If scalar_ref = \'bar'
# Result: "bar"

# MongoDB ObjectID references
oid_value: ${mongodb_oid}
# If mongodb_oid = MongoDB::OID->new(value => '012345678901234567890123')
# Result: "012345678901234567890123"

Acceso a Variables Anidadas

Puede acceder a propiedades anidadas usando notación de punto:

# Access nested properties
server_host: ${server.host}
server_port: ${server.port}
database_url: ${database.connection.url}

Si las variables contienen:

server:
  host: "app.example.com"
  port: 443
database:
  connection:
    url: "postgresql://localhost:5432/mydb"

El resultado sería:

server_host: "app.example.com"
server_port: 443
database_url: "postgresql://localhost:5432/mydb"

Comportamiento de Acceso a Campos

Al acceder a campos de valores que no son hash, la variable permanece sin procesar:

# If foo is an empty string
field_access: ${foo.bar}
# Result: "${foo.bar}" (remains unparsed)

Acceso a Índice de Array

Acceda a elementos de array usando notación de corchetes:

# Access array elements
first_item: ${items[0]}
second_item: ${items[1]}
nested_access: ${items[0].bar}

Ejemplos de Acceso a Array

# If items = [{bar: "baz"}]
nested_value: ${items[0].bar}
# Result: "baz"

# With recursive parsing
nested_recursive: ${items[0].bar}
# If items = [{bar: "${deep}"}] and deep = "hello"
# Result: "hello"

Funciones Incorporadas

Clarive proporciona varias funciones incorporadas para transformación de variables:

Funciones de Caso de Cadena

Mayúsculas (uc())

# Convert to uppercase
environment: ${uc(foo)}
# If foo = "bar"
# Result: "BAR"

Minúsculas (lc())

# Convert to lowercase
hostname: ${lc(foo)}
# If foo = "BAR"
# Result: "bar"

Conversión de ID (to_id())

# Convert name to ID format
project_id: ${to_id(this is 123 and #more... !stuff)}
# Result: "this_is_123_and_more_stuff"

Función de Relleno (pad())

# Pad with zeros
version: ${pad(0, 15, x)}
# If x = 1234
# Result: "000000000001234"

# Pad with custom character
label: ${pad("x", 15, x)}
# If x = "asdf"
# Result: "xxxxxxxxxxxasdf"

# Extra spaces in function are ignored
padded: ${pad(0,  15,   x)}
# If x = "asdf"
# Result: "00000000000asdf"

Función Quote List (quote_list())

# Quote single value
quoted: ${quote_list(foo)}
# If foo = "bar"
# Result: '"bar"'

Funciones JSON y YAML

# Convert to JSON
json_config: ${json(foo)}
# If foo = {aa: 100}
# Result: '{"aa":100}'

# Convert to YAML
yaml_config: ${yaml(foo)}
# If foo = {aa: 200}
# Result: '{"aa":200}'

Acceso a Objetos CI

Puede acceder a propiedades CI (Configuration Item) directamente:

# Access CI properties
ci_name: ${ci(server_id).name}
ci_status: ${ci(server_id).status}
ci_ip: ${ci(server_id).ip_address}

O obtener el objeto CI completo:

# Get full CI object
server_ci: ${ci(server_id)}

Variables Requeridas

Use el prefijo + para marcar variables como requeridas. Si una variable requerida no se encuentra, la regla fallará:

# Required variable - will fail if not defined
critical_path: ${+deployment_path}
api_key: ${+secret_key}

# Required nested access
required_field: ${+foo.bar}

Variables No Recursivas

Use la sintaxis ${{variable}} para prevenir el parsing recursivo:

# Non-recursive - won't parse variables inside the result
template: ${{email_template}}
# If email_template = "Hello ${user_name}!"
# Result: "Hello ${user_name}!" (not parsed further)

# Mixing recursive and non-recursive
mixed: "${foo} ${{bar}}"
# If foo = "${baz}", bar = "${baz}", baz = "123"
# Result: "123 ${baz}"

Manejo de Espacios en Blanco

El parser ignora espacios en blanco alrededor de nombres de variables y parámetros de función:

# Whitespace is ignored
spaced_var: ${ foo }
# If foo = "bar"
# Result: "bar"

# Tab characters are also ignored
tabbed_var: ${    foo }
# If foo = "bar"
# Result: "bar"

# Function parameters with extra spaces
spaced_func: ${ to_id(  foo bar  ) }
# Result: "foo_bar"

Escapar Variables

Para incluir sintaxis de variable literal en la salida, escape con signos de dólar dobles:

# Escape dollar signs
escaped: "$${foo}"
# If foo = 123
# Result: "${foo}"

# Escape in multiline strings
multiline_escape: |
  hello
  $${foo}
  world
# If foo = 123
# Result: "hello\n${foo}\nworld"

Manejo de Errores

Variables Faltantes

Cuando las variables no se encuentran, el comportamiento depende de la configuración:

# Default behavior - variables remain unparsed
missing_var: ${foo}
# If foo is not defined
# Result: "${foo}"

# With cleanup enabled - variables are removed
# cleanup = true
cleaned_var: ${foo}
# If foo is not defined
# Result: ""

# Multiple unresolved variables
multiple_missing: "${foo} ${bar}"
# If both are undefined
# Result: " " (space between them)

Variables Requeridas

Las variables requeridas causan errores cuando faltan:

# This will throw an error if foo.bar is not defined
required_error: ${+foo.bar}

Detección de Recursión

El parser detecta recursión infinita y falla graciosamente:

# Direct recursion - will fail
circular: ${foo}
# If foo = "${foo}"

# Indirect recursion - will fail
indirect: ${foo}
# If foo = "${bar}" and bar = "${foo}"

Errores de Referencia

Al usar referencias en contexto de cadena:

# Single variable with reference - works
single_ref: ${foo}
# If foo = {foo: "bar"}
# Result: {foo: "bar"}

# Reference in string context - fails
string_ref: "Hello, ${foo}!"
# If foo = {foo: "bar"}
# Error: "Unexpected reference found in ${foo}"

Ejemplos Avanzados

Configuración de Regla Compleja

# Rule with multiple variable types
name: "Deploy ${app_name} to ${environment}"
description: "Deploying version ${version} to ${ci(server_id).name}"
parameters:
  host: ${ci(server_id).ip_address}
  port: ${nvl(custom_port, 8080)}
  environment: ${uc(environment)}
  config_file: "${app_name}-${environment}.yml"
  backup_path: "/backups/${to_id(app_name)}/${date}"

Parsing de Estructura de Datos

# Parse complex nested structures
config:
  foo: "${foo.bar}"
  bar: ["${server}"]
  deep:
    nested: ["${path}"]

# If variables are:
# foo = {bar: "value"}
# server = "web-01"
# path = "/var/log"

# Result:
config:
  foo: "value"
  bar: ["web-01"]
  deep:
    nested: ["/var/log"]

Consistencia de Referencias

# Multiple references to the same object
server_config:
  var1: "${server}"
  var2: "${server}"

# If server = {name: "foo", hostname: "foo"}
# Both var1 and var2 will reference the same object

Consideraciones de Rendimiento

  • El parsing de variables se realiza durante la ejecución de reglas
  • Las estructuras anidadas complejas pueden impactar el rendimiento
  • Use parsing no recursivo (${{}}) cuando sea posible para evitar procesamiento innecesario
  • El parser rastrea el uso de variables para optimización

Depuración de Parsing de Variables

Para depurar problemas de parsing de variables:

  1. Verifique que todas las variables requeridas estén definidas
  2. Verifique que los nombres de variables coincidan exactamente (sensible a mayúsculas)
  3. Use el REPL para probar expresiones de variables
  4. Verifique la recursión en definiciones de variables
  5. Asegure el escape apropiado de caracteres especiales
  6. Monitoree la propiedad vars para ver qué variables fueron accedidas