aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-06-29 04:06:06 +0800
committer魏曹先生 <1992414357@qq.com>2026-06-29 04:06:06 +0800
commite2c6570d02aed85a16d5596f541ef2a1ff808817 (patch)
tree64af08fc00bb80d8d1b67cf91576f812bfc994ff
parente2579e22812f0629706d1e81443fc512bf6add58 (diff)
docs: rewrite README to document display blocks and new `tmpl!` macro
syntax
-rw-r--r--README.md186
-rw-r--r--README_zh_CN.md187
-rw-r--r--just_template/src/lib.rs4
3 files changed, 256 insertions, 121 deletions
diff --git a/README.md b/README.md
index 14439b4..30acf2b 100644
--- a/README.md
+++ b/README.md
@@ -1,81 +1,153 @@
# just_template
-> a tool for code gen via templates
+> A template engine for code generation.
-## Template File Writing Rules
+## Template syntax
-`just_template` gens repetitive code using three core concepts: `impl_mark`, `impl_area`, and `param`.
+### Simple parameters — `<<<key>>>`
-1. impl_mark
- Mark an "impl point" with a line starting with 10 `>` chars: `>>>>>>>>>> NAME`.
- Used for positioning. The system extracts the matching `impl_area` content and expands it here.
+The most basic substitution. Replaced with the value set via
+[`Template::insert_param`] or the [`tmpl!`] macro.
-2. impl_area
- Declare a reusable code template:
- `@@@ NAME >>>`
- [template content]
- `@@@ <<<`
- Inside, use param placeholders like `<<<PARAM>>>`.
- When adding an impl via cmd (e.g., `insert_impl!`), the system copies the area, replaces params, and appends to the impl_mark.
+```rust
+# use just_template::Template;
+let mut t = Template::from("Hello, <<<name>>>!".to_string());
+t.insert_param("name".to_string(), "World".to_string());
+assert_eq!(t.expand().unwrap(), "Hello, World!");
+```
+
+### Implementation blocks
+
+**Syntax:** `>>>>>>>>>> name` / `@@@ >>> name ... @@@ <<<`
-3. param
- - Params outside an impl_area are replaced globally.
- - Params inside are replaced per-impl when generating.
+Template sections that can be instantiated multiple times with different
+parameter sets. Each instantiation is called an "arm".
+
+```rust
+# use just_template::Template;
+let mut t = Template::from(r#"
+>>>>>>>>>> match_arms
+@@@ >>> match_arms
+ <<<value>>> => println!("<<<value>>>"),
+@@@ <<<
+"#.trim().to_string());
+
+let arms = t.add_impl("match_arms".to_string());
+arms.push(std::collections::HashMap::from([
+ ("value".to_string(), "a".to_string()),
+]));
+arms.push(std::collections::HashMap::from([
+ ("value".to_string(), "b".to_string()),
+]));
+
+let out = t.expand().unwrap();
+assert!(out.contains(r#"a => println!("a")"#));
+assert!(out.contains(r#"b => println!("b")"#));
+```
+
+### Display blocks
+
+**Syntax:** `??? >>> name` / `??? <<<`
+
+Conditionally included sections. Hidden by default; shown when a parameter
+with the same name exists in the parameter map.
+
+```rust
+# use just_template::Template;
+// Without enabling, the block is omitted
+let t = Template::from(r#"
+visible
+??? >>> debug
+ hidden by default
+??? <<<
+"#.trim().to_string());
+assert_eq!(t.expand().unwrap(), "visible");
+
+// Enable by inserting a param with the block name
+let mut t = Template::from(r#"
+visible
+??? >>> debug
+ hidden by default
+??? <<<
+"#.trim().to_string());
+t.insert_param("debug".to_string(), "".to_string());
+let out = t.expand().unwrap();
+assert!(out.contains("hidden by default"));
+```
-Example:
+Display blocks also work inside implementation blocks, and can be controlled
+per arm by including the block name in that arm's parameter map:
-Template:
```rust
-// Auto generated
-use std::collections::HashMap;
-
-pub async fn my_func(
- name: &str,
- data: &[u8],
- params: &HashMap<String, String>,
-) -> Option<Result<Vec<u32>, std::io::Error>> {
- match name {
+# use just_template::Template;
+let mut t = Template::from(r#"
>>>>>>>>>> arms
@@@ >>> arms
- "<<<crate_name>>>" => Some(<<<crate_name>>>::exec(data, params).await),
+ <<<name>>>
+??? >>> extra
+ <<<name>>>.extra()
+??? <<<
@@@ <<<
- _ => None,
- }
-}
+"#.trim().to_string());
+
+let arms = t.add_impl("arms".to_string());
+// Arm 1: no "extra" → display block hidden
+arms.push(std::collections::HashMap::from([
+ ("name".to_string(), "foo".to_string()),
+]));
+// Arm 2: has "extra" → display block shown for this arm only
+arms.push(std::collections::HashMap::from([
+ ("name".to_string(), "bar".to_string()),
+ ("extra".to_string(), "".to_string()),
+]));
+
+let out = t.expand().unwrap();
+assert!(out.contains("foo"));
+assert!(!out.contains("foo.extra()"));
+assert!(out.contains("bar"));
+assert!(out.contains("bar.extra()"));
```
-Run cmds:
+### The `tmpl!` macro
+
+The [`tmpl!`](macro.tmpl.html) proc macro provides a concise syntax for
+setting both simple parameters and implementation blocks.
+
```rust
-tmpl!(tmpl += {
+# use just_template::{Template, tmpl};
+let mut t = Template::from(r#"
+>>>>>>>>>> arms
+@@@ >>> arms
+ <<<crate_name>>> => Some(<<<crate_name>>>::exec(data, params).await),
+@@@ <<<
+"#.trim().to_string());
+
+# let param: i32 = 1; // dummy
+tmpl!(t,
+ func_name = "my_func",
arms {
- (crate_name = "my"),
- (crate_name = "you")
+ crate_name = "my",
+ {
+ crate_name = "you",
+ extra = ""
+ }
}
-});
+);
```
-The `arms` impl_area becomes:
-```rust
- "my" => Some(my::exec(data, params).await),
- "you" => Some(you::exec(data, params).await),
-```
+When the template variable is named `tmpl`, it can be omitted:
-Final expanded code:
```rust
-// Auto generated
-use std::collections::HashMap;
-
-pub async fn my_func(
- name: &str,
- data: &[u8],
- params: &HashMap<String, String>,
-) -> Option<Result<Vec<u32>, std::io::Error>> {
- match name {
- "my" => Some(my::exec(data, params).await),
- "you" => Some(you::exec(data, params).await),
- _ => None,
- }
-}
+# use just_template::{Template, tmpl};
+let mut tmpl = Template::from("<<<a>>> + <<<b>>> = <<<c>>>".to_string());
+
+tmpl! {
+ a = "1",
+ b = "2",
+ c = "3",
+};
+
+assert_eq!(tmpl.expand().unwrap(), "1 + 2 = 3");
```
## Installation
@@ -84,7 +156,7 @@ Add this to your `Cargo.toml`:
```toml
[dependencies]
-just_template = "0.1"
+just_template = "0.2"
```
## License
diff --git a/README_zh_CN.md b/README_zh_CN.md
index 125f58a..117d02a 100644
--- a/README_zh_CN.md
+++ b/README_zh_CN.md
@@ -1,93 +1,160 @@
# just_template
-> 只是通过模板生成代码的工具
+> 用于代码生成的模板引擎。
-## 模板文件编写规则
+## 模板语法
-`just_template` 用于生成重复性代码,包含三个核心概念:`实现标记`、`实现块` 和 `参数替换`
+### 简单参数 — `<<<key>>>`
-1. 实现标记
- 用一行以 10 个连续 `>` 开头的行来标记一个“实现点”,格式为 `>>>>>>>>>> NAME`
- 该标记用于定位,系统将提取对应名称的“实现块”内容,并在此处进行重复展开。
+最基本的替换方式。通过 [`Template::insert_param`] 或 [`tmpl!`] 宏设置的值来替换。
-2. 实现块
- 用以下语法声明一个实现块,它可以定义一段可重复生成的代码模板:
- `@@@ NAME >>>`
- [模板内容]
- `@@@ <<<`
- 在实现块内部,可以使用形如 `<<<PARAM>>>` 的参数占位符。
- 当通过指令(如 `insert_impl!`)为某个实现块添加具体实现时,系统会复制该块的内容,替换其中的参数,并将结果追加到对应的实现标记处
+```rust
+# use just_template::Template;
+let mut t = Template::from("Hello, <<<name>>>!".to_string());
+t.insert_param("name".to_string(), "World".to_string());
+assert_eq!(t.expand().unwrap(), "Hello, World!");
+```
+
+### 实现块
+
+**语法:** `>>>>>>>>>> name` / `@@@ >>> name ... @@@ <<<`
-3. 参数
- - 写在实现块之外的参数会被直接进行全局替换
- - 写在实现块之内的参数,会在为该块生成每个具体实现时,被替换为对应的值
+可以使用不同参数集多次实例化的模板片段。每次实例化称为一个"分支"。
+
+```rust
+# use just_template::Template;
+let mut t = Template::from(r#"
+>>>>>>>>>> match_arms
+@@@ >>> match_arms
+ <<<value>>> => println!("<<<value>>>"),
+@@@ <<<
+"#.trim().to_string());
+
+let arms = t.add_impl("match_arms".to_string());
+arms.push(std::collections::HashMap::from([
+ ("value".to_string(), "a".to_string()),
+]));
+arms.push(std::collections::HashMap::from([
+ ("value".to_string(), "b".to_string()),
+]));
+
+let out = t.expand().unwrap();
+assert!(out.contains(r#"a => println!("a")"#));
+assert!(out.contains(r#"b => println!("b")"#));
+```
+
+### 显示块
+
+**语法:** `??? >>> name` / `??? <<<`
+
+条件包含的片段。默认隐藏;当参数映射中存在同名参数时显示。
+
+```rust
+# use just_template::Template;
+// 不启用时,块被省略
+let t = Template::from(r#"
+visible
+??? >>> debug
+ hidden by default
+??? <<<
+"#.trim().to_string());
+assert_eq!(t.expand().unwrap(), "visible");
+
+// 通过插入与块名同名的参数来启用
+let mut t = Template::from(r#"
+visible
+??? >>> debug
+ hidden by default
+??? <<<
+"#.trim().to_string());
+t.insert_param("debug".to_string(), "".to_string());
+let out = t.expand().unwrap();
+assert!(out.contains("hidden by default"));
+```
-使用示例:
+显示块也可以在实现块内部工作,并且可以通过在分支的参数映射中包含块名来对每个分支进行控制:
-原始模板文件内容:
```rust
-// Auto generated
-use std::collections::HashMap;
-
-pub async fn my_func(
- name: &str,
- data: &[u8],
- params: &HashMap<String, String>,
-) -> Option<Result<Vec<u32>, std::io::Error>> {
- match name {
+# use just_template::Template;
+let mut t = Template::from(r#"
>>>>>>>>>> arms
@@@ >>> arms
- "<<<crate_name>>>" => Some(<<<crate_name>>>::exec(data, params).await),
+ <<<name>>>
+??? >>> extra
+ <<<name>>>.extra()
+??? <<<
@@@ <<<
- _ => None,
- }
-}
+"#.trim().to_string());
+
+let arms = t.add_impl("arms".to_string());
+// 分支 1:没有 "extra" → 显示块隐藏
+arms.push(std::collections::HashMap::from([
+ ("name".to_string(), "foo".to_string()),
+]));
+// 分支 2:有 "extra" → 仅此分支显示显示块
+arms.push(std::collections::HashMap::from([
+ ("name".to_string(), "bar".to_string()),
+ ("extra".to_string(), "".to_string()),
+]));
+
+let out = t.expand().unwrap();
+assert!(out.contains("foo"));
+assert!(!out.contains("foo.extra()"));
+assert!(out.contains("bar"));
+assert!(out.contains("bar.extra()"));
```
-执行添加实现的指令:
+### `tmpl!` 宏
+
+[`tmpl!`](macro.tmpl.html) 过程宏提供了一种简洁的语法,用于同时设置简单参数和实现块。
+
```rust
-tmpl!(tmpl += {
+# use just_template::{Template, tmpl};
+let mut t = Template::from(r#"
+>>>>>>>>>> arms
+@@@ >>> arms
+ <<<crate_name>>> => Some(<<<crate_name>>>::exec(data, params).await),
+@@@ <<<
+"#.trim().to_string());
+
+# let param: i32 = 1; // dummy
+tmpl!(t,
+ func_name = "my_func",
arms {
- (crate_name = "my"),
- (crate_name = "you")
+ crate_name = "my",
+ {
+ crate_name = "you",
+ extra = ""
+ }
}
-});
+);
```
-系统会为 `arms` 实现块生成两个具体实现,此时实现块内容变为:
-```rust
- "my" => Some(my::exec(data, params).await),
- "you" => Some(you::exec(data, params).await),
-```
+当模板变量名为 `tmpl` 时,可以省略它:
-最终,模板展开生成的代码如下:
```rust
-// Auto generated
-use std::collections::HashMap;
-
-pub async fn my_func(
- name: &str,
- data: &[u8],
- params: &HashMap<String, String>,
-) -> Option<Result<Vec<u32>, std::io::Error>> {
- match name {
- "my" => Some(my::exec(data, params).await),
- "you" => Some(you::exec(data, params).await),
- _ => None,
- }
-}
+# use just_template::{Template, tmpl};
+let mut tmpl = Template::from("<<<a>>> + <<<b>>> = <<<c>>>".to_string());
+
+tmpl! {
+ a = "1",
+ b = "2",
+ c = "3",
+};
+
+assert_eq!(tmpl.expand().unwrap(), "1 + 2 = 3");
```
## 安装
-将此添加到您的 `Cargo.toml` 文件中:
+将以下内容添加到您的 `Cargo.toml`:
```toml
[dependencies]
-just_template = "0.1"
+just_template = "0.2"
```
## 许可证
-本项目采用 MIT 和 Apache 2.0 双重许可。
-详见 LICENSE 文件。
+本项目采用 MIT 和 Apache 2.0 双许可证。
+详情请参阅 LICENSE 文件。
diff --git a/just_template/src/lib.rs b/just_template/src/lib.rs
index 21a122e..36342e6 100644
--- a/just_template/src/lib.rs
+++ b/just_template/src/lib.rs
@@ -1,9 +1,5 @@
//! A template engine for code generation.
//!
-//! `just_template` provides a template system with three layers of substitution,
-//! designed for generating repetitive source code while keeping the template
-//! readable.
-//!
//! # Template syntax
//!
//! ## Simple parameters — `<<<key>>>`