diff options
-rw-r--r-- | askama_derive/src/generator.rs | 4 | ||||
-rw-r--r-- | askama_derive/src/input.rs | 7 | ||||
-rw-r--r-- | askama_derive/src/lib.rs | 22 | ||||
-rw-r--r-- | askama_shared/src/lib.rs | 70 | ||||
-rw-r--r-- | askama_shared/src/path.rs | 69 |
5 files changed, 92 insertions, 80 deletions
diff --git a/askama_derive/src/generator.rs b/askama_derive/src/generator.rs index 3fce6c9..7bc7b41 100644 --- a/askama_derive/src/generator.rs +++ b/askama_derive/src/generator.rs @@ -491,7 +491,9 @@ impl<'a> Generator<'a> { fn handle_include(&mut self, ctx: &'a Context, ws: WS, path: &str) { self.flush_ws(ws); - let path = path::find_template_from_path(path, Some(&self.input.path)); + let path = self.input + .config + .find_template(path, Some(&self.input.path)); let src = path::get_template_source(&path); let nodes = parser::parse(&src); let nested = { diff --git a/askama_derive/src/input.rs b/askama_derive/src/input.rs index 6e349da..14531cf 100644 --- a/askama_derive/src/input.rs +++ b/askama_derive/src/input.rs @@ -2,7 +2,7 @@ use proc_macro2::TokenStream; use quote::ToTokens; -use shared::path; +use shared::Config; use std::path::PathBuf; @@ -10,6 +10,7 @@ use syn; pub struct TemplateInput<'a> { pub ast: &'a syn::DeriveInput, + pub config: Config, pub source: Source, pub print: Print, pub escaping: EscapeMode, @@ -96,9 +97,10 @@ impl<'a> TemplateInput<'a> { // Validate the `source` and `ext` value together, since they are // related. In case `source` was used instead of `path`, the value // of `ext` is merged into a synthetic `path` value here. + let config = Config::new(); let source = source.expect("template path or source not found in attributes"); let path = match (&source, &ext) { - (&Source::Path(ref path), None) => path::find_template_from_path(path, None), + (&Source::Path(ref path), None) => config.find_template(path, None), (&Source::Source(_), Some(ext)) => PathBuf::from(format!("{}.{}", ast.ident, ext)), (&Source::Path(_), Some(_)) => { panic!("'ext' attribute cannot be used with 'path' attribute") @@ -124,6 +126,7 @@ impl<'a> TemplateInput<'a> { TemplateInput { ast, + config, source, print, escaping: escaping.unwrap_or_else(|| EscapeMode::from_path(&path)), diff --git a/askama_derive/src/lib.rs b/askama_derive/src/lib.rs index 4bdcb0a..c36da67 100644 --- a/askama_derive/src/lib.rs +++ b/askama_derive/src/lib.rs @@ -14,10 +14,10 @@ mod parser; use input::{Print, Source, TemplateInput}; use parser::{Expr, Macro, Node}; use proc_macro::TokenStream; -use shared::path; +use shared::{path, Config}; use std::collections::HashMap; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; #[proc_macro_derive(Template, attributes(template))] pub fn derive_template(input: TokenStream) -> TokenStream { @@ -40,7 +40,7 @@ fn build_template(ast: &syn::DeriveInput) -> String { }; let mut sources = HashMap::new(); - find_used_templates(&mut sources, input.path.clone(), source); + find_used_templates(&input, &mut sources, source); let mut parsed = HashMap::new(); for (path, src) in &sources { @@ -49,7 +49,7 @@ fn build_template(ast: &syn::DeriveInput) -> String { let mut contexts = HashMap::new(); for (path, nodes) in &parsed { - contexts.insert(*path, Context::new(path, nodes)); + contexts.insert(*path, Context::new(&input.config, path, nodes)); } if input.print == Print::Ast || input.print == Print::All { @@ -63,18 +63,18 @@ fn build_template(ast: &syn::DeriveInput) -> String { code } -fn find_used_templates(map: &mut HashMap<PathBuf, String>, path: PathBuf, source: String) { - let mut check = vec![(path, source)]; +fn find_used_templates(input: &TemplateInput, map: &mut HashMap<PathBuf, String>, source: String) { + let mut check = vec![(input.path.clone(), source)]; while let Some((path, source)) = check.pop() { for n in parser::parse(&source) { match n { Node::Extends(Expr::StrLit(extends)) => { - let extends = path::find_template_from_path(extends, Some(&path)); + let extends = input.config.find_template(extends, Some(&path)); let source = path::get_template_source(&extends); check.push((extends, source)); } Node::Import(_, import, _) => { - let import = path::find_template_from_path(import, Some(&path)); + let import = input.config.find_template(import, Some(&path)); let source = path::get_template_source(&import); check.push((import, source)); } @@ -94,7 +94,7 @@ pub(crate) struct Context<'a> { } impl<'a> Context<'a> { - fn new<'n>(path: &PathBuf, nodes: &'n [Node<'n>]) -> Context<'n> { + fn new<'n>(config: &Config, path: &Path, nodes: &'n [Node<'n>]) -> Context<'n> { let mut extends = None; let mut blocks = Vec::new(); let mut macros = HashMap::new(); @@ -105,7 +105,7 @@ impl<'a> Context<'a> { Node::Extends(Expr::StrLit(extends_path)) => match extends { Some(_) => panic!("multiple extend blocks found"), None => { - extends = Some(path::find_template_from_path(extends_path, Some(path))); + extends = Some(config.find_template(extends_path, Some(path))); } }, def @ Node::BlockDef(_, _, _, _) => { @@ -115,7 +115,7 @@ impl<'a> Context<'a> { macros.insert(*name, m); } Node::Import(_, import_path, scope) => { - let path = path::find_template_from_path(import_path, Some(path)); + let path = config.find_template(import_path, Some(path)); imports.insert(*scope, path); } _ => {} diff --git a/askama_shared/src/lib.rs b/askama_shared/src/lib.rs index 2c2a88f..08b243d 100644 --- a/askama_shared/src/lib.rs +++ b/askama_shared/src/lib.rs @@ -9,7 +9,7 @@ extern crate toml; use std::env; use std::fs; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; mod error; mod escaping; @@ -43,6 +43,27 @@ impl Config { Config { dirs } } + + pub fn find_template(&self, path: &str, start_at: Option<&Path>) -> PathBuf { + if let Some(root) = start_at { + let relative = root.with_file_name(path); + if relative.exists() { + return relative.to_owned(); + } + } + + for dir in &self.dirs { + let rooted = dir.join(path); + if rooted.exists() { + return rooted; + } + } + + panic!( + "template {:?} not found in directories {:?}", + path, self.dirs + ) + } } #[derive(Deserialize)] @@ -51,3 +72,50 @@ struct RawConfig { } static CONFIG_FILE_NAME: &str = "askama.toml"; + +#[cfg(test)] +mod tests { + use super::Config; + use std::env; + use std::path::{Path, PathBuf}; + + fn assert_eq_rooted(actual: &Path, expected: &str) { + let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + root.push("templates"); + let mut inner = PathBuf::new(); + inner.push(expected); + assert_eq!(actual.strip_prefix(root).unwrap(), inner); + } + + #[test] + fn find_absolute() { + let config = Config::new(); + let root = config.find_template("a.html", None); + let path = config.find_template("sub/b.html", Some(&root)); + assert_eq_rooted(&path, "sub/b.html"); + } + + #[test] + #[should_panic] + fn find_relative_nonexistent() { + let config = Config::new(); + let root = config.find_template("a.html", None); + config.find_template("b.html", Some(&root)); + } + + #[test] + fn find_relative() { + let config = Config::new(); + let root = config.find_template("sub/b.html", None); + let path = config.find_template("c.html", Some(&root)); + assert_eq_rooted(&path, "sub/c.html"); + } + + #[test] + fn find_relative_sub() { + let config = Config::new(); + let root = config.find_template("sub/b.html", None); + let path = config.find_template("sub1/d.html", Some(&root)); + assert_eq_rooted(&path, "sub/sub1/d.html"); + } +} diff --git a/askama_shared/src/path.rs b/askama_shared/src/path.rs index 568437f..16102b8 100644 --- a/askama_shared/src/path.rs +++ b/askama_shared/src/path.rs @@ -1,7 +1,5 @@ -use super::Config; - use std::fs; -use std::path::{Path, PathBuf}; +use std::path::Path; pub fn get_template_source(tpl_path: &Path) -> String { match fs::read_to_string(tpl_path) { @@ -18,73 +16,14 @@ pub fn get_template_source(tpl_path: &Path) -> String { } } -pub fn find_template_from_path(path: &str, start_at: Option<&Path>) -> PathBuf { - if let Some(root) = start_at { - let relative = root.with_file_name(path); - if relative.exists() { - return relative.to_owned(); - } - } - - let config = Config::new(); - for dir in &config.dirs { - let rooted = dir.join(path); - if rooted.exists() { - return rooted; - } - } - - panic!( - "template {:?} not found in directories {:?}", - path, config.dirs - ) -} - #[cfg(test)] mod tests { - use super::{find_template_from_path, get_template_source}; - use std::env; - use std::path::{Path, PathBuf}; - - fn assert_eq_rooted(actual: &Path, expected: &str) { - let mut root = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); - root.push("templates"); - let mut inner = PathBuf::new(); - inner.push(expected); - assert_eq!(actual.strip_prefix(root).unwrap(), inner); - } + use super::get_template_source; + use Config; #[test] fn get_source() { - let path = find_template_from_path("sub/b.html", None); + let path = Config::new().find_template("sub/b.html", None); assert_eq!(get_template_source(&path), "bar"); } - - #[test] - fn find_absolute() { - let root = find_template_from_path("a.html", None); - let path = find_template_from_path("sub/b.html", Some(&root)); - assert_eq_rooted(&path, "sub/b.html"); - } - - #[test] - #[should_panic] - fn find_relative_nonexistent() { - let root = find_template_from_path("a.html", None); - find_template_from_path("b.html", Some(&root)); - } - - #[test] - fn find_relative() { - let root = find_template_from_path("sub/b.html", None); - let path = find_template_from_path("c.html", Some(&root)); - assert_eq_rooted(&path, "sub/c.html"); - } - - #[test] - fn find_relative_sub() { - let root = find_template_from_path("sub/b.html", None); - let path = find_template_from_path("sub1/d.html", Some(&root)); - assert_eq_rooted(&path, "sub/sub1/d.html"); - } } |