From f74e286e317ab6cfcc31796e63872f50c258752c Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Thu, 22 Sep 2016 04:12:07 -0700 Subject: [PATCH] Add templating support in contrib crate. The contrib crate now contains support for both Handlebars and Tera. No documentation yet. resolves #5 --- Cargo.toml | 1 + contrib/Cargo.toml | 19 +++- contrib/src/json/mod.rs | 1 + contrib/src/lib.rs | 10 ++ contrib/src/templates/handlebars_templates.rs | 35 ++++++ contrib/src/templates/macros.rs | 44 ++++++++ contrib/src/templates/mod.rs | 102 ++++++++++++++++++ contrib/src/templates/tera_templates.rs | 39 +++++++ examples/handlebars_templates/Cargo.toml | 17 +++ examples/handlebars_templates/src/main.rs | 44 ++++++++ .../templates/404.html.hbs | 11 ++ .../templates/index.html.hbs | 16 +++ examples/todo/Cargo.toml | 10 +- examples/todo/src/main.rs | 49 ++++----- .../index.html => templates/index.html.tera} | 8 +- lib/src/response/flash.rs | 10 +- lib/src/rocket.rs | 13 +-- 17 files changed, 387 insertions(+), 42 deletions(-) create mode 100644 contrib/src/templates/handlebars_templates.rs create mode 100644 contrib/src/templates/macros.rs create mode 100644 contrib/src/templates/mod.rs create mode 100644 contrib/src/templates/tera_templates.rs create mode 100644 examples/handlebars_templates/Cargo.toml create mode 100644 examples/handlebars_templates/src/main.rs create mode 100644 examples/handlebars_templates/templates/404.html.hbs create mode 100644 examples/handlebars_templates/templates/index.html.hbs rename examples/todo/{static/index.html => templates/index.html.tera} (90%) 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