Skip to content

Commit

Permalink
Support minijinja in 'dyn_templates'.
Browse files Browse the repository at this point in the history
  • Loading branch information
SergioBenitez committed Apr 3, 2024
1 parent 0edbb6d commit 8614a7f
Show file tree
Hide file tree
Showing 17 changed files with 781 additions and 529 deletions.
20 changes: 9 additions & 11 deletions contrib/dyn_templates/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,26 @@ type_complexity = "allow"
multiple_bound_locations = "allow"

[features]
tera = ["tera_"]
handlebars = ["handlebars_"]
tera = ["dep:tera"]
handlebars = ["dep:handlebars"]
minijinja = ["dep:minijinja"]

[dependencies]
walkdir = "2.4"
notify = "6"
normpath = "1"

tera = { version = "1.19.0", optional = true }
handlebars = { version = "5.1", optional = true }
minijinja = { version = "1.0.16", optional = true, features = ["loader"] }

[dependencies.rocket]
version = "0.6.0-dev"
path = "../../core/lib"
default-features = false

[dependencies.tera_]
package = "tera"
version = "1.10.0"
optional = true

[dependencies.handlebars_]
package = "handlebars"
version = "5.1"
optional = true
[dev-dependencies]
pretty_assertions = "1.4"

[package.metadata.docs.rs]
all-features = true
5 changes: 3 additions & 2 deletions contrib/dyn_templates/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::error::Error;

use crate::{Engines, TemplateInfo};
use crate::engine::Engines;
use crate::template::TemplateInfo;

use rocket::http::ContentType;
use normpath::PathExt;
Expand Down Expand Up @@ -99,7 +100,7 @@ impl Context {
#[cfg(not(debug_assertions))]
mod manager {
use std::ops::Deref;
use crate::Context;
use super::Context;

/// Wraps a Context. With `cfg(debug_assertions)` active, this structure
/// additionally provides a method to reload the context at runtime.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::path::Path;

use handlebars::Handlebars;
use rocket::serde::Serialize;

use crate::engine::Engine;
pub use crate::handlebars::Handlebars;

impl Engine for Handlebars<'static> {
const EXT: &'static str = "hbs";
Expand Down
55 changes: 55 additions & 0 deletions contrib/dyn_templates/src/engine/minijinja.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use std::sync::Arc;
use std::path::Path;
use std::collections::HashMap;

use rocket::serde::Serialize;
use minijinja::{Environment, Error, ErrorKind, AutoEscape};

use crate::engine::Engine;

impl Engine for Environment<'static> {
const EXT: &'static str = "j2";

fn init<'a>(templates: impl Iterator<Item = (&'a str, &'a Path)>) -> Option<Self> {
let _templates = Arc::new(templates
.map(|(k, p)| (k.to_owned(), p.to_owned()))
.collect::<HashMap<_, _>>());

let templates = _templates.clone();
let mut env = Environment::new();
env.set_loader(move |name| {
let Some(path) = templates.get(name) else {
return Ok(None);
};

match std::fs::read_to_string(path) {
Ok(result) => Ok(Some(result)),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(None),
Err(e) => Err(
Error::new(ErrorKind::InvalidOperation, "template read failed").with_source(e)
),
}
});

let templates = _templates.clone();
env.set_auto_escape_callback(move |name| {
templates.get(name)
.and_then(|path| path.to_str())
.map(minijinja::default_auto_escape_callback)
.unwrap_or(AutoEscape::None)
});

Some(env)
}

fn render<C: Serialize>(&self, name: &str, context: C) -> Option<String> {
let Ok(template) = self.get_template(name) else {
error_!("Minijinja template '{name}' was not found.");
return None;
};

template.render(context)
.map_err(|e| error_!("Minijinja: {}", e))
.ok()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,22 @@ use std::collections::HashMap;

use rocket::serde::Serialize;

use crate::TemplateInfo;
use crate::template::TemplateInfo;

#[cfg(feature = "tera")] use crate::tera::Tera;
#[cfg(feature = "handlebars")] use crate::handlebars::Handlebars;
#[cfg(feature = "tera")]
mod tera;
#[cfg(feature = "tera")]
use ::tera::Tera;

#[cfg(feature = "handlebars")]
mod handlebars;
#[cfg(feature = "handlebars")]
use ::handlebars::Handlebars;

#[cfg(feature = "minijinja")]
mod minijinja;
#[cfg(feature = "minijinja")]
use ::minijinja::Environment;

pub(crate) trait Engine: Send + Sync + Sized + 'static {
const EXT: &'static str;
Expand Down Expand Up @@ -52,24 +64,38 @@ pub(crate) trait Engine: Send + Sync + Sized + 'static {
/// [`tera::Value`]: crate::tera::Value
/// [`tera::Result`]: crate::tera::Result
pub struct Engines {
/// A `Tera` templating engine. This field is only available when the
/// `tera_templates` feature is enabled. When calling methods on the `Tera`
/// instance, ensure you use types imported from
/// `rocket_dyn_templates::tera` to avoid version mismatches.
/// A `Tera` templating engine.
///
/// This field is only available when the `tera` feature is enabled. When
/// calling methods on the `Tera` instance, ensure you use types imported
/// from `rocket_dyn_templates::tera` to avoid version mismatches.
#[cfg(feature = "tera")]
pub tera: Tera,
/// The Handlebars templating engine. This field is only available when the
/// `handlebars_templates` feature is enabled. When calling methods on the
/// `Handlebars` instance, ensure you use types imported from
/// `rocket_dyn_templates::handlebars` to avoid version mismatches.

/// The Handlebars templating engine.
///
/// This field is only available when the `handlebars` feature is enabled.
/// When calling methods on the `Handlebars` instance, ensure you use types
/// imported from `rocket_dyn_templates::handlebars` to avoid version
/// mismatches.
#[cfg(feature = "handlebars")]
pub handlebars: Handlebars<'static>,

/// The minijinja templating engine.
///
/// This field is only available when the `minijinja` feature is enabled.
/// When calling methods on the [`Environment`] instance, ensure you use
/// types imported from `rocket_dyn_templates::minijinja` to avoid version
/// mismatches.
#[cfg(feature = "minijinja")]
pub minijinja: Environment<'static>,
}

impl Engines {
pub(crate) const ENABLED_EXTENSIONS: &'static [&'static str] = &[
#[cfg(feature = "tera")] Tera::EXT,
#[cfg(feature = "handlebars")] Handlebars::EXT,
#[cfg(feature = "minijinja")] Environment::EXT,
];

pub(crate) fn init(templates: &HashMap<String, TemplateInfo>) -> Option<Engines> {
Expand All @@ -93,14 +119,19 @@ impl Engines {
Some(hb) => hb,
None => return None
},
#[cfg(feature = "minijinja")]
minijinja: match inner::<Environment<'static>>(templates) {
Some(hb) => hb,
None => return None
},
})
}

pub(crate) fn render<C: Serialize>(
&self,
name: &str,
info: &TemplateInfo,
context: C
context: C,
) -> Option<String> {
#[cfg(feature = "tera")] {
if info.engine_ext == Tera::EXT {
Expand All @@ -114,6 +145,12 @@ impl Engines {
}
}

#[cfg(feature = "minijinja")] {
if info.engine_ext == Environment::EXT {
return Engine::render(&self.minijinja, name, context);
}
}

None
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::path::Path;
use std::error::Error;

use tera::{Context, Tera};
use rocket::serde::Serialize;

use crate::engine::Engine;

pub use crate::tera::{Context, Tera};

impl Engine for Tera {
const EXT: &'static str = "tera";

Expand Down
7 changes: 4 additions & 3 deletions contrib/dyn_templates/src/fairing.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::{DEFAULT_TEMPLATE_DIR, Context, Engines};
use crate::context::{Callback, ContextManager};

use rocket::{Rocket, Build, Orbit};
use rocket::fairing::{self, Fairing, Info, Kind};

use crate::context::{Callback, Context, ContextManager};
use crate::template::DEFAULT_TEMPLATE_DIR;
use crate::engine::Engines;

/// The TemplateFairing initializes the template system on attach, running
/// custom_callback after templates have been loaded. In debug mode, the fairing
/// checks for modifications to templates before every request and reloads them
Expand Down
Loading

0 comments on commit 8614a7f

Please sign in to comment.