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 emit a single value
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//! - `~ <value>`: Emits a value.
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//! - `<a> and <b>`: Logical AND operation.
38//! - `<a> or <b>`: Logical OR operation.
39//! - `<a> xor <b>`: Logical XOR operation.
40//!
41//! # DSL Example
42//!
43//! We're going to use the following script to format a person's details:
44//! ```rhai
45#![doc = include_str!("../doc_test.rhai")]
46//! ```
47//!
48//! ```rust
49//! use script_format::{
50//!     // The crate re-exports the Rhai engine for convenience
51//!     rhai::{CustomType, TypeBuilder},
52//!     FormattingEngine,
53//! };
54//!
55//! // Derive the `CustomType` trait to enable Rhai to access the fields of the struct
56//! #[derive(Clone, CustomType)]
57//! struct Person {
58//!     pub name: String,
59//!     pub age: i32,
60//! }
61//!
62//! // Create a new `FormattingEngine` instance with debug mode disabled
63//! let mut engine = FormattingEngine::new(false);
64//! // Register the custom type so the Rhai engine can access it
65//! engine.build_type::<Person>();
66//!
67//! let person = Person {
68//!     name: "Alice".into(),
69//!     age: 30,
70//! };
71//!
72//! let script = r#"
73#![doc = include_str!("../doc_test.rhai")]
74//! "#;
75//!
76//! let expected = r#"
77//! Person Details:
78//! .. Name: Alice
79//! .. Age: 30
80//! .. .. - Adult
81//!     "#
82//!     .trim();
83//!
84//! // Execute the Rhai script to format the person's details
85//! let result = engine.format("person", person, script);
86//! assert_eq!(result.unwrap(), expected);
87//! ```
88//!
89//! **Expected Output:**
90//! ```txt
91//! Name: Alice
92//! Age: 30 - Adult
93//! ```
94//!
95//! This DSL is ideal for generating formatted text dynamically based on data inputs.
96
97mod engine;
98mod internal;
99
100pub use rhai;
101
102pub use crate::engine::{FormattingEngine, ScriptResult};