#string #template #key-name #syntax #values #inject #rules

string_templater

一个用于在字符串模板中注入值的字符串模板器

3个版本

0.1.3 2024年6月30日
0.1.2 2024年6月29日
0.1.1 2024年6月29日

68模板引擎

每月 下载 30

MIT/Apache

42KB
762

String Templater

一个用于编写一些字符串模板并在其中注入数据的简单字符串模板库。

语法

语法简单,只需了解一些规则即可。

  1. 紧跟在 \ 符号后面的 {}\ 的字符将被转义,使输出中忽略 \
  2. 要访问键的值,您将使用表示法 {{my_key_name}}
  3. * 符号(镜像操作符)只能在紧跟在 {{ 后面和键名之前使用。
  4. 在解析键名时,紧跟在 \ 符号后面的 * 将输出字符 *
  5. 转义 * 符号仅在紧跟在 {{ 后面时才有用。
  6. 镜像操作符可以应用于键名中存在的任何次数。
  7. 要使用键的值作为模板,您将使用表示法 {{{my_key_name}}}
  8. 您可以在其他模板内部拥有任意数量的模板,但要小心无限循环。
  9. 序列化数据时,键名的路径尽可能接近于JS访问器(数组除外)。
  10. 要访问数组索引,请使用点符号而不是来自JS的括号符号(例如:my_field.2.name)。

如何使用

创建您的对象并定义其字段。

use serde::Serialize;

#[derive(Debug, Serialize)]
struct Person {
  pub name: String,
  pub child: Option<Box<Person>>,
}

该对象将专门用于数据注入,因此如果您有可选数据,请确保它有一些数据。在None的情况下,将返回一个StringTemplaterError::UnknownField,对于有问题的花括号,您将得到一个StringTemplaterError::MissingCurvyBracket错误,在序列化错误的情况下,将返回一个StringTemplaterError::SerializeError

现在,写下一些字符串模板并享受吧

use string_templater::parse;

fn main() {
  let someone = Person {
    name: "Roger".to_string(),
    child: Some(Box::new(Person {
      name: "Betty".to_string(),
      child: Some(Box::new(Person {
        name: "Kenny".to_string(),
        child: None,
      })),
    })),
  };
  let result = parse("Hello {{name}}! Is {{child.name}} your child? So your grandchild must be {{child.child.name}}.", &someone).unwrap();
  println!("{}", result); // Display : Hello Roger! Is Betty your child? So your grandchild must be Kenny.
}

它支持使用路径符号的JSON对象和数组,使得文本模板化变得容易。

use serde::Serialize;
use string_templater::parse;

...

#[derive(Debug, Serialize)]
struct Classroom {
  pub students: Vec<Child>,
}

#[derive(Debug, Serialize)]
struct Child {
  pub name: String,
}

...

let classroom = Classroom {
  students: vec![
    Child {
      name: "john".to_string(),
    },
    Child {
      name: "janne".to_string(),
    },
    Child {
      name: "alice".to_string(),
    },
    Child {
      name: "bob".to_string(),
    },
  ]
};
let template_str = "You should be {{students.2.name}}.";
println!("{}", parse(template_str, &classroom).unwrap()); // Display : You should be alice.

镜像数据

由于某种原因,您可能需要根据字段值访问哈希表中键的值。在这里,我们将这种行为称为镜像,因为它类似于激光指向镜子然后被引导。

首先,让我们创建一组数据来展示镜像行为(如果您想解析结构,也可以,但直接思考最终数据会更快)。

use std::collections::HashMap;
use string_templater::generate;

...

let mut data: HashMap<String, String> = HashMap::new();
data.insert("name".to_string(), "Doe".to_string());
data.insert("age".to_string(), "35".to_string());
data.insert("key_name".to_string(), "age".to_string());

要镜像一个值,您需要在变量的路径之前使用*符号。这将使用所选键的值作为新键来搜索值。您还可以使用多个*进行镜像。您可以在以下示例中看到它是如何工作的。

let template_str = "Hello {{name}}! Is it true that you're {{*key_name}} years old?";
println!("{}", generate(template_str, &data).unwrap()); // Display : Hello Doe! Is it true that you're 35 years old?

嵌套模板

可能有原因我们想使用多个模板,嵌套在彼此内部。出于这个原因,您需要使用三重花括号符号来编写字符串插值。

use std::collections::HashMap;
use string_templater::generate;

...

let mut data: HashMap<String, String> = HashMap::new();
data.insert("time".to_string(), "today".to_string());
data.insert("name".to_string(), "Doe".to_string());
data.insert("beers_count".to_string(), "2".to_string());
data.insert(
  "dialog".to_string(),
  "I only have {{beers_count}} beers for you {{time}}".to_string(),
);
data.insert(
  "bye".to_string(),
  "Well, bye {{name}}! {{{polite}}}".to_string(),
);
data.insert(
  "polite".to_string(),
  "Enjoy your {{beers_count}} beers.".to_string(),
);

let template_str = "Hello {{name}}! {{{dialog}}}... {{{bye}}}";
println!("{}", generate(template_str, &data).unwrap()); // Display : Hello Doe! I only have 2 beers for you today... Well, bye Doe! Enjoy your 2 beers.

嵌套模板与镜像一起工作,因此您可以使用{{{*my_key}}}模式来使用镜像模板。

警告:使用模板的嵌套时,您需要小心,以避免在模板中搜索模板时创建无限循环,即在一个已经调用的模板中调用另一个模板。

选项

如果您想修改模板生成的方式,可以使用generate_with_optionsparse_with_options。默认情况下,generateparsesafe_parse设置为false,因此要使用选项,您必须启用此布尔值。StringTemplaterOptions还包含字段display_missing_keysoverride_missing_keys,这些在StringTemplaterOptions中的safe_parse设置为true时使用。

现在,您可以选择显示缺失的键,如果您这样做,则可以使用override_missing_keys来覆盖默认显示,并使用您自己的函数生成一些自定义文本。

use std::collections::HashMap;
use string_templater::{generate_with_options, StringTemplaterOptions};

...

let mut data: HashMap<String, String> = HashMap::new();
data.insert("name".to_string(), "Doe".to_string());
data.insert("age".to_string(), "35".to_string());

let template_str = "Hello {{name}}! Is it true that you're {{current_age}} years old?";
println!(
  "{}",
  generate_with_options(
    template_str,
    &data,
    &StringTemplaterOptions {
      safe_parse: true,
      display_missing_keys: false,
      override_missing_keys: None,
    },
  )
  .unwrap()
); // Display : Hello Doe! Is it true that you're  years old?

println!(
  "{}",
  generate_with_options(
    template_str,
    &data,
    &StringTemplaterOptions {
      safe_parse: true,
      display_missing_keys: true,
      override_missing_keys: Some(Box::new(move |s| format!("[key `{}` is missing]", s))),
    },
  )
  .unwrap()
); // Display : Hello Doe! Is it true that you're [key `current_age` is missing] years old?

解析到HashMap

您可能需要将数据转换为HashMap以便在消费它之前对其进行操作。出于这个原因,您可以访问parse_to_hashmap函数。

fn parse_to_hashmap<T: ?Sized + Serialize>(value: &T) -> Result<HashMap<String, String>, StringTemplaterError>;

哈希表中的键包含一个值的父/子字段路径,使用点表示法。

模板构建器

您也可以简单地使用模板构建器来处理您的数据。以下是一个模板构建器作用的示例。

let mut template_builder = TemplateBuilder::new();
template_builder.insert("name", "Doe");
template_builder.insert("surname", "Doey");
let result: String = template_builder.build("Hello {{name}}! Or should I call you {{surname}}?").unwrap();

构建器中提供了多种方法,以简化您的工作。

依赖项

~0.8–1.7MB
~36K SLoC