use minijinja::{Environment, ErrorKind, Value};
use super::defaultfilters::register_default_filters;
#[derive(Debug)]
pub struct TemplateEngine {
env: Environment<'static>,
}
impl TemplateEngine {
pub fn new() -> Self {
let mut env = Environment::new();
register_default_filters(&mut env);
Self { env }
}
pub fn add_template(&mut self, name: &str, source: &str) {
self.env
.add_template_owned(name.to_string(), source.to_string())
.unwrap_or_else(|error| panic!("failed to add template `{name}`: {error}"));
}
pub fn render(&self, name: &str, context: Value) -> Result<String, TemplateError> {
let template = self
.env
.get_template(name)
.map_err(|error| match error.kind() {
ErrorKind::TemplateNotFound => TemplateError::NotFound(name.to_string()),
_ => TemplateError::Render(error),
})?;
template.render(context).map_err(TemplateError::from)
}
}
impl Default for TemplateEngine {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, thiserror::Error)]
pub enum TemplateError {
#[error("Template not found: {0}")]
NotFound(String),
#[error(transparent)]
Render(#[from] minijinja::Error),
}
#[cfg(test)]
mod tests {
use super::*;
use minijinja::context;
#[test]
fn renders_registered_templates() {
let mut engine = TemplateEngine::new();
engine.add_template("hello.html", "Hello {{ name }}!");
let rendered = engine
.render("hello.html", context!(name => "World"))
.expect("rendered template");
assert_eq!(rendered, "Hello World!");
}
#[test]
fn reports_missing_templates() {
let engine = TemplateEngine::new();
let error = engine
.render("missing.html", context! {})
.expect_err("missing template error");
assert!(matches!(error, TemplateError::NotFound(name) if name == "missing.html"));
}
#[test]
fn renders_templates_with_registered_default_filters() {
let mut engine = TemplateEngine::new();
engine.add_template(
"filters.html",
"{{ title|slugify }} {{ name|upper }} countr{{ amount|pluralize(\"y,ies\") }} {{ size|filesizeformat }}",
);
let rendered = engine
.render(
"filters.html",
context!(title => "Hello Rust World", name => "rjango", amount => 2, size => 1536),
)
.expect("rendered template with filters");
assert_eq!(rendered, "hello-rust-world RJANGO countries 1.5 KB");
}
}