diff --git a/Cargo.toml b/Cargo.toml index c3f47965..d57589fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "examples/from_request", "examples/stream", "examples/json", + "examples/handlebars_templates", ] [replace] diff --git a/contrib/Cargo.toml b/contrib/Cargo.toml index b8a1308b..5a72f110 100644 --- a/contrib/Cargo.toml +++ b/contrib/Cargo.toml @@ -6,11 +6,28 @@ authors = ["Sergio Benitez "] [features] default = ["json"] json = ["serde", "serde_json"] +tera_templates = ["tera", "templates"] +handlebars_templates = ["handlebars", "templates"] + +# Internal use only. +templates = ["serde", "serde_json", "lazy_static_macro", "glob"] +lazy_static_macro = ["lazy_static"] [dependencies] rocket = { path = "../lib/" } log = "*" -# JSON module dependencies +# JSON and templating dependencies. serde = { version = "*", optional = true } serde_json = { version = "*", optional = true } + +# Templating dependencies only. +handlebars = { version = "*", optional = true, features = ["serde_type"] } +glob = { version = "*", optional = true } +lazy_static = { version = "*", optional = true } + +# Tera dependency +[dependencies.tera] +git = "https://github.com/SergioBenitez/tera" +branch = "array-get-filter" +optional = true diff --git a/contrib/src/json/mod.rs b/contrib/src/json/mod.rs index 0f88aedf..99a4ace2 100644 --- a/contrib/src/json/mod.rs +++ b/contrib/src/json/mod.rs @@ -44,6 +44,7 @@ use self::serde_json::Error as JSONError; /// } /// ``` /// +#[derive(Debug)] pub struct JSON(pub T); impl JSON { diff --git a/contrib/src/lib.rs b/contrib/src/lib.rs index 923b261b..8c84a646 100644 --- a/contrib/src/lib.rs +++ b/contrib/src/lib.rs @@ -32,9 +32,19 @@ #[macro_use] extern crate log; #[macro_use] extern crate rocket; +#[cfg_attr(feature = "lazy_static_macro", macro_use)] +#[cfg(feature = "lazy_static_macro")] +extern crate lazy_static; + #[cfg_attr(feature = "json", macro_use)] #[cfg(feature = "json")] mod json; +#[cfg(feature = "templates")] +mod templates; + #[cfg(feature = "json")] pub use json::JSON; + +#[cfg(feature = "templates")] +pub use templates::Template; diff --git a/contrib/src/templates/handlebars_templates.rs b/contrib/src/templates/handlebars_templates.rs new file mode 100644 index 00000000..b750e7e1 --- /dev/null +++ b/contrib/src/templates/handlebars_templates.rs @@ -0,0 +1,35 @@ +extern crate handlebars; + +use std::sync::RwLock; + +use super::serde::Serialize; +use super::TemplateInfo; + +use self::handlebars::Handlebars; + +lazy_static! { + static ref HANDLEBARS: RwLock = RwLock::new(Handlebars::new()); +} + +pub const EXT: &'static str = "hbs"; + +pub fn render(name: &str, info: &TemplateInfo, context: &T) -> Option + where T: Serialize +{ + // FIXME: Expose a callback to register each template at launch => no lock. + if HANDLEBARS.read().unwrap().get_template(name).is_none() { + let p = &info.full_path; + if let Err(e) = HANDLEBARS.write().unwrap().register_template_file(name, p) { + error_!("Handlebars template '{}' failed registry: {:?}", name, e); + return None; + } + } + + match HANDLEBARS.read().unwrap().render(name, context) { + Ok(string) => Some(string), + Err(e) => { + error_!("Error rendering Handlebars template '{}': {}", name, e); + None + } + } +} diff --git a/contrib/src/templates/macros.rs b/contrib/src/templates/macros.rs new file mode 100644 index 00000000..cb86be6e --- /dev/null +++ b/contrib/src/templates/macros.rs @@ -0,0 +1,44 @@ +#[macro_export] +macro_rules! engine_set { + ($($feature:expr => $engine:ident),+) => ({ + use std::collections::HashSet; + let mut set = HashSet::new(); + $( + #[cfg(feature = $feature)] + fn $engine(set: &mut HashSet) { + set.insert($engine::EXT.to_string()); + } + + #[cfg(not(feature = $feature))] + fn $engine(_: &mut HashSet) { } + + $engine(&mut set); + )+ + set + }); +} + +#[macro_export] +macro_rules! render_set { + ($name:expr, $info:expr, $ctxt:expr, $($feature:expr => $engine:ident),+) => ({$( + #[cfg(feature = $feature)] + fn $engine(name: &str, info: &TemplateInfo, c: &T) + -> Option