use crate::domain::error::WireResult;
use handlebars::{no_escape, Handlebars};
pub trait TemplateEngine: Send + Sync {
fn id(&self) -> &'static str;
fn render(&self, template: &str, context: &serde_json::Value) -> WireResult<String>;
}
#[derive(Default)]
pub struct HandlebarsEngine;
impl HandlebarsEngine {
pub fn new() -> Self {
Self
}
}
impl TemplateEngine for HandlebarsEngine {
fn id(&self) -> &'static str {
"handlebars"
}
fn render(&self, template: &str, context: &serde_json::Value) -> WireResult<String> {
let mut hb = Handlebars::new();
hb.register_escape_fn(no_escape);
hb.set_strict_mode(false);
match hb.render_template(template, context) {
Ok(s) => Ok(s),
Err(e) => Ok(format!("{{{{render-error: {}}}}} {}", e, template)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn handlebars_engine_id_is_handlebars() {
assert_eq!(HandlebarsEngine::new().id(), "handlebars");
}
#[test]
fn handlebars_engine_renders_scalar() {
let eng = HandlebarsEngine::new();
let out = eng
.render("Hi, {{name}}!", &json!({"name": "alpha"}))
.unwrap();
assert_eq!(out, "Hi, alpha!");
}
#[test]
fn handlebars_engine_renders_nested_path() {
let eng = HandlebarsEngine::new();
let out = eng
.render(
"Owner is {{owner.name}}.",
&json!({"owner": {"name": "user_a"}}),
)
.unwrap();
assert_eq!(out, "Owner is user_a.");
}
#[test]
fn handlebars_engine_missing_path_renders_empty() {
let eng = HandlebarsEngine::new();
let out = eng
.render("[{{absent}}]", &json!({"name": "alpha"}))
.unwrap();
assert_eq!(out, "[]");
}
}