Overview

This crate defines a simple templating language in the format %(SELECTOR) that can operate on a structure. A given SELECTOR accesses a given structure of type T via a closure Fn(&T) -> Option<String>. Using a closure allows complex logic to accessing the structure e.g. "if field x does not exist, then try field y, otherwise return a default value or None".

(This library is most definitely not production-ready)

Terminology

Quick Start

In Cargo.toml: [dependencies] struct_string_template = "0.1.0" Say we have a struct definition, and an instance of the struct: ```rust struct Book { id: i64, title: String, author: String, contributors: Option }

let mybook = Book { id: 9784832275492, title: "Hidamari Sketch".toowned(), author: "蒼樹うめ".toowned(), contributors: None, }; Define a format string: rust let formatstring = "[%(id)] %(title) %(所有作者)"; Build a `Templater<Book>` by doing: rust use structstringtemplate::TemplaterBuilder;

let templater = TemplaterBuilder::::new() .withselector("id", |book| Some(book.id.tostring())) .withselector("title", |book| Some(book.title.clone())) .withselector("所有作者", |book| { Some(format!("(By: {}{})", &book.author, &book.contributors.clone().map(|x| format!(", {}", x)).or(Some("".toowned())).unwrap()) ) }) .build(); Render it using `Templater`'s `render` function rust let result = templater.render(&mybook, format_string).ok().unwrap(); println!("{}", &result); ```

Advanced Use

Building Templater without TemplateBuilder

If the Templater needs to be built iteratively instead of using the builder class, use Templater::new(), then add closures using the insert or extend methods. rust let mut templater = Templater::<Book>::new(); templater.insert("id", |book| Some(book.id.to_string())); templater.insert("title", |book| Some(book.title.clone())); templater.insert("所有作者", |book| { Some(format!("(By: {}{})", &book.author, &book.contributors.clone().map(|x| format!(", {}", x)).or(Some("".to_owned())).unwrap()) ) });

Formatter

If you plan to use a format string many times, you can "precompile" it similar to a regex for better performance using the Formatter class (render turns the format string into a Formatter internally), then pass the Formatter variable into the renderf function: ```rust use structstringtemplate::Formatter;

let formatter = Formatter::build(formatstring).ok().unwrap(); let result = templater.renderf(&mybook, &formatter); println!("{}", &result); ```

Error Handling

See src/err.rs for the errors thrown.

Template Rules

In this section, X is any selector

  1. %% is treated as a literal %
  2. % followed by a character (or end of string) that is not ( is invalid
  3. %(X) is always valid
  4. %(X)A where A is any valid string is valid
  5. %(X (template is not terminated) is invalid
  6. Having no closure associated with X is invalid
  7. If the return value of the closure of X on the structure is None, NA is printed. This is currently unconfigurable except by modifying the closure itself.

Limitations

Currently the Templater object cannot be copied around due to the closure types. I've not found a work-around for this yet.

Motivation

I use this library in a few personal applications of mine, and I've found it annoying to keep changes to the library in sync between them.