From fd68f8498683a73c13cf0f6050db171dd09c3721 Mon Sep 17 00:00:00 2001 From: "Elf M. Sternberg" Date: Thu, 28 Apr 2022 15:44:23 -0700 Subject: [PATCH 1/3] Add YAML to formats supported by load_data() A fairly trivial addition; JSON and YAML are handled so similarly that this was a matter of copying the JSON-relevant handlers and editing the copies to handle YAML as well. The test file was literally generated with 'json2yaml'. The documentation has been updated to indicate that load_data() now handles YAML code. The CHANGELOG has been updated as well. --- CHANGELOG.md | 1 + .../templates/src/global_fns/load_data.rs | 31 +++++++++++++++++++ components/utils/test-files/test.yaml | 9 ++++++ .../documentation/templates/overview.md | 9 ++++-- 4 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 components/utils/test-files/test.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index cd0d873a6b..2196d3acf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ also specify classes on headers now - Make `ignored_content` work with nested paths and directories - `zola serve/build` can now run from anywhere in a zola directory - Add XML support to `load_data` +- Add YAML support to `load_data` - `skip_prefixes` is now checked before parsing external link URLs - Add `render` attribute to taxonomies configuration in `config.toml`, for when you don't want to render any pages related to that taxonomy diff --git a/components/templates/src/global_fns/load_data.rs b/components/templates/src/global_fns/load_data.rs index 263d949765..d06bf4187b 100644 --- a/components/templates/src/global_fns/load_data.rs +++ b/components/templates/src/global_fns/load_data.rs @@ -1,3 +1,4 @@ +use libs::serde_yaml; use std::collections::hash_map::DefaultHasher; use std::collections::HashMap; use std::hash::{Hash, Hasher}; @@ -47,6 +48,7 @@ enum OutputFormat { Bibtex, Plain, Xml, + Yaml, } impl FromStr for OutputFormat { @@ -60,6 +62,7 @@ impl FromStr for OutputFormat { "bibtex" => Ok(OutputFormat::Bibtex), "xml" => Ok(OutputFormat::Xml), "plain" => Ok(OutputFormat::Plain), + "yaml" => Ok(OutputFormat::Yaml), format => Err(format!("Unknown output format {}", format).into()), } } @@ -74,6 +77,7 @@ impl OutputFormat { OutputFormat::Bibtex => "application/x-bibtex", OutputFormat::Xml => "text/xml", OutputFormat::Plain => "text/plain", + OutputFormat::Yaml => "application/yaml", }) } } @@ -388,6 +392,7 @@ impl TeraFn for LoadData { OutputFormat::Json => load_json(data), OutputFormat::Bibtex => load_bibtex(data), OutputFormat::Xml => load_xml(data), + OutputFormat::Yaml => load_yaml(data), OutputFormat::Plain => to_value(data).map_err(|e| e.into()), }; @@ -406,6 +411,13 @@ fn load_json(json_data: String) -> Result { Ok(json_content) } +/// Parse a YAML string and convert it to a Tera Value +fn load_yaml(yaml_data: String) -> Result { + let yaml_content: Value = + serde_yaml::from_str(yaml_data.as_str()).map_err(|e| format!("{:?}", e))?; + Ok(yaml_content) +} + /// Parse a TOML string and convert it to a Tera Value fn load_toml(toml_data: String) -> Result { let toml_content: toml::Value = toml::from_str(&toml_data).map_err(|e| format!("{:?}", e))?; @@ -1084,6 +1096,25 @@ mod tests { ) } + #[test] + fn can_load_yaml() { + let static_fn = LoadData::new(PathBuf::from("../utils/test-files"), None, PathBuf::new()); + let mut args = HashMap::new(); + args.insert("path".to_string(), to_value("test.yaml").unwrap()); + let result = static_fn.call(&args.clone()).unwrap(); + + assert_eq!( + result, + json!({ + "key": "value", + "array": [1, 2, 3], + "subpackage": { + "subkey": 5 + } + }) + ) + } + #[test] fn is_load_remote_data_using_post_method_with_different_body_not_cached() { let _mjson = mock("POST", "/kr1zdgbm4y3") diff --git a/components/utils/test-files/test.yaml b/components/utils/test-files/test.yaml new file mode 100644 index 0000000000..37d3f9a6df --- /dev/null +++ b/components/utils/test-files/test.yaml @@ -0,0 +1,9 @@ +--- + key: "value" + array: + - 1 + - 2 + - 3 + subpackage: + subkey: 5 + diff --git a/docs/content/documentation/templates/overview.md b/docs/content/documentation/templates/overview.md index 6271093dd7..0e1f17dfaf 100644 --- a/docs/content/documentation/templates/overview.md +++ b/docs/content/documentation/templates/overview.md @@ -259,7 +259,8 @@ The method returns a map containing `width`, `height` and `format` (the lowercas ### `load_data` -Loads data from a file, URL, or string literal. Supported file types include *toml*, *json*, *csv*, *bibtex* and *xml* and only supports UTF-8 encoding. +Loads data from a file, URL, or string literal. Supported file types include *toml*, *json*, *csv*, *bibtex*, *yaml* +and *xml* and only supports UTF-8 encoding. Any other file type will be loaded as plain text. @@ -293,7 +294,9 @@ The snippet below outputs the HTML from a Wikipedia page, or "No data found" if {% if data %}{{ data | safe }}{% else %}No data found{% endif %} ``` -The optional `format` argument allows you to specify and override which data type is contained within the specified file or URL. Valid entries are `toml`, `json`, `csv`, `bibtex`, `xml` or `plain`. If the `format` argument isn't specified, then the path extension is used. In the case of a literal, `plain` is assumed if `format` is unspecified. +The optional `format` argument allows you to specify and override which data type is contained within the specified file or URL. +Valid entries are `toml`, `json`, `csv`, `bibtex`, `yaml`, `xml` or `plain`. If the `format` argument isn't specified, then the +path extension is used. In the case of a literal, `plain` is assumed if `format` is unspecified. ```jinja2 @@ -302,7 +305,7 @@ The optional `format` argument allows you to specify and override which data typ Use the `plain` format for when your file has a supported extension but you want to load it as plain text. -For *toml*, *json* and *xml*, the data is loaded into a structure matching the original data file; +For *toml*, *json*, *yaml* and *xml*, the data is loaded into a structure matching the original data file; however, for *csv* there is no native notion of such a structure. Instead, the data is separated into a data structure containing *headers* and *records*. See the example below to see how this works. From dd61b7b33e5a1c94842ea1cb3e062296f3ccf97f Mon Sep 17 00:00:00 2001 From: "Elf M. Sternberg" Date: Thu, 28 Apr 2022 15:52:49 -0700 Subject: [PATCH 2/3] After checking, I found that it's generally agreed the mime type is still application/x-yaml. --- components/templates/src/global_fns/load_data.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/templates/src/global_fns/load_data.rs b/components/templates/src/global_fns/load_data.rs index d06bf4187b..b7114644ac 100644 --- a/components/templates/src/global_fns/load_data.rs +++ b/components/templates/src/global_fns/load_data.rs @@ -77,7 +77,7 @@ impl OutputFormat { OutputFormat::Bibtex => "application/x-bibtex", OutputFormat::Xml => "text/xml", OutputFormat::Plain => "text/plain", - OutputFormat::Yaml => "application/yaml", + OutputFormat::Yaml => "application/x-yaml", }) } } From df7212212819c33c6dbd3be5ce6e997be025ca16 Mon Sep 17 00:00:00 2001 From: "Elf M. Sternberg" Date: Thu, 28 Apr 2022 16:09:25 -0700 Subject: [PATCH 3/3] Update comment, unify library importing. I noticed one more place where the list of formats was supported, and added YAML to that list. I noticed that there's a singular place to load the `libs::` crate, and unified by importing of serde_yaml in that place. --- components/templates/src/global_fns/load_data.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/templates/src/global_fns/load_data.rs b/components/templates/src/global_fns/load_data.rs index b7114644ac..dc6c4210b8 100644 --- a/components/templates/src/global_fns/load_data.rs +++ b/components/templates/src/global_fns/load_data.rs @@ -1,4 +1,3 @@ -use libs::serde_yaml; use std::collections::hash_map::DefaultHasher; use std::collections::HashMap; use std::hash::{Hash, Hasher}; @@ -13,7 +12,7 @@ use libs::tera::{ from_value, to_value, Error, Error as TeraError, Function as TeraFn, Map, Result, Value, }; use libs::url::Url; -use libs::{nom_bibtex, serde_json, toml}; +use libs::{nom_bibtex, serde_json, serde_yaml, toml}; use utils::de::fix_toml_dates; use utils::fs::{get_file_time, read_file}; @@ -212,7 +211,7 @@ fn add_headers_from_args(header_args: Option>) -> Result } /// A Tera function to load data from a file or from a URL -/// Currently the supported formats are json, toml, csv, bibtex and plain text +/// Currently the supported formats are json, toml, csv, yaml, bibtex and plain text #[derive(Debug)] pub struct LoadData { base_path: PathBuf,