use std::path::Path;
use serde::Serialize;
use crate::{controller::views::ViewRenderer, Error, Result};
const VIEWS_DIR: &str = "assets/views";
#[derive(Clone, Debug)]
pub struct TeraView {
pub tera: tera::Tera,
pub default_context: tera::Context,
}
impl TeraView {
pub fn build() -> Result<Self> {
Self::from_custom_dir(&VIEWS_DIR)
}
pub fn from_custom_dir<P: AsRef<Path>>(path: &P) -> Result<Self> {
if !path.as_ref().exists() {
return Err(Error::string(&format!(
"missing views directory: `{}`",
path.as_ref().display()
)));
}
let tera = tera::Tera::new(
path.as_ref()
.join("**")
.join("*.html")
.to_str()
.ok_or_else(|| Error::string("invalid blob"))?,
)?;
let ctx = tera::Context::default();
Ok(Self {
tera,
default_context: ctx,
})
}
}
impl ViewRenderer for TeraView {
fn render<S: Serialize>(&self, key: &str, data: S) -> Result<String> {
let context = tera::Context::from_serialize(data)?;
Ok(self.tera.render(key, &context)?)
}
}
#[cfg(test)]
mod tests {
use serde_json::json;
use tree_fs;
use super::*;
#[test]
fn can_render_view() {
let yaml_content = r"
files:
- path: template/test.html
content: |-
generate test.html file: {{foo}}
- path: template/test2.html
content: |-
generate test2.html file: {{bar}}
";
let tree_res = tree_fs::from_yaml_str(yaml_content).unwrap();
let v = TeraView::from_custom_dir(&tree_res).unwrap();
assert_eq!(
v.render("template/test.html", json!({"foo": "foo-txt"}))
.unwrap(),
"generate test.html file: foo-txt"
);
assert_eq!(
v.render("template/test2.html", json!({"bar": "bar-txt"}))
.unwrap(),
"generate test2.html file: bar-txt"
);
}
}