9个版本

0.1.10 2023年2月12日
0.1.9 2023年2月12日
0.1.6 2022年10月9日
0.1.4 2022年9月12日

#75模板引擎

每月24次下载

WTFPL 许可证

70KB
1.5K SLoC

萨托

一个基于s-expression的HTML模板系统。

萨托模板语言示例

基本模板示例

(html
 (head
  (title "basic example")))

标签属性

(html
 (head (@ (some thing))
  (title "basic example")))

变量

萨托中的变量以 $ 为前缀。

(html
 (head
  (title $some_variable)))

条件语句

(html
 (head
  (title (if (is-set $some_variable)
             (div "$some_variable")
             (div "variable is not set")))))

遍历数组

(html
 (body
  (for i in $some_array
       (div "element: " $i))))

遍历映射

(html
 (body
  (for k v in $some_map
       (div $k ": " $v))))

switch/case

(html
 (body
  (switch $blah
          (case asdf
            qwer)
          (case zxcv
            (div what else))
          (case hjkl
            nm))))

基本库示例

use sato::renderer::Renderer;
use sato::context::RenderContext;
use sato::template::Template;

let renderer = Renderer::builder()
    .build();
let expr = r#"(html (head (title "basic example")))"#;
let template = Template::from_str(expr).unwrap();
let html = renderer.render(&template, &RenderContext::default()).unwrap();

assert_eq!(html, "<!doctype html5><html><head><title>basic example</title></head></html>")

使用变量

use sato::renderer::Renderer;
use sato::context::RenderContext;
use sato::template::Template;

let renderer = Renderer::builder()
    .build();
let expr = r#"(html (body (if (eq $asdf qwer) (for i in $array (div $i)))))"#;
let template = Template::from_str(expr).unwrap();
let context = RenderContext::builder()
    .insert("asdf", "qwer")
    .insert("array", vec!["zxc", "xcv", "cvb"])
    .build();
let html = renderer.render(&template, &context).unwrap();

assert_eq!(html, "<!doctype html5><html><body><div>zxc</div><div>xcv</div><div>cvb</div></body></html>")

自定义处理函数

use sato::renderer::{Attributes, Renderer, RenderError};
use sato::context::RenderContext;
use sato::template::{Template, TemplateExprNode};

let post_expr = r##"(div (h2 $title) (span "posted by $author") $content (br) (div (for tag in $tags (span "#$tag"))))"##;
let blogpost_template = Template::from_str(post_expr).unwrap();

let renderer = Renderer::builder()
    .function("blogpost", Box::new(move |attrs, expr, renderer, context| {
        let title = attrs.get("title").unwrap();
        let author = attrs.get("author").unwrap();

        let mut new_context = context.clone();
        new_context.insert("title", title);
        new_context.insert("author", author);
        new_context.insert("content", renderer.evaluate_multiple(expr, &new_context)?);

        Ok(vec![renderer.render(&blogpost_template, &new_context).unwrap()])
    }))
    .build();
let expr = r#"(html (body (blogpost (@ (title faketitle) (author me)) (div "my content here"))))"#;
let template = Template::from_str(expr).unwrap();
let context = RenderContext::builder()
    .insert("tags", vec!["zxc", "xcv", "cvb"])
    .build();
let html = renderer.render(&template, &context).unwrap();

assert_eq!(html, "<!doctype html5><html><body><div><h2>faketitle</h2><span>posted by me</span><div>my content here</div><br /><div><span>#zxc</span><span>#xcv</span><span>#cvb</span></div></div></body></html>")

依赖

~310–770KB
~18K SLoC