1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
use handlebars::{Handlebars, RenderError};
use serde::Serialize;
use std::{
path::PathBuf,
sync::{Arc, RwLock},
};
use trillium::{async_trait, Conn, Handler};
/**
A trillium handler that provides registered templates to
downsequence handlers
*/
#[derive(Default, Clone, Debug)]
pub struct HandlebarsHandler(Arc<RwLock<Handlebars<'static>>>);
impl HandlebarsHandler {
/// Builds a new trillium Handlebars handler from either a directory
/// glob string or [`PathBuf`] or a
/// [`handlebars::Handlebars<'static>`](handlebars::Handlebars)
/// instance
///
/// ## From a glob
/// ```
/// # if cfg!(unix) {
/// # use std::path::PathBuf;
/// use trillium_handlebars::{HandlebarsHandler, HandlebarsConnExt};
/// let handler = (
/// HandlebarsHandler::new("**/*.hbs"),
/// |mut conn: trillium::Conn| async move {
/// conn.assign("name", "handlebars")
/// .render("examples/templates/hello.hbs")
/// }
/// );
///
/// use trillium_testing::prelude::*;
/// assert_ok!(get("/").on(&handler), "hello handlebars!");
/// # }
/// ```
/// ## From a [`handlebars::Handlebars`]
///
/// ```
/// use trillium_handlebars::{HandlebarsHandler, Handlebars, HandlebarsConnExt};
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// // building a Handlebars directly
/// let mut handlebars = Handlebars::new();
/// handlebars.register_template_string("greet-user", "Hello {{name}}")?;
/// let handler = (
/// HandlebarsHandler::new(handlebars),
/// |mut conn: trillium::Conn| async move {
/// conn.assign("name", "handlebars")
/// .render("greet-user")
/// }
/// );
///
/// use trillium_testing::prelude::*;
/// assert_ok!(get("/").on(&handler), "Hello handlebars");
/// # Ok(()) }
/// ```
pub fn new(source: impl Into<Self>) -> Self {
source.into()
}
pub(crate) fn render(
&self,
template: &str,
data: &impl Serialize,
) -> Result<String, RenderError> {
self.0.read().unwrap().render(template, data)
}
fn glob(self, pattern: &str) -> Self {
{
let mut handlebars = self.0.write().unwrap();
for file in glob::glob(pattern).unwrap().filter_map(Result::ok) {
log::debug!("registered template {:?}", &file);
handlebars
.register_template_file(file.clone().to_string_lossy().as_ref(), file)
.unwrap();
}
}
self
}
}
impl From<&str> for HandlebarsHandler {
fn from(pattern: &str) -> Self {
Self::default().glob(pattern)
}
}
impl From<Handlebars<'static>> for HandlebarsHandler {
fn from(ah: Handlebars<'static>) -> Self {
Self(Arc::new(RwLock::new(ah)))
}
}
impl From<PathBuf> for HandlebarsHandler {
fn from(path: PathBuf) -> Self {
path.to_str().unwrap().into()
}
}
#[async_trait]
impl Handler for HandlebarsHandler {
async fn run(&self, conn: Conn) -> Conn {
conn.with_state(self.clone())
}
}