| Crates.io | struct-string-template |
| lib.rs | struct-string-template |
| version | 0.1.0 |
| created_at | 2023-05-16 05:50:34.75606+00 |
| updated_at | 2023-05-16 05:50:34.75606+00 |
| description | Simple string templating language on struct fields |
| homepage | |
| repository | https://github.com/ryanYtan/templater |
| max_upload_size | |
| id | 865802 |
| size | 26,868 |
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)
%(X) where X is a selector)%(id) - %(title)In Cargo.toml:
[dependencies]
struct_string_template = "0.1.0"
Say we have a struct definition, and an instance of the struct:
struct Book {
id: i64,
title: String,
author: String,
contributors: Option<String>
}
let my_book = Book {
id: 9784832275492,
title: "Hidamari Sketch".to_owned(),
author: "蒼樹うめ".to_owned(),
contributors: None,
};
Define a format string:
let format_string = "[%(id)] %(title) %(所有作者)";
Build a Templater<Book> by doing:
use struct_string_template::TemplaterBuilder;
let templater = TemplaterBuilder::<Book>::new()
.with_selector("id", |book| Some(book.id.to_string()))
.with_selector("title", |book| Some(book.title.clone()))
.with_selector("所有作者", |book| {
Some(format!("(By: {}{})",
&book.author,
&book.contributors.clone().map(|x| format!(", {}", x)).or(Some("".to_owned())).unwrap())
)
})
.build();
Render it using Templater's render function
let result = templater.render(&my_book, format_string).ok().unwrap();
println!("{}", &result);
Templater without TemplateBuilderIf 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.
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())
)
});
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:
use struct_string_template::Formatter;
let formatter = Formatter::build(format_string).ok().unwrap();
let result = templater.renderf(&my_book, &formatter);
println!("{}", &result);
See src/err.rs for the errors thrown.
In this section, X is any selector
%% is treated as a literal %% followed by a character (or end of string) that is not ( is invalid%(X) is always valid%(X)A where A is any valid string is valid%(X (template is not terminated) is invalidX is invalidX on the structure is None, NA is printed. This is currently unconfigurable except by modifying the closure itself.Currently the Templater object cannot be copied around due to the closure
types. I've not found a work-around for this yet.
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.