[![Build Status](https://travis-ci.org/maghoff/bart.svg?branch=master)](https://travis-ci.org/maghoff/bart) Bart is a compile time templating language for [Rust](https://www.rust-lang.org/en-US/) inspired by [Mustache](https://mustache.github.io/mustache.5.html). It plays to Rust's strengths by statically compiling the template into efficient code and performing full variable resolution and type checking at compile time. Cargo dependencies ================== To use Bart, add these dependencies to your `Cargo.toml`: [dependencies] bart = "0.1.4" bart_derive = "0.1.4" Example ======= Given the template file `hello_world.html`: Hello {{name}} We can write the following program: #[derive(bart_derive::BartDisplay)] #[template = "hello_world.html"] struct HelloWorld<'a> { name: &'a str, } fn main() { print!("{}", &HelloWorld { name: "World" }); } To compile this example program, you need to add both `bart` and `bart_derive` as dependencies in your `Cargo.toml`. Running this program will output Hello World You can run this example by cloning this repository and executing `cargo run --example hello_world`. Line by line ------------ #[derive(BartDisplay)] The programmer interface to Bart is the procedural macro defined in the `bart_derive` crate, which implements support for `#[derive(bart_derive::BartDisplay)]`. It must be added as a dependency in your `Cargo.toml`. `bart_derive` generates code which is dependent on the `bart` crate, so you also need to pull this in as a dependency. Use `bart_derive::BartDisplay` to generate an `impl` of the [`Display`][Display] trait based on the template and struct below. #[template = "hello_world.html"] `bart_derive` will read `hello_world.html` and use it to generate the template rendering code. The given file name is relative to your crate root, so, for example, you have to specify `#[template = "src/hello_world.html"]` if you want your template to reside in the `src/` directory. It is also possible to specify the template inline with `template_string`: `#[template_string = "Hello {{name}}"]`. struct HelloWorld<'a> { name: &'a str, } Values to be interpolated in the template will be resolved from the given `struct`. In this case `{{name}}` would be resolved to the `name` field of this struct. Fields to be interpolated must implement the [`Display`][Display] trait. fn main() { print!("{}", &HelloWorld { name: "World" }); } As noted above, `bart_derive` has now generated an `impl` of [`Display`][Display] for `HelloWorld`. This means we can pass instances of `HelloWorld` to `print!`, `write!`, `format!` and so on. The template is rendered with the supplied data, generating `Hello World` to standard output. Language reference ================== The Bart templating language is inspired by Mustache. (Bart is the Norwegian word for Mustache.) The input is reproduced verbatim except for tags. Tags start with `{{` and end with `}}`. Interpolation ------------- The simplest tag is the interpolation tag, which contains a data reference. For the template `Hello {{name}}`, `{{name}}` is recognized as an interpolation tag and `name` is resolved as a field on the given `struct`. This field must implement the [`Display`][Display] trait. It is possible to use `.` to refer to fields in nested `struct`s; `{{name.surname}}`. Interpolation tags are HTML escaped, so for the template `Hello {{name}}`, if `{{name}}` is `Bobby `, the output will be `Hello Bobby <tags>`. Verbatim/unescaped interpolation -------------------------------- It is also useful to be able to deliberately include HTML content unescaped. Use triple-tags, `{{{`…`}}}`, for this: `Hello {{{name}}}` would render `Hello Bobby ` if `name` were `Bobby `. Iteration --------- It is possible to iterate over anything that implements [`IntoIterator`](https://doc.rust-lang.org/std/iter/trait.IntoIterator.html):
    {{#values}}
  • {{.}}
  • {{/values}}
Use `{{.}}` to refer to the current value. For example, if `values` were a `Vec`, `{{.}}` would refer to each of the contained `i32` values in turn. When iterating over a set of structures, use a `.` prefix to refer to members:
    {{#people}}
  • {{.name}} ({{.age}})
  • {{/people}}
It can be useful to take advantage of the `IntoIterator` implementations on `Option` and `Result` to use them in Bart iterations. Scoping ------- Similar to iteration, it is possible to enter a scope for a variable, by specifying a trailing dot: {{#person.}} {{.name}} ({{.age}}) {{/person}} It is also possible to fully qualify each reference: {{person.name}} ({{person.age}}) When in a nested scope, use multiple leading dots to step out: {{#department.}} {{#head.}} {{.name}}, head of the {{..name}} department. {{/head}} {{/department}} Unqualified names, that is, names without leading dots, will always be resolved in the topmost scope. The same scoping rules apply to iteration scopes. [Display]: https://doc.rust-lang.org/std/fmt/trait.Display.html