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}