upon

Crates.io Version Docs.rs Latest Build Status

A simple, powerful template engine.

Features

Syntax

Engine

Getting started

Your entry point is the Engine struct. The engine stores the syntax config, filter functions, and compiled templates. Generally, you only need to construct one engine during the lifetime of a program.

rust let engine = upon::Engine::new();

Next, .add_template is used to compile and store a template in the engine.

rust engine.add_template("hello", "Hello {{ user.name }}!")?;

Finally, the template is rendered by fetching it using .get_template and calling .render.

rust let template = engine.get_template("hello").unwrap(); let result = template.render(upon::value!{ user: { name: "John Smith" }})?; assert_eq!(result, "Hello John Smith!");

If the lifetime of the template source is shorter than the engine lifetime or you don’t need to store the compiled template then you can also use the .compile function to return the template directly.

rust let template = engine.compile("Hello {{ user.name }}!")?; let result = template.render(upon::value!{ user: { name: "John Smith" }})?; assert_eq!(result, "Hello John Smith!");

Features

Examples

The following section contains some simple examples. See the examples/ directory in the repository for more.

Render using structured data

You can render using any serde serializable data.

```rust

[derive(serde::Serialize)]

struct Context { user: User }

[derive(serde::Serialize)]

struct User { name: String }

let ctx = Context { user: User { name: "John Smith".into() } };

let result = upon::Engine::new() .compile("Hello {{ user.name }}")? .render(&ctx)?;

assert_eq!(result, "Hello John Smith"); ```

Transform data using filters

Data can be transformed using registered filters.

```rust let mut engine = upon::Engine::new(); engine.addfilter("lower", str::tolowercase);

let result = engine .compile("Hello {{ value | lower }}")? .render(upon::value! { value: "WORLD!" })?;

assert_eq!(result, "Hello world!"); ```

See the filters module documentation for more information on filters.

Render a template using custom syntax

The template syntax can be set by constructing an engine using Engine::with_syntax.

```rust let syntax = upon::Syntax::builder().expr("").block("<%", "%>").build();

let result = upon::Engine::with_syntax(syntax) .compile("Hello ")? .render(upon::value!{ user: { name: "John Smith" }})?;

assert_eq!(result, "Hello John Smith"); ```

Render a template to an impl io::Write

You can render a template directly to a buffer implementing io::Write by using .render_to_writer().

```rust use std::io;

let stdout = io::BufWriter::new(io::stdout());

upon::Engine::new() .compile("Hello {{ user.name }}")? .rendertowriter(stdout, upon::value! { user: { name: "John Smith" }})?; ```

Add and use a custom formatter

You can add your own custom formatter’s or even override the default formatter using Engine::set_default_formatter. The following example shows how you could add debug formatter to the engine.

```rust use std::fmt::Write; use upon::{Formatter, Value, Result};

let mut engine = upon::Engine::new(); engine.add_formatter("debug", |f, value| { write!(f, "Value::{:?}", value)?; Ok(()) });

let result = engine .compile("User age: {{ user.age | debug }}")? .render(upon::value! { user: { age: 23 } })?;

assert_eq!(result, "User age: Value::Integer(23)"); ```

Benchmarks

upon was benchmarked against several popular template rendering engines in the Rust ecosystem. Obviously, each of these engines has a completely different feature set so the benchmark just compares the performance of some of the features that they share. Handlebars is so slow that it is excluded from the compile violin plot.

Violin plot of compile results Violin plot of render results

Benchmarking was done using criterion on a quiet cloud machine.

Host

License

Licensed under either of

at your option.