Variable Parsing
Variable parsing in Clarive allows you to dynamically insert values and perform operations on data within rules. This powerful feature enables you to create flexible and reusable rule configurations by referencing variables, performing transformations, and accessing nested data structures.
Basic Variable Syntax¶
Variables in Clarive rules use the ${variable_name}
syntax. When a rule is processed, these placeholders are replaced with their corresponding values.
Simple Variable Substitution¶
The most basic form of variable parsing is direct substitution:
# Rule configuration name: "Deploy to ${environment}" description: "Deploying application ${app_name} to ${target_server}"
If the variables are defined as:
environment: "production" app_name: "my-web-app" target_server: "web-01.example.com"
The result would be:
name: "Deploy to production" description: "Deploying application my-web-app to web-01.example.com"
Multiple Variables in One String¶
You can use multiple variables in a single string:
# 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"
Variable Types and Data Structures¶
Variables can contain various data types, and the parser handles them appropriately:
String Variables¶
# Simple string substitution message: "Hello ${user_name}!" # Result: "Hello John!"
Array Variables¶
# Array substitution files: ${file_list} # If file_list = ["config.yml", "app.js", "style.css"] # Result: ["config.yml", "app.js", "style.css"]
Hash/Dictionary Variables¶
# Hash substitution config: ${app_config} # If app_config = {port: 8080, host: "localhost"} # Result: {port: 8080, host: "localhost"}
Reference Variables¶
# 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"
Nested Variable Access¶
You can access nested properties using dot notation:
# Access nested properties server_host: ${server.host} server_port: ${server.port} database_url: ${database.connection.url}
If the variables contain:
server: host: "app.example.com" port: 443 database: connection: url: "postgresql://localhost:5432/mydb"
The result would be:
server_host: "app.example.com" server_port: 443 database_url: "postgresql://localhost:5432/mydb"
Field Access Behavior¶
When accessing fields of non-hash values, the variable remains unparsed:
# If foo is an empty string field_access: ${foo.bar} # Result: "${foo.bar}" (remains unparsed)
Array Index Access¶
Access array elements using bracket notation:
# Access array elements first_item: ${items[0]} second_item: ${items[1]} nested_access: ${items[0].bar}
Array Access Examples¶
# 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"
Built-in Functions¶
Clarive provides several built-in functions for variable transformation:
String Case Functions¶
Upper Case (uc()
)¶
# Convert to uppercase environment: ${uc(foo)} # If foo = "bar" # Result: "BAR"
Lower Case (lc()
)¶
# Convert to lowercase hostname: ${lc(foo)} # If foo = "BAR" # Result: "bar"
ID Conversion (to_id()
)¶
# Convert name to ID format project_id: ${to_id(this is 123 and #more... !stuff)} # Result: "this_is_123_and_more_stuff"
Padding Function (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"
Quote List Function (quote_list()
)¶
# Quote single value quoted: ${quote_list(foo)} # If foo = "bar" # Result: '"bar"'
JSON and YAML Functions¶
# 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}'
CI Object Access¶
You can access CI (Configuration Item) properties directly:
# Access CI properties ci_name: ${ci(server_id).name} ci_status: ${ci(server_id).status} ci_ip: ${ci(server_id).ip_address}
Or get the entire CI object:
# Get full CI object server_ci: ${ci(server_id)}
Required Variables¶
Use the +
prefix to mark variables as required. If a required variable is not found, the rule will fail:
# Required variable - will fail if not defined critical_path: ${+deployment_path} api_key: ${+secret_key} # Required nested access required_field: ${+foo.bar}
Non-Recursive Variables¶
Use ${{variable}}
syntax to prevent recursive parsing:
# 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}"
Whitespace Handling¶
The parser ignores whitespace around variable names and function parameters:
# 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"
Escaping Variables¶
To include literal variable syntax in output, escape with double dollar signs:
# 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"
Error Handling¶
Missing Variables¶
When variables are not found, behavior depends on configuration:
# 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)
Required Variables¶
Required variables cause errors when missing:
# This will throw an error if foo.bar is not defined required_error: ${+foo.bar}
Recursion Detection¶
The parser detects infinite recursion and fails gracefully:
# Direct recursion - will fail circular: ${foo} # If foo = "${foo}" # Indirect recursion - will fail indirect: ${foo} # If foo = "${bar}" and bar = "${foo}"
Reference Errors¶
When using references in string context:
# 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}"
Advanced Examples¶
Complex Rule Configuration¶
# 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}"
Data Structure Parsing¶
# 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"]
Reference Consistency¶
# 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
Performance Considerations¶
- Variable parsing is performed during rule execution
- Complex nested structures may impact performance
- Use non-recursive parsing (
${{}}
) when possible to avoid unnecessary processing - The parser tracks variable usage for optimization
Debugging Variable Parsing¶
To debug variable parsing issues:
- Check that all required variables are defined
- Verify variable names match exactly (case-sensitive)
- Use the REPL to test variable expressions
- Check for recursion in variable definitions
- Ensure proper escaping of special characters
- Monitor the
vars
property to see which variables were accessed