aboutsummaryrefslogtreecommitdiffstats
path: root/askama_mendes
diff options
context:
space:
mode:
Diffstat (limited to 'askama_mendes')
-rw-r--r--askama_mendes/Cargo.toml23
-rw-r--r--askama_mendes/README.md9
-rw-r--r--askama_mendes/src/lib.rs39
-rw-r--r--askama_mendes/templates/hello.txt1
-rw-r--r--askama_mendes/tests/basic.rs96
5 files changed, 168 insertions, 0 deletions
diff --git a/askama_mendes/Cargo.toml b/askama_mendes/Cargo.toml
new file mode 100644
index 0000000..34eeb11
--- /dev/null
+++ b/askama_mendes/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "askama_mendes"
+version = "0.1.0"
+description = "Mendes integration for Askama templates"
+documentation = "https://docs.rs/askama"
+keywords = ["markup", "template", "jinja2", "html"]
+categories = ["template-engine"]
+homepage = "https://github.com/djc/askama"
+repository = "https://github.com/djc/askama"
+license = "MIT OR Apache-2.0"
+workspace = ".."
+readme = "README.md"
+edition = "2018"
+
+[dependencies]
+askama = { version = "0.11.0-beta.1", path = "../askama", default-features = false, features = ["with-mendes", "mime", "mime_guess"] }
+mendes = "0.0.59"
+mime_guess = "2.0.3"
+
+[dev-dependencies]
+async-trait = "0.1.51"
+hyper = "0.14.15"
+tokio = { version = "1.12", features = ["macros", "rt-multi-thread"] }
diff --git a/askama_mendes/README.md b/askama_mendes/README.md
new file mode 100644
index 0000000..f91ffbd
--- /dev/null
+++ b/askama_mendes/README.md
@@ -0,0 +1,9 @@
+# askama_mendes: Askama integration with Mendes
+
+[![Documentation](https://docs.rs/askama_mendes/badge.svg)](https://docs.rs/askama_mendes/)
+[![Latest version](https://img.shields.io/crates/v/askama_mendes.svg)](https://crates.io/crates/askama_mendes)
+[![Build Status](https://github.com/djc/askama/workflows/CI/badge.svg)](https://github.com/djc/askama/actions?query=workflow%3ACI)
+[![Chat](https://badges.gitter.im/gitterHQ/gitter.svg)](https://gitter.im/djc/askama)
+
+Integration of the [Askama](https://github.com/djc/askama) templating engine in
+code building on the [Mendes](https://github.com/djc/mendes) framework.
diff --git a/askama_mendes/src/lib.rs b/askama_mendes/src/lib.rs
new file mode 100644
index 0000000..8f32269
--- /dev/null
+++ b/askama_mendes/src/lib.rs
@@ -0,0 +1,39 @@
+#![deny(elided_lifetimes_in_paths)]
+
+use std::convert::TryFrom;
+
+use mendes::application::{Application, Responder};
+use mendes::http::header::{HeaderValue, CONTENT_LENGTH, CONTENT_TYPE};
+use mendes::http::request::Parts;
+use mendes::http::Response;
+use mime_guess::MimeGuess;
+
+pub use askama::*;
+
+pub fn into_response<A, T>(
+ app: &A,
+ req: &Parts,
+ t: &T,
+ ext: Option<&str>,
+) -> Response<A::ResponseBody>
+where
+ A: Application,
+ T: Template,
+ A::ResponseBody: From<String>,
+ A::Error: From<askama::Error>,
+{
+ let content = match t.render() {
+ Ok(content) => content,
+ Err(e) => return <A::Error as From<_>>::from(e).into_response(app, req),
+ };
+
+ let mut builder = Response::builder();
+ builder = builder.header(CONTENT_LENGTH, content.len());
+ if let Some(ext) = ext {
+ if let Some(ty) = MimeGuess::from_ext(ext).first() {
+ builder = builder.header(CONTENT_TYPE, HeaderValue::try_from(ty.as_ref()).unwrap());
+ }
+ }
+
+ builder.body(content.into()).unwrap()
+}
diff --git a/askama_mendes/templates/hello.txt b/askama_mendes/templates/hello.txt
new file mode 100644
index 0000000..8149be7
--- /dev/null
+++ b/askama_mendes/templates/hello.txt
@@ -0,0 +1 @@
+Hello, {{ name }}!
diff --git a/askama_mendes/tests/basic.rs b/askama_mendes/tests/basic.rs
new file mode 100644
index 0000000..2a07c13
--- /dev/null
+++ b/askama_mendes/tests/basic.rs
@@ -0,0 +1,96 @@
+use std::sync::Arc;
+
+use async_trait::async_trait;
+use hyper::body::to_bytes;
+use hyper::{Body, Request};
+use mendes::application::Responder;
+use mendes::http::request::Parts;
+use mendes::http::{Response, StatusCode};
+use mendes::{handler, route, Application, Context};
+
+use askama::Template;
+
+#[tokio::test]
+async fn test() {
+ let req = Request::builder().body(()).unwrap();
+ let rsp = App::handle(Context::new(Arc::new(App), req)).await;
+ let (rsp, body) = rsp.into_parts();
+ assert_eq!(
+ rsp.headers
+ .get("content-type")
+ .and_then(|hv| hv.to_str().ok()),
+ Some("text/plain")
+ );
+ assert_eq!(to_bytes(body).await.unwrap(), &b"Hello, world!"[..]);
+}
+
+#[handler(GET)]
+async fn hello(_: &App) -> Result<HelloTemplate<'static>, Error> {
+ Ok(HelloTemplate { name: "world" })
+}
+
+#[derive(Template)]
+#[template(path = "hello.txt")]
+struct HelloTemplate<'a> {
+ name: &'a str,
+}
+
+struct App;
+
+#[async_trait]
+impl Application for App {
+ type RequestBody = ();
+ type ResponseBody = Body;
+ type Error = Error;
+
+ async fn handle(mut cx: Context<Self>) -> Response<Body> {
+ route!(match cx.path() {
+ _ => hello,
+ })
+ }
+}
+
+#[derive(Debug)]
+enum Error {
+ Askama(askama::Error),
+ Mendes(mendes::Error),
+}
+
+impl From<askama::Error> for Error {
+ fn from(e: askama::Error) -> Error {
+ Error::Askama(e)
+ }
+}
+
+impl From<mendes::Error> for Error {
+ fn from(e: mendes::Error) -> Error {
+ Error::Mendes(e)
+ }
+}
+
+impl std::fmt::Display for Error {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Error::Askama(e) => write!(f, "{}", e),
+ Error::Mendes(e) => write!(f, "{}", e),
+ }
+ }
+}
+
+impl Responder<App> for Error {
+ fn into_response(self, _: &App, _: &Parts) -> Response<Body> {
+ Response::builder()
+ .status(StatusCode::from(&self))
+ .body(self.to_string().into())
+ .unwrap()
+ }
+}
+
+impl From<&Error> for StatusCode {
+ fn from(e: &Error) -> StatusCode {
+ match e {
+ Error::Mendes(e) => StatusCode::from(e),
+ Error::Askama(_) => StatusCode::INTERNAL_SERVER_ERROR,
+ }
+ }
+}