From a97779567e64d5257d67e1f91d0c15c24e657467 Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Tue, 11 May 2021 18:05:00 +0200 Subject: [PATCH] Split Tera functions in several files --- .../templates/src/global_fns/content.rs | 324 +++++++++++++ components/templates/src/global_fns/images.rs | 120 +++++ components/templates/src/global_fns/mod.rs | 426 +----------------- 3 files changed, 448 insertions(+), 422 deletions(-) create mode 100644 components/templates/src/global_fns/content.rs create mode 100644 components/templates/src/global_fns/images.rs diff --git a/components/templates/src/global_fns/content.rs b/components/templates/src/global_fns/content.rs new file mode 100644 index 00000000..91f2387f --- /dev/null +++ b/components/templates/src/global_fns/content.rs @@ -0,0 +1,324 @@ +use library::{Library, Taxonomy}; +use std::collections::HashMap; +use std::path::PathBuf; +use std::sync::{Arc, RwLock}; +use tera::{from_value, to_value, Function as TeraFn, Result, Value}; +use utils::slugs::{slugify_paths, SlugifyStrategy}; + +#[derive(Debug)] +pub struct GetTaxonomyUrl { + taxonomies: HashMap>, + default_lang: String, + slugify: SlugifyStrategy, +} + +impl GetTaxonomyUrl { + pub fn new(default_lang: &str, all_taxonomies: &[Taxonomy], slugify: SlugifyStrategy) -> Self { + let mut taxonomies = HashMap::new(); + for taxo in all_taxonomies { + let mut items = HashMap::new(); + for item in &taxo.items { + items.insert(slugify_paths(&item.name.clone(), slugify), item.permalink.clone()); + } + taxonomies.insert(format!("{}-{}", taxo.kind.name, taxo.lang), items); + } + Self { taxonomies, default_lang: default_lang.to_string(), slugify } + } +} +impl TeraFn for GetTaxonomyUrl { + fn call(&self, args: &HashMap) -> Result { + let kind = required_arg!( + String, + args.get("kind"), + "`get_taxonomy_url` requires a `kind` argument with a string value" + ); + let name = required_arg!( + String, + args.get("name"), + "`get_taxonomy_url` requires a `name` argument with a string value" + ); + let lang = + optional_arg!(String, args.get("lang"), "`get_taxonomy`: `lang` must be a string") + .unwrap_or_else(|| self.default_lang.clone()); + + let container = match self.taxonomies.get(&format!("{}-{}", kind, lang)) { + Some(c) => c, + None => { + return Err(format!( + "`get_taxonomy_url` received an unknown taxonomy as kind: {}", + kind + ) + .into()); + } + }; + + if let Some(permalink) = container.get(&slugify_paths(&name, self.slugify)) { + return Ok(to_value(permalink).unwrap()); + } + + Err(format!("`get_taxonomy_url`: couldn't find `{}` in `{}` taxonomy", name, kind).into()) + } +} + +#[derive(Debug)] +pub struct GetPage { + base_path: PathBuf, + library: Arc>, +} +impl GetPage { + pub fn new(base_path: PathBuf, library: Arc>) -> Self { + Self { base_path: base_path.join("content"), library } + } +} +impl TeraFn for GetPage { + fn call(&self, args: &HashMap) -> Result { + let path = required_arg!( + String, + args.get("path"), + "`get_page` requires a `path` argument with a string value" + ); + let full_path = self.base_path.join(&path); + let library = self.library.read().unwrap(); + match library.get_page(&full_path) { + Some(p) => Ok(to_value(p.to_serialized(&library)).unwrap()), + None => Err(format!("Page `{}` not found.", path).into()), + } + } +} + +#[derive(Debug)] +pub struct GetSection { + base_path: PathBuf, + library: Arc>, +} +impl GetSection { + pub fn new(base_path: PathBuf, library: Arc>) -> Self { + Self { base_path: base_path.join("content"), library } + } +} +impl TeraFn for GetSection { + fn call(&self, args: &HashMap) -> Result { + let path = required_arg!( + String, + args.get("path"), + "`get_section` requires a `path` argument with a string value" + ); + + let metadata_only = args + .get("metadata_only") + .map_or(false, |c| from_value::(c.clone()).unwrap_or(false)); + + let full_path = self.base_path.join(&path); + let library = self.library.read().unwrap(); + + match library.get_section(&full_path) { + Some(s) => { + if metadata_only { + Ok(to_value(s.to_serialized_basic(&library)).unwrap()) + } else { + Ok(to_value(s.to_serialized(&library)).unwrap()) + } + } + None => Err(format!("Section `{}` not found.", path).into()), + } + } +} + +#[derive(Debug)] +pub struct GetTaxonomy { + library: Arc>, + taxonomies: HashMap, + default_lang: String, +} +impl GetTaxonomy { + pub fn new( + default_lang: &str, + all_taxonomies: Vec, + library: Arc>, + ) -> Self { + let mut taxonomies = HashMap::new(); + for taxo in all_taxonomies { + taxonomies.insert(format!("{}-{}", taxo.kind.name, taxo.lang), taxo); + } + Self { taxonomies, library, default_lang: default_lang.to_string() } + } +} +impl TeraFn for GetTaxonomy { + fn call(&self, args: &HashMap) -> Result { + let kind = required_arg!( + String, + args.get("kind"), + "`get_taxonomy` requires a `kind` argument with a string value" + ); + + let lang = + optional_arg!(String, args.get("lang"), "`get_taxonomy`: `lang` must be a string") + .unwrap_or_else(|| self.default_lang.clone()); + + match self.taxonomies.get(&format!("{}-{}", kind, lang)) { + Some(t) => Ok(to_value(t.to_serialized(&self.library.read().unwrap())).unwrap()), + None => { + Err(format!("`get_taxonomy` received an unknown taxonomy as kind: {}", kind).into()) + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use config::{Config, Taxonomy as TaxonomyConfig}; + use library::TaxonomyItem; + + #[test] + fn can_get_taxonomy() { + let mut config = Config::default(); + config.slugify.taxonomies = SlugifyStrategy::On; + let taxo_config = TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; + let taxo_config_fr = + TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; + let library = Arc::new(RwLock::new(Library::new(0, 0, false))); + let tag = TaxonomyItem::new( + "Programming", + &config.default_language, + "tags", + &config, + vec![], + &library.read().unwrap(), + ); + let tag_fr = TaxonomyItem::new( + "Programmation", + "fr", + "tags", + &config, + vec![], + &library.read().unwrap(), + ); + let tags = Taxonomy { + kind: taxo_config, + lang: config.default_language.clone(), + slug: "tags".to_string(), + items: vec![tag], + }; + let tags_fr = Taxonomy { + kind: taxo_config_fr, + lang: "fr".to_owned(), + slug: "tags".to_string(), + items: vec![tag_fr], + }; + + let taxonomies = vec![tags.clone(), tags_fr.clone()]; + let static_fn = + GetTaxonomy::new(&config.default_language, taxonomies.clone(), library.clone()); + // can find it correctly + let mut args = HashMap::new(); + args.insert("kind".to_string(), to_value("tags").unwrap()); + let res = static_fn.call(&args).unwrap(); + let res_obj = res.as_object().unwrap(); + assert_eq!(res_obj["kind"], to_value(tags.kind).unwrap()); + assert_eq!(res_obj["items"].clone().as_array().unwrap().len(), 1); + assert_eq!( + res_obj["items"].clone().as_array().unwrap()[0].clone().as_object().unwrap()["name"], + Value::String("Programming".to_string()) + ); + assert_eq!( + res_obj["items"].clone().as_array().unwrap()[0].clone().as_object().unwrap()["slug"], + Value::String("programming".to_string()) + ); + assert_eq!( + res_obj["items"].clone().as_array().unwrap()[0].clone().as_object().unwrap() + ["permalink"], + Value::String("http://a-website.com/tags/programming/".to_string()) + ); + assert_eq!( + res_obj["items"].clone().as_array().unwrap()[0].clone().as_object().unwrap()["pages"], + Value::Array(vec![]) + ); + // Works with other languages as well + let mut args = HashMap::new(); + args.insert("kind".to_string(), to_value("tags").unwrap()); + args.insert("lang".to_string(), to_value("fr").unwrap()); + let res = static_fn.call(&args).unwrap(); + let res_obj = res.as_object().unwrap(); + assert_eq!(res_obj["kind"], to_value(tags_fr.kind).unwrap()); + assert_eq!(res_obj["items"].clone().as_array().unwrap().len(), 1); + assert_eq!( + res_obj["items"].clone().as_array().unwrap()[0].clone().as_object().unwrap()["name"], + Value::String("Programmation".to_string()) + ); + + // and errors if it can't find it + let mut args = HashMap::new(); + args.insert("kind".to_string(), to_value("something-else").unwrap()); + assert!(static_fn.call(&args).is_err()); + } + + #[test] + fn can_get_taxonomy_url() { + let mut config = Config::default(); + config.slugify.taxonomies = SlugifyStrategy::On; + let taxo_config = TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; + let taxo_config_fr = + TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; + let library = Library::new(0, 0, false); + let tag = TaxonomyItem::new( + "Programming", + &config.default_language, + "tags", + &config, + vec![], + &library, + ); + let tag_fr = TaxonomyItem::new("Programmation", "fr", "tags", &config, vec![], &library); + let tags = Taxonomy { + kind: taxo_config, + lang: config.default_language.clone(), + slug: "tags".to_string(), + items: vec![tag], + }; + let tags_fr = Taxonomy { + kind: taxo_config_fr, + lang: "fr".to_owned(), + slug: "tags".to_string(), + items: vec![tag_fr], + }; + + let taxonomies = vec![tags.clone(), tags_fr.clone()]; + let static_fn = + GetTaxonomyUrl::new(&config.default_language, &taxonomies, config.slugify.taxonomies); + + // can find it correctly + let mut args = HashMap::new(); + args.insert("kind".to_string(), to_value("tags").unwrap()); + args.insert("name".to_string(), to_value("Programming").unwrap()); + assert_eq!( + static_fn.call(&args).unwrap(), + to_value("http://a-website.com/tags/programming/").unwrap() + ); + + // can find it correctly with inconsistent capitalisation + let mut args = HashMap::new(); + args.insert("kind".to_string(), to_value("tags").unwrap()); + args.insert("name".to_string(), to_value("programming").unwrap()); + assert_eq!( + static_fn.call(&args).unwrap(), + to_value("http://a-website.com/tags/programming/").unwrap() + ); + + // works with other languages + let mut args = HashMap::new(); + args.insert("kind".to_string(), to_value("tags").unwrap()); + args.insert("name".to_string(), to_value("Programmation").unwrap()); + args.insert("lang".to_string(), to_value("fr").unwrap()); + assert_eq!( + static_fn.call(&args).unwrap(), + to_value("http://a-website.com/fr/tags/programmation/").unwrap() + ); + + // and errors if it can't find it + let mut args = HashMap::new(); + args.insert("kind".to_string(), to_value("tags").unwrap()); + args.insert("name".to_string(), to_value("random").unwrap()); + assert!(static_fn.call(&args).is_err()); + } +} diff --git a/components/templates/src/global_fns/images.rs b/components/templates/src/global_fns/images.rs new file mode 100644 index 00000000..d225ecdb --- /dev/null +++ b/components/templates/src/global_fns/images.rs @@ -0,0 +1,120 @@ +use std::collections::HashMap; +use std::ffi::OsStr; +use std::path::PathBuf; +use std::sync::{Arc, Mutex}; + +use image::GenericImageView; +use svg_metadata as svg; +use tera::{from_value, to_value, Error, Function as TeraFn, Result, Value}; + +#[derive(Debug)] +pub struct ResizeImage { + imageproc: Arc>, +} +impl ResizeImage { + pub fn new(imageproc: Arc>) -> Self { + Self { imageproc } + } +} + +static DEFAULT_OP: &str = "fill"; +static DEFAULT_FMT: &str = "auto"; + +impl TeraFn for ResizeImage { + fn call(&self, args: &HashMap) -> Result { + let path = required_arg!( + String, + args.get("path"), + "`resize_image` requires a `path` argument with a string value" + ); + let width = optional_arg!( + u32, + args.get("width"), + "`resize_image`: `width` must be a non-negative integer" + ); + let height = optional_arg!( + u32, + args.get("height"), + "`resize_image`: `height` must be a non-negative integer" + ); + let op = optional_arg!(String, args.get("op"), "`resize_image`: `op` must be a string") + .unwrap_or_else(|| DEFAULT_OP.to_string()); + + let format = + optional_arg!(String, args.get("format"), "`resize_image`: `format` must be a string") + .unwrap_or_else(|| DEFAULT_FMT.to_string()); + + let quality = + optional_arg!(u8, args.get("quality"), "`resize_image`: `quality` must be a number"); + if let Some(quality) = quality { + if quality == 0 || quality > 100 { + return Err("`resize_image`: `quality` must be in range 1-100".to_string().into()); + } + } + + let mut imageproc = self.imageproc.lock().unwrap(); + if !imageproc.source_exists(&path) { + return Err(format!("`resize_image`: Cannot find path: {}", path).into()); + } + + let imageop = imageproc::ImageOp::from_args(path, &op, width, height, &format, quality) + .map_err(|e| format!("`resize_image`: {}", e))?; + let url = imageproc.insert(imageop); + + to_value(url).map_err(|err| err.into()) + } +} + +#[derive(Debug)] +pub struct GetImageMeta { + content_path: PathBuf, +} + +impl GetImageMeta { + pub fn new(content_path: PathBuf) -> Self { + Self { content_path } + } +} + +impl TeraFn for GetImageMeta { + fn call(&self, args: &HashMap) -> Result { + let path = required_arg!( + String, + args.get("path"), + "`get_image_metadata` requires a `path` argument with a string value" + ); + let src_path = self.content_path.join(&path); + if !src_path.exists() { + return Err(format!("`get_image_metadata`: Cannot find path: {}", path).into()); + } + let (height, width) = image_dimensions(&src_path)?; + let mut map = tera::Map::new(); + map.insert(String::from("height"), Value::Number(tera::Number::from(height))); + map.insert(String::from("width"), Value::Number(tera::Number::from(width))); + Ok(Value::Object(map)) + } +} + +// Try to read the image dimensions for a given image +fn image_dimensions(path: &PathBuf) -> Result<(u32, u32)> { + if let Some("svg") = path.extension().and_then(OsStr::to_str) { + let img = svg::Metadata::parse_file(&path) + .map_err(|e| Error::chain(format!("Failed to process SVG: {}", path.display()), e))?; + match (img.height(), img.width(), img.view_box()) { + (Some(h), Some(w), _) => Ok((h as u32, w as u32)), + (_, _, Some(view_box)) => Ok((view_box.height as u32, view_box.width as u32)), + _ => Err("Invalid dimensions: SVG width/height and viewbox not set.".into()), + } + } else { + let img = image::open(&path) + .map_err(|e| Error::chain(format!("Failed to process image: {}", path.display()), e))?; + Ok((img.height(), img.width())) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // TODO +} diff --git a/components/templates/src/global_fns/mod.rs b/components/templates/src/global_fns/mod.rs index 598ce118..363f60ad 100644 --- a/components/templates/src/global_fns/mod.rs +++ b/components/templates/src/global_fns/mod.rs @@ -1,25 +1,23 @@ use std::collections::HashMap; -use std::ffi::OsStr; use std::path::PathBuf; -use std::sync::{Arc, Mutex, RwLock}; use std::{fs, io, result}; use base64::encode as encode_b64; use sha2::{digest, Sha256, Sha384, Sha512}; -use svg_metadata as svg; use tera::{from_value, to_value, Error, Function as TeraFn, Result, Value}; use config::Config; -use image::GenericImageView; -use library::{Library, Taxonomy}; use utils::site::resolve_internal_link; -use utils::slugs::{slugify_paths, SlugifyStrategy}; #[macro_use] mod macros; +mod content; +mod images; mod load_data; +pub use self::content::{GetPage, GetSection, GetTaxonomy, GetTaxonomyUrl}; +pub use self::images::{GetImageMeta, ResizeImage}; pub use self::load_data::LoadData; #[derive(Debug)] @@ -238,270 +236,6 @@ impl TeraFn for GetFileHash { } } -#[derive(Debug)] -pub struct ResizeImage { - imageproc: Arc>, -} -impl ResizeImage { - pub fn new(imageproc: Arc>) -> Self { - Self { imageproc } - } -} - -static DEFAULT_OP: &str = "fill"; -static DEFAULT_FMT: &str = "auto"; - -impl TeraFn for ResizeImage { - fn call(&self, args: &HashMap) -> Result { - let path = required_arg!( - String, - args.get("path"), - "`resize_image` requires a `path` argument with a string value" - ); - let width = optional_arg!( - u32, - args.get("width"), - "`resize_image`: `width` must be a non-negative integer" - ); - let height = optional_arg!( - u32, - args.get("height"), - "`resize_image`: `height` must be a non-negative integer" - ); - let op = optional_arg!(String, args.get("op"), "`resize_image`: `op` must be a string") - .unwrap_or_else(|| DEFAULT_OP.to_string()); - - let format = - optional_arg!(String, args.get("format"), "`resize_image`: `format` must be a string") - .unwrap_or_else(|| DEFAULT_FMT.to_string()); - - let quality = - optional_arg!(u8, args.get("quality"), "`resize_image`: `quality` must be a number"); - if let Some(quality) = quality { - if quality == 0 || quality > 100 { - return Err("`resize_image`: `quality` must be in range 1-100".to_string().into()); - } - } - - let mut imageproc = self.imageproc.lock().unwrap(); - if !imageproc.source_exists(&path) { - return Err(format!("`resize_image`: Cannot find path: {}", path).into()); - } - - let imageop = imageproc::ImageOp::from_args(path, &op, width, height, &format, quality) - .map_err(|e| format!("`resize_image`: {}", e))?; - let url = imageproc.insert(imageop); - - to_value(url).map_err(|err| err.into()) - } -} - -#[derive(Debug)] -pub struct GetImageMeta { - content_path: PathBuf, -} - -impl GetImageMeta { - pub fn new(content_path: PathBuf) -> Self { - Self { content_path } - } -} - -impl TeraFn for GetImageMeta { - fn call(&self, args: &HashMap) -> Result { - let path = required_arg!( - String, - args.get("path"), - "`get_image_metadata` requires a `path` argument with a string value" - ); - let src_path = self.content_path.join(&path); - if !src_path.exists() { - return Err(format!("`get_image_metadata`: Cannot find path: {}", path).into()); - } - let (height, width) = image_dimensions(&src_path)?; - let mut map = tera::Map::new(); - map.insert(String::from("height"), Value::Number(tera::Number::from(height))); - map.insert(String::from("width"), Value::Number(tera::Number::from(width))); - Ok(Value::Object(map)) - } -} - -// Try to read the image dimensions for a given image -fn image_dimensions(path: &PathBuf) -> Result<(u32, u32)> { - if let Some("svg") = path.extension().and_then(OsStr::to_str) { - let img = svg::Metadata::parse_file(&path) - .map_err(|e| Error::chain(format!("Failed to process SVG: {}", path.display()), e))?; - match (img.height(), img.width(), img.view_box()) { - (Some(h), Some(w), _) => Ok((h as u32, w as u32)), - (_, _, Some(view_box)) => Ok((view_box.height as u32, view_box.width as u32)), - _ => Err("Invalid dimensions: SVG width/height and viewbox not set.".into()), - } - } else { - let img = image::open(&path) - .map_err(|e| Error::chain(format!("Failed to process image: {}", path.display()), e))?; - Ok((img.height(), img.width())) - } -} - -#[derive(Debug)] -pub struct GetTaxonomyUrl { - taxonomies: HashMap>, - default_lang: String, - slugify: SlugifyStrategy, -} - -impl GetTaxonomyUrl { - pub fn new(default_lang: &str, all_taxonomies: &[Taxonomy], slugify: SlugifyStrategy) -> Self { - let mut taxonomies = HashMap::new(); - for taxo in all_taxonomies { - let mut items = HashMap::new(); - for item in &taxo.items { - items.insert(slugify_paths(&item.name.clone(), slugify), item.permalink.clone()); - } - taxonomies.insert(format!("{}-{}", taxo.kind.name, taxo.lang), items); - } - Self { taxonomies, default_lang: default_lang.to_string(), slugify } - } -} -impl TeraFn for GetTaxonomyUrl { - fn call(&self, args: &HashMap) -> Result { - let kind = required_arg!( - String, - args.get("kind"), - "`get_taxonomy_url` requires a `kind` argument with a string value" - ); - let name = required_arg!( - String, - args.get("name"), - "`get_taxonomy_url` requires a `name` argument with a string value" - ); - let lang = - optional_arg!(String, args.get("lang"), "`get_taxonomy`: `lang` must be a string") - .unwrap_or_else(|| self.default_lang.clone()); - - let container = match self.taxonomies.get(&format!("{}-{}", kind, lang)) { - Some(c) => c, - None => { - return Err(format!( - "`get_taxonomy_url` received an unknown taxonomy as kind: {}", - kind - ) - .into()); - } - }; - - if let Some(permalink) = container.get(&slugify_paths(&name, self.slugify)) { - return Ok(to_value(permalink).unwrap()); - } - - Err(format!("`get_taxonomy_url`: couldn't find `{}` in `{}` taxonomy", name, kind).into()) - } -} - -#[derive(Debug)] -pub struct GetPage { - base_path: PathBuf, - library: Arc>, -} -impl GetPage { - pub fn new(base_path: PathBuf, library: Arc>) -> Self { - Self { base_path: base_path.join("content"), library } - } -} -impl TeraFn for GetPage { - fn call(&self, args: &HashMap) -> Result { - let path = required_arg!( - String, - args.get("path"), - "`get_page` requires a `path` argument with a string value" - ); - let full_path = self.base_path.join(&path); - let library = self.library.read().unwrap(); - match library.get_page(&full_path) { - Some(p) => Ok(to_value(p.to_serialized(&library)).unwrap()), - None => Err(format!("Page `{}` not found.", path).into()), - } - } -} - -#[derive(Debug)] -pub struct GetSection { - base_path: PathBuf, - library: Arc>, -} -impl GetSection { - pub fn new(base_path: PathBuf, library: Arc>) -> Self { - Self { base_path: base_path.join("content"), library } - } -} -impl TeraFn for GetSection { - fn call(&self, args: &HashMap) -> Result { - let path = required_arg!( - String, - args.get("path"), - "`get_section` requires a `path` argument with a string value" - ); - - let metadata_only = args - .get("metadata_only") - .map_or(false, |c| from_value::(c.clone()).unwrap_or(false)); - - let full_path = self.base_path.join(&path); - let library = self.library.read().unwrap(); - - match library.get_section(&full_path) { - Some(s) => { - if metadata_only { - Ok(to_value(s.to_serialized_basic(&library)).unwrap()) - } else { - Ok(to_value(s.to_serialized(&library)).unwrap()) - } - } - None => Err(format!("Section `{}` not found.", path).into()), - } - } -} - -#[derive(Debug)] -pub struct GetTaxonomy { - library: Arc>, - taxonomies: HashMap, - default_lang: String, -} -impl GetTaxonomy { - pub fn new( - default_lang: &str, - all_taxonomies: Vec, - library: Arc>, - ) -> Self { - let mut taxonomies = HashMap::new(); - for taxo in all_taxonomies { - taxonomies.insert(format!("{}-{}", taxo.kind.name, taxo.lang), taxo); - } - Self { taxonomies, library, default_lang: default_lang.to_string() } - } -} -impl TeraFn for GetTaxonomy { - fn call(&self, args: &HashMap) -> Result { - let kind = required_arg!( - String, - args.get("kind"), - "`get_taxonomy` requires a `kind` argument with a string value" - ); - - let lang = - optional_arg!(String, args.get("lang"), "`get_taxonomy`: `lang` must be a string") - .unwrap_or_else(|| self.default_lang.clone()); - - match self.taxonomies.get(&format!("{}-{}", kind, lang)) { - Some(t) => Ok(to_value(t.to_serialized(&self.library.read().unwrap())).unwrap()), - None => { - Err(format!("`get_taxonomy` received an unknown taxonomy as kind: {}", kind).into()) - } - } - } -} - #[cfg(test)] mod tests { use super::{GetFileHash, GetTaxonomy, GetTaxonomyUrl, GetUrl, Trans}; @@ -583,158 +317,6 @@ mod tests { assert_eq!(static_fn.call(&args).unwrap(), "http://a-website.com/app.css"); } - #[test] - fn can_get_taxonomy() { - let mut config = Config::default(); - config.slugify.taxonomies = SlugifyStrategy::On; - let taxo_config = TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; - let taxo_config_fr = - TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; - let library = Arc::new(RwLock::new(Library::new(0, 0, false))); - let tag = TaxonomyItem::new( - "Programming", - &config.default_language, - "tags", - &config, - vec![], - &library.read().unwrap(), - ); - let tag_fr = TaxonomyItem::new( - "Programmation", - "fr", - "tags", - &config, - vec![], - &library.read().unwrap(), - ); - let tags = Taxonomy { - kind: taxo_config, - lang: config.default_language.clone(), - slug: "tags".to_string(), - items: vec![tag], - }; - let tags_fr = Taxonomy { - kind: taxo_config_fr, - lang: "fr".to_owned(), - slug: "tags".to_string(), - items: vec![tag_fr], - }; - - let taxonomies = vec![tags.clone(), tags_fr.clone()]; - let static_fn = - GetTaxonomy::new(&config.default_language, taxonomies.clone(), library.clone()); - // can find it correctly - let mut args = HashMap::new(); - args.insert("kind".to_string(), to_value("tags").unwrap()); - let res = static_fn.call(&args).unwrap(); - let res_obj = res.as_object().unwrap(); - assert_eq!(res_obj["kind"], to_value(tags.kind).unwrap()); - assert_eq!(res_obj["items"].clone().as_array().unwrap().len(), 1); - assert_eq!( - res_obj["items"].clone().as_array().unwrap()[0].clone().as_object().unwrap()["name"], - Value::String("Programming".to_string()) - ); - assert_eq!( - res_obj["items"].clone().as_array().unwrap()[0].clone().as_object().unwrap()["slug"], - Value::String("programming".to_string()) - ); - assert_eq!( - res_obj["items"].clone().as_array().unwrap()[0].clone().as_object().unwrap() - ["permalink"], - Value::String("http://a-website.com/tags/programming/".to_string()) - ); - assert_eq!( - res_obj["items"].clone().as_array().unwrap()[0].clone().as_object().unwrap()["pages"], - Value::Array(vec![]) - ); - // Works with other languages as well - let mut args = HashMap::new(); - args.insert("kind".to_string(), to_value("tags").unwrap()); - args.insert("lang".to_string(), to_value("fr").unwrap()); - let res = static_fn.call(&args).unwrap(); - let res_obj = res.as_object().unwrap(); - assert_eq!(res_obj["kind"], to_value(tags_fr.kind).unwrap()); - assert_eq!(res_obj["items"].clone().as_array().unwrap().len(), 1); - assert_eq!( - res_obj["items"].clone().as_array().unwrap()[0].clone().as_object().unwrap()["name"], - Value::String("Programmation".to_string()) - ); - - // and errors if it can't find it - let mut args = HashMap::new(); - args.insert("kind".to_string(), to_value("something-else").unwrap()); - assert!(static_fn.call(&args).is_err()); - } - - #[test] - fn can_get_taxonomy_url() { - let mut config = Config::default(); - config.slugify.taxonomies = SlugifyStrategy::On; - let taxo_config = TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; - let taxo_config_fr = - TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; - let library = Library::new(0, 0, false); - let tag = TaxonomyItem::new( - "Programming", - &config.default_language, - "tags", - &config, - vec![], - &library, - ); - let tag_fr = TaxonomyItem::new("Programmation", "fr", "tags", &config, vec![], &library); - let tags = Taxonomy { - kind: taxo_config, - lang: config.default_language.clone(), - slug: "tags".to_string(), - items: vec![tag], - }; - let tags_fr = Taxonomy { - kind: taxo_config_fr, - lang: "fr".to_owned(), - slug: "tags".to_string(), - items: vec![tag_fr], - }; - - let taxonomies = vec![tags.clone(), tags_fr.clone()]; - let static_fn = - GetTaxonomyUrl::new(&config.default_language, &taxonomies, config.slugify.taxonomies); - - // can find it correctly - let mut args = HashMap::new(); - args.insert("kind".to_string(), to_value("tags").unwrap()); - args.insert("name".to_string(), to_value("Programming").unwrap()); - assert_eq!( - static_fn.call(&args).unwrap(), - to_value("http://a-website.com/tags/programming/").unwrap() - ); - - // can find it correctly with inconsistent capitalisation - let mut args = HashMap::new(); - args.insert("kind".to_string(), to_value("tags").unwrap()); - args.insert("name".to_string(), to_value("programming").unwrap()); - assert_eq!( - static_fn.call(&args).unwrap(), - to_value("http://a-website.com/tags/programming/").unwrap() - ); - - // works with other languages - let mut args = HashMap::new(); - args.insert("kind".to_string(), to_value("tags").unwrap()); - args.insert("name".to_string(), to_value("Programmation").unwrap()); - args.insert("lang".to_string(), to_value("fr").unwrap()); - assert_eq!( - static_fn.call(&args).unwrap(), - to_value("http://a-website.com/fr/tags/programmation/").unwrap() - ); - - // and errors if it can't find it - let mut args = HashMap::new(); - args.insert("kind".to_string(), to_value("tags").unwrap()); - args.insert("name".to_string(), to_value("random").unwrap()); - assert!(static_fn.call(&args).is_err()); - } - const TRANS_CONFIG: &str = r#" base_url = "https://remplace-par-ton-url.fr" default_language = "fr"