script_format/
lib.rs

1//! Simple DSL for formatting data based on Rhai.
2//!
3//! This crate provides a custom DSL built on top of the Rhai scripting engine,
4//! designed specifically for formatting data. The DSL introduces a set of custom
5//! functions and operators to enhance the capabilities of Rhai when it comes to
6//! text formatting tasks.
7//!
8//! # Key Features
9//!
10//! - **Custom Operators:** Extended with operators like `++`, `and`, `or`, `xor`,
11//!   `contains`, `equals`, `require`, `then_emit`, and `or_emit` for expressive scripts.
12//! - **Value/Text Emission:** Use `~` to print the expression to the right
13//! - **Concatenate multiple values:** Use `++` to stringify and concatenate multiple values.
14//! - **Conditional Emission:** The `then_emit` and `or_emit` operators allow conditional value emission
15//!   based on boolean conditions.
16//! - **Indentation Control:** `IND` and `SET_INDENT` functions to manage indentation dynamically.
17//! - **Flexible Data Handling:** Supports vector, maps, strings, and custom types.
18//! - **Shortcuts:** `IND` and `NL` constants can be used as shortcuts for `IND(1)` and `NL(1)` respectively.
19//!
20//! # DSL Overview
21//!
22//! - `~ <expr>`: Prints the result of the expression.
23//! - `<a> ++ <b>`: Concatenates values `a` and `b`.
24//! - `<condition> then_emit <value>`: Returns `<value>` if `<condition>` is true.
25//! - `<condition> or_emit <value>`: Returns `<value>` if `<condition>` is false.
26//! - `SET_INDENT(<string>)`: Sets the current indent string.
27//! - `IND(<count>)`: Returns the currently set indent string for `<count>` times.
28//! - `NL(<count>)`: Returns `<count>` newlines.
29//! - `IND`: Shortcut for `IND(1)`.
30//! - `NL`: Shortcut for `NL(1)`.
31//! - `<vector> require <number> to_be <value>`: Throws an error if not exactly `<number>` of <value> are found.
32//! - `<a> contains <b>`: Checks if `<a>` is part of `<b>`.
33//! - `<value> equals <value>`: Checks if two maps are equal.
34//! - `<vector> any <value>`: Checks if any of the values in `<vector>` is equal to `<value>`.
35//! - `<vector> all <value>`: Checks if all of the values in `<vector>` are equal to `<value>`.
36//! - `<vector> none <value>`: Checks if none of the values in `<vector>` are equal to `<value>`.
37//!
38//! # DSL Example
39//!
40//! We're going to use the following script to format a person's details:
41//! ```rhai
42#![doc = include_str!("../doc_test.rhai")]
43//! ```
44//!
45//! ```rust
46//! use script_format::{
47//!     // The crate re-exports the Rhai engine for convenience
48//!     rhai::{CustomType, TypeBuilder},
49//!     FormattingEngine,
50//! };
51//!
52//! // Derive the `CustomType` trait to enable Rhai to access the fields of the struct
53//! #[derive(Clone, CustomType)]
54//! struct Person {
55//!     pub name: String,
56//!     pub age: i32,
57//! }
58//!
59//! // Create a new `FormattingEngine` instance with debug mode disabled
60//! let mut engine = FormattingEngine::new(false);
61//! // Register the custom type so the Rhai engine can access it
62//! engine.build_type::<Person>();
63//!
64//! let person = Person {
65//!     name: "Alice".into(),
66//!     age: 30,
67//! };
68//!
69//! let script = r#"
70#![doc = include_str!("../doc_test.rhai")]
71//! "#;
72//!
73//! let expected = r#"
74//! Person Details:
75//! .. Name: Alice
76//! .. Age: 30
77//! .. .. - Adult
78//!     "#
79//!     .trim();
80//!
81//! // Execute the Rhai script to format the person's details
82//! let result = engine.format("person", person, script);
83//! assert_eq!(result.unwrap(), expected);
84//! ```
85//!
86//! **Expected Output:**
87//! ```txt
88//! Name: Alice
89//! Age: 30 - Adult
90//! ```
91//!
92//! This DSL is ideal for generating formatted text dynamically based on data inputs.
93
94mod engine;
95mod internal;
96
97pub use rhai;
98
99pub use crate::engine::{FormattingEngine, ScriptResult};