tide_handlebars/
lib.rs

1//! # Tide-Handlebars integration This crate exposes [an extension
2//! trait](TideHandlebarsExt) that adds two methods to [`handlebars::Handlebars`]:
3//! [`render_response`](TideHandlebarsExt::render_response) and
4//! [`render_body`](TideHandlebarsExt::render_body).
5//! [`Handlebars`](handlebars::Handlebars)s.
6use handlebars::Handlebars;
7use serde::Serialize;
8use std::path::PathBuf;
9use tide::{http::Mime, Body, Response, Result};
10
11/// This extension trait adds two methods to [`handlebars::Handlebars`]:
12/// [`render_response`](TideHandlebarsExt::render_response) and
13/// [`render_body`](TideHandlebarsExt::render_body)
14pub trait TideHandlebarsExt {
15    /// `render_body` returns a fully-rendered [`tide::Body`] with mime
16    /// type set based on the template name file extension using the
17    /// logic at [`tide::http::Mime::from_extension`]. This will
18    /// return an `Err` variant if the render was unsuccessful.
19    ///
20    /// ```rust
21    /// use handlebars::Handlebars;
22    /// use tide_handlebars::prelude::*;
23    /// use std::collections::BTreeMap;
24    /// let mut handlebars = Handlebars::new();
25    ///     handlebars
26    ///     .register_template_file("simple.html", "./tests/templates/simple.html")
27    ///     .unwrap();
28    ///
29    /// let mut data0 = BTreeMap::new();
30    /// data0.insert("title".to_string(), "hello tide!".to_string());
31    /// let mut body = handlebars.render_body("simple.html", &data0).unwrap();
32    /// assert_eq!(body.mime(), &tide::http::mime::HTML);
33    ///```
34    fn render_body<T>(&self, template_name: &str, context: &T) -> Result<Body>
35    where
36        T: Serialize;
37    /// `render_body_ext` returns a fully-rendered [`tide::Body`] with mime
38    /// type set based on the extension using the
39    /// logic at [`tide::http::Mime::from_extension`]. This will
40    /// return an `Err` variant if the render was unsuccessful.
41    ///
42    /// ```rust
43    /// use handlebars::Handlebars;
44    /// use tide_handlebars::prelude::*;
45    /// use std::collections::BTreeMap;
46    /// let mut handlebars = Handlebars::new();
47    ///     handlebars
48    ///     .register_template_file("simple.hbs", "./tests/templates/simple.hbs")
49    ///     .unwrap();
50    ///
51    /// let mut data0 = BTreeMap::new();
52    /// data0.insert("title".to_string(), "hello tide!".to_string());
53    /// let mut body = handlebars.render_body_ext("simple.hbs", &data0, "html").unwrap();
54    /// assert_eq!(body.mime(), &tide::http::mime::HTML);
55    ///```
56    fn render_body_ext<T>(&self, template_name: &str, context: &T, extension: &str) -> Result<Body>
57    where
58        T: Serialize;
59    /// `render_response` returns a tide Response with a body rendered
60    /// with [`render_body`](TideHandlebarsExt::render_body). This will
61    /// return an `Err` variant if the render was unsuccessful.
62    ///
63    /// ```rust
64    /// use handlebars::Handlebars;
65    /// use tide_handlebars::prelude::*;
66    /// use std::collections::BTreeMap;
67    /// let mut handlebars = Handlebars::new();
68    /// handlebars
69    ///     .register_template_file("simple.html", "./tests/templates/simple.html")
70    ///     .unwrap();
71    /// let mut data0 = BTreeMap::new();
72    /// data0.insert("title".to_string(), "hello tide!".to_string());
73    /// let mut response = handlebars.render_response("simple.html", &data0).unwrap();
74    /// assert_eq!(response.content_type(), Some(tide::http::mime::HTML));
75    ///```
76    fn render_response<T>(&self, template_name: &str, context: &T) -> Result
77    where
78        T: Serialize;
79    /// `render_response_ext` returns a tide Response with a body rendered
80    /// with [`render_body`](TideHandlebarsExt::render_body). This will
81    /// return an `Err` variant if the render was unsuccessful.
82    ///
83    /// ```rust
84    /// use handlebars::Handlebars;
85    /// use tide_handlebars::prelude::*;
86    /// use std::collections::BTreeMap;
87    /// let mut handlebars = Handlebars::new();
88    /// handlebars
89    ///     .register_template_file("simple.hbs", "./tests/templates/simple.hbs")
90    ///     .unwrap();
91    /// let mut data0 = BTreeMap::new();
92    /// data0.insert("title".to_string(), "hello tide!".to_string());
93    /// let mut response = handlebars.render_response_ext("simple.hbs", &data0, "html").unwrap();
94    /// assert_eq!(response.content_type(), Some(tide::http::mime::HTML));
95    ///```
96    fn render_response_ext<T>(&self, template_name: &str, context: &T, extension: &str) -> Result
97    where
98        T: Serialize;
99}
100
101impl TideHandlebarsExt for Handlebars<'_> {
102    fn render_body_ext<T>(&self, template_name: &str, context: &T, extension: &str) -> Result<Body>
103    where
104        T: Serialize,
105    {
106        let string = self.render(template_name, context)?;
107        let mut body = Body::from_string(string);
108        if let Some(mime) = Mime::from_extension(extension) {
109            body.set_mime(mime);
110        }
111        Ok(body)
112    }
113    fn render_body<T>(&self, template_name: &str, context: &T) -> Result<Body>
114    where
115        T: Serialize,
116    {
117        let string = self.render(template_name, context)?;
118
119        let path = PathBuf::from(template_name);
120        let mut body = Body::from_string(string);
121        if let Some(extension) = path.extension() {
122            if let Some(mime) = Mime::from_extension(extension.to_string_lossy()) {
123                body.set_mime(mime);
124            }
125        }
126        Ok(body)
127    }
128    fn render_response<T>(&self, template_name: &str, context: &T) -> Result
129    where
130        T: Serialize,
131    {
132        let mut response = Response::new(200);
133        response.set_body(self.render_body(template_name, context)?);
134        Ok(response)
135    }
136    fn render_response_ext<T>(&self, template_name: &str, context: &T, extension: &str) -> Result
137    where
138        T: Serialize,
139    {
140        let mut response = Response::new(200);
141        response.set_body(self.render_body_ext(template_name, context, extension)?);
142        Ok(response)
143    }
144}
145
146pub mod prelude {
147    pub use super::TideHandlebarsExt;
148}
149
150#[cfg(test)]
151mod tests {
152
153    use super::*;
154    use async_std::prelude::*;
155    use std::collections::BTreeMap;
156
157    #[async_std::test]
158    async fn test_body() {
159        let mut handlebars = Handlebars::new();
160
161        handlebars
162            .register_template_file("simple.html", "./tests/templates/simple.html")
163            .unwrap();
164
165        let mut data0 = BTreeMap::new();
166        data0.insert("title".to_string(), "hello tide!".to_string());
167        let mut body = handlebars.render_body("simple.html", &data0).unwrap();
168
169        assert_eq!(body.mime(), &tide::http::mime::HTML);
170
171        let mut body_string = String::new();
172        body.read_to_string(&mut body_string).await.unwrap();
173        assert_eq!(body_string, "<h1>hello tide!</h1>\n");
174    }
175
176    #[async_std::test]
177    async fn response() {
178        let mut handlebars = Handlebars::new();
179        handlebars
180            .register_template_file("simple.html", "./tests/templates/simple.html")
181            .unwrap();
182        let mut data0 = BTreeMap::new();
183        data0.insert("title".to_string(), "hello tide!".to_string());
184
185        let mut response = handlebars.render_response("simple.html", &data0).unwrap();
186
187        assert_eq!(response.content_type(), Some(tide::http::mime::HTML));
188
189        let http_response: &mut tide::http::Response = response.as_mut();
190        let body_string = http_response.body_string().await.unwrap();
191        assert_eq!(body_string, "<h1>hello tide!</h1>\n");
192    }
193
194    #[test]
195    fn unknown_content_type() {
196        let mut handlebars = Handlebars::new();
197        handlebars
198            .register_templates_directory(".hbs", "./tests/templates")
199            .unwrap();
200
201        let mut data0 = BTreeMap::new();
202        data0.insert("title".to_string(), "hello tide!".to_string());
203        let body = handlebars.render_body("simple", &data0).unwrap();
204
205        assert_eq!(body.mime(), &tide::http::mime::PLAIN);
206    }
207    #[test]
208    fn body_with_extension() {
209        let mut handlebars = Handlebars::new();
210        handlebars
211            .register_templates_directory(".hbs", "./tests/templates")
212            .unwrap();
213
214        let mut data0 = BTreeMap::new();
215        data0.insert("title".to_string(), "hello tide!".to_string());
216        let body = handlebars
217            .render_body_ext("simple", &data0, "html")
218            .unwrap();
219
220        assert_eq!(body.mime(), &tide::http::mime::HTML);
221    }
222    #[async_std::test]
223    async fn response_with_extension() {
224        let mut handlebars = Handlebars::new();
225        handlebars
226            .register_templates_directory(".hbs", "./tests/templates")
227            .unwrap();
228        let mut data0 = BTreeMap::new();
229        data0.insert("title".to_string(), "hello tide!".to_string());
230
231        let mut response = handlebars
232            .render_response_ext("simple", &data0, "html")
233            .unwrap();
234
235        assert_eq!(response.content_type(), Some(tide::http::mime::HTML));
236
237        let http_response: &mut tide::http::Response = response.as_mut();
238        let body_string = http_response.body_string().await.unwrap();
239        assert_eq!(body_string, "<h1>hello tide!</h1>\n");
240    }
241    // Templates are validate on load in handlebars -- need to work into the component
242    // #[test]
243    // fn bad_template() {
244    //     let mut handlebars = Handlebars::new();
245    //     handlebars
246    //         .register_templates_directory(".broken", "./tests/templates")
247    //         .unwrap();
248
249    //     let mut data0 = BTreeMap::new();
250    //     data0.insert("title".to_string(), "hello tide!".to_string());
251    //     let result = handlebars.render_body("simple", &data0);
252
253    //     assert!(result.is_err());
254    // }
255}