Expand description
Simple DSL for formatting data based on Rhai.
This crate provides a custom DSL built on top of the Rhai scripting engine, designed specifically for formatting data. The DSL introduces a set of custom functions and operators to enhance the capabilities of Rhai when it comes to text formatting tasks.
§Key Features
- Custom Operators: Extended with operators like
++,and,or,xor,contains,equals,require,then_emit, andor_emitfor expressive scripts. - Value/Text Emission: Use
~to print the expression to the right - Concatenate multiple values: Use
++to stringify and concatenate multiple values. - Conditional Emission: The
then_emitandor_emitoperators allow conditional value emission based on boolean conditions. - Indentation Control:
INDandSET_INDENTfunctions to manage indentation dynamically. - Flexible Data Handling: Supports vector, maps, strings, and custom types.
- Shortcuts:
INDandNLconstants can be used as shortcuts forIND(1)andNL(1)respectively.
§DSL Overview
~ <expr>: Prints the result of the expression.<a> ++ <b>: Concatenates valuesaandb.<condition> then_emit <value>: Returns<value>if<condition>is true.<condition> or_emit <value>: Returns<value>if<condition>is false.SET_INDENT(<string>): Sets the current indent string.IND(<count>): Returns the currently set indent string for<count>times.NL(<count>): Returns<count>newlines.IND: Shortcut forIND(1).NL: Shortcut forNL(1).<vector> require <number> to_be <value>: Throws an error if not exactly<number>ofare found. <a> contains <b>: Checks if<a>is part of<b>.<value> equals <value>: Checks if two maps are equal.<vector> any <value>: Checks if any of the values in<vector>is equal to<value>.<vector> all <value>: Checks if all of the values in<vector>are equal to<value>.<vector> none <value>: Checks if none of the values in<vector>are equal to<value>.
§DSL Example
We’re going to use the following script to format a person’s details:
SET_INDENT(".. "); // sets the current indent string to ".. "
~ "Person Details:"; // ~ emits a single message
~ NL; // NL emits a newline
~ IND ++ "Name: " ++ person.name ++ NL; // ++ concatenates the values
~ IND ++ "Age: " ++ person.age ++ NL; // ++ automatically converts the values to strings
~ IND(2); // custom operator IND indents the message
~ person.age > 18 then_emit("- Adult"); // custom operator then_emit emits a message conditionallyuse script_format::{
// The crate re-exports the Rhai engine for convenience
rhai::{CustomType, TypeBuilder},
FormattingEngine,
};
// Derive the `CustomType` trait to enable Rhai to access the fields of the struct
#[derive(Clone, CustomType)]
struct Person {
pub name: String,
pub age: i32,
}
// Create a new `FormattingEngine` instance with debug mode disabled
let mut engine = FormattingEngine::new(false);
// Register the custom type so the Rhai engine can access it
engine.build_type::<Person>();
let person = Person {
name: "Alice".into(),
age: 30,
};
let script = r#"
SET_INDENT(".. "); // sets the current indent string to ".. "
~ "Person Details:"; // ~ emits a single message
~ NL; // NL emits a newline
~ IND ++ "Name: " ++ person.name ++ NL; // ++ concatenates the values
~ IND ++ "Age: " ++ person.age ++ NL; // ++ automatically converts the values to strings
~ IND(2); // custom operator IND indents the message
~ person.age > 18 then_emit("- Adult"); // custom operator then_emit emits a message conditionally
"#;
let expected = r#"
Person Details:
.. Name: Alice
.. Age: 30
.. .. - Adult
"#
.trim();
// Execute the Rhai script to format the person's details
let result = engine.format("person", person, script);
assert_eq!(result.unwrap(), expected);Expected Output:
Name: Alice
Age: 30 - AdultThis DSL is ideal for generating formatted text dynamically based on data inputs.
Re-exports§
pub use rhai;
Structs§
- Formatting
Engine - A wrapper around the Rhai
Enginefor formatting data using a dsl based on rhai.
Type Aliases§
- Script
Result - A type alias for the result of script execution within the
FormattingEngine.