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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! If you want to render templates, see the [`Render`](trait.Render.html)
//! trait.
//!
//! To customise the templating behavior, see the
//! [`TemplateSupport`](trait.TemplateSupport.html) trait.

#![deny(missing_docs)]

#[macro_use]
extern crate nickel;
extern crate mustache;
extern crate rustc_serialize;

use rustc_serialize::Encodable;
use mustache::{Data, Template};

use std::borrow::Cow;
use std::path::Path;

mod default_implementations;
mod response_extension;

/// Extension trait for common `mustache::Template` usage.
pub trait Render {
    /// Return type for all of the extension methods.
    type Output;

    /// Renders a `mustache::Template` with specific `Encodable` data
    ///
    /// See `examples/example.rs` for example usage.
    fn render<T, P>(self, path: P, data: &T) -> Self::Output
    where T: Encodable,
          P: AsRef<Path>;

    /// Renders a `mustache::Template` wrapped inside a specific layout
    ///
    /// See `examples/with_layout.rs` for example usage.
    fn render_with_layout<T, P, L>(self, path: P, layout: L, data: &T) -> Self::Output
    where T: Encodable,
          P: AsRef<Path>,
          L: AsRef<Path>;

    /// Renders a `mustache::Template` with specific `mustache::Data`
    ///
    /// See `examples/helper_functions.rs` for example usage.
    fn render_data<P>(self, path: P, data: &Data) -> Self::Output where P: AsRef<Path>;

    /// Renders a `mustache::Template` wrapped inside a specific layout
    ///
    /// See `examples/with_layout.rs` for example usage.
    fn render_data_with_layout<P, L>(self, path: P, layout: L, data: &Data) -> Self::Output
    where P: AsRef<Path>,
          L: AsRef<Path>;
}

/// Customise the behaviour of the templating system.
pub trait TemplateSupport {
    /// What type to dispatch the cache handling to.
    ///
    /// # Note
    ///
    /// Currently if you don't want custom behavior you should use `()` as your
    /// `Cache`. When 'associated type defaults' becomes stable then this won't
    /// be necessary to specify anymore.
    type Cache: TemplateCache;

    /// A reference to the `Cache` if there is one.
    fn cache(&self) -> Option<&Self::Cache> {
        None
    }

    /// Adjust the path of a template lookup before it gets compiled.
    ///
    /// This can be useful if you want to keep a clean directory structure
    /// without having to spread that knowledge across your handlers.
    ///
    /// See `examples/adjusted_path.rs` for example usage.
    fn adjust_path<'a>(&self, path: &'a Path) -> Cow<'a, Path> {
        Cow::Borrowed(path)
    }

    /// Adjust the path of a layout lookup before it gets compiled.
    ///
    /// This can be useful if you want to keep a clean directory structure
    /// without having to spread that knowledge across your handlers.
    ///
    /// See `examples/adjusted_path.rs` for example usage.
    fn adjust_layout_path<'a>(&self, path: &'a Path) -> Cow<'a, Path> {
        Cow::Borrowed(path)
    }

    /// The default layout to use when rendering.
    ///
    /// See `examples/default_layout.rs` for example usage.
    fn default_layout(&self) -> Option<Cow<Path>> {
        None
    }
}

/// Handle template caching through a borrowed reference.
pub trait TemplateCache {
    /// Handles a cache lookup for a given template.
    ///
    /// # Expected behavior
    /// ```not_rust
    /// if let Some(template) = cache.get(path) {
    ///     return handle(template)
    /// } else {
    ///     let template = on_miss(path);
    ///     return handle(template)
    /// }
    /// ```
    ///
    /// # Fix-me!
    /// The signature is a bit crazy, but due to the nature of the interior mutability
    /// required it's difficult to express a general interface without restrictions
    /// on the kinds of type `TemplateCache` could be implemented for.
    ///
    /// Any improvements to get it to a more `entry`-like design are welcome!
    fn handle<'a, P, F, R>(&self, path: &'a Path, handle: P, on_miss: F) -> R
    where P: FnOnce(Result<&Template, CompileError>) -> R,
          F: FnOnce(&'a Path) -> Result<Template, CompileError>;
}

/// Currently the errors are `String`s
pub type CompileError = String;