1use std::path::PathBuf;
9use tera::{Context, Tera};
10use tide::{http::Mime, Body, Response, Result};
11
12pub trait TideTeraExt {
16 fn render_response(&self, template_name: &str, context: &Context) -> Result;
30 fn render_body(&self, template_name: &str, context: &Context) -> Result<Body>;
43}
44
45impl TideTeraExt for Tera {
46 fn render_body(&self, template_name: &str, context: &Context) -> Result<Body> {
47 let string = self.render(template_name, context)?;
48 let mut body = Body::from_string(string);
49
50 let path = PathBuf::from(template_name);
51 if let Some(extension) = path.extension() {
52 if let Some(mime) = Mime::from_extension(extension.to_string_lossy()) {
53 body.set_mime(mime)
54 }
55 }
56
57 Ok(body)
58 }
59
60 fn render_response(&self, template_name: &str, context: &tera::Context) -> Result {
61 let mut response = Response::new(200);
62 response.set_body(self.render_body(template_name, context)?);
63 Ok(response)
64 }
65}
66
67#[macro_export]
75macro_rules! context {
76 ($($key:expr => $value:expr,)+) => { context!($($key => $value),+) };
77 ($($key:expr => $value:expr),*) => {
78 {
79 let mut _context = ::tera::Context::new();
80 $(
81 _context.insert($key, &$value);
82 )*
83 _context
84 }
85 };
86}
87
88pub mod prelude {
89 pub use super::{context, TideTeraExt};
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use async_std::prelude::*;
97
98 #[test]
99 fn context() {
100 let context = context! {
101 "key" => "value"
102 };
103
104 assert_eq!(context.into_json()["key"], "value");
105
106 let context = context! { "key1" => "value1", "key2" => "value2" };
107 assert_eq!(context.into_json()["key2"], "value2");
108 }
109
110 #[async_std::test]
111 async fn test_body() {
112 let tera = Tera::new("tests/templates/**/*").unwrap();
113 let mut body = tera
114 .render_body("good_template.html", &context! { "name" => "tide" })
115 .unwrap();
116
117 assert_eq!(body.mime(), &tide::http::mime::HTML);
118
119 let mut body_string = String::new();
120 body.read_to_string(&mut body_string).await.unwrap();
121 assert_eq!(body_string, "hello tide!\n");
122 }
123
124 #[async_std::test]
125 async fn response() {
126 let tera = Tera::new("tests/templates/**/*").unwrap();
127 let mut response = tera
128 .render_response("good_template.html", &context! { "name" => "tide" })
129 .unwrap();
130
131 assert_eq!(response.content_type(), Some(tide::http::mime::HTML));
132
133 let http_response: &mut tide::http::Response = response.as_mut();
134 let body_string = http_response.body_string().await.unwrap();
135 assert_eq!(body_string, "hello tide!\n");
136 }
137
138 #[test]
139 fn unknown_content_type() {
140 let tera = Tera::new("tests/templates/**/*").unwrap();
141 let body = tera
142 .render_body("unknown_extension.tide", &context! { "name" => "tide" })
143 .unwrap();
144
145 assert_eq!(body.mime(), &tide::http::mime::PLAIN);
146 }
147
148 #[test]
149 fn no_extension() {
150 let tera = Tera::new("tests/templates/**/*").unwrap();
151 let body = tera
152 .render_body("no_extension", &context! { "name" => "tide" })
153 .unwrap();
154
155 assert_eq!(body.mime(), &tide::http::mime::PLAIN);
156 }
157
158 #[test]
159 fn bad_template() {
160 let tera = Tera::new("tests/templates/**/*").unwrap();
161 let result = tera.render_body("good_template.html", &context! { "framework" => "tide" });
162
163 assert!(result.is_err());
164 }
165}