From bfdfe3bba3f7f4793cf5d45c119686efb37a429a Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Thu, 26 Oct 2017 17:03:26 +0200 Subject: [PATCH] Properly parse shortcode arg value types --- CHANGELOG.md | 1 + components/rendering/src/short_code.rs | 59 ++++++++++++++++--- .../documentation/content/shortcodes.md | 9 +++ 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 379f53e..269716d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Fix permalink generation for index page - Add Nim syntax highlighting - Allow static folder to be missing +- Fix shortcodes args being only passed as strings ## 0.2.1 (2017-10-17) diff --git a/components/rendering/src/short_code.rs b/components/rendering/src/short_code.rs index 5e8aaa3..532aea9 100644 --- a/components/rendering/src/short_code.rs +++ b/components/rendering/src/short_code.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use regex::Regex; -use tera::{Tera, Context}; +use tera::{Tera, Context, Value, to_value}; use errors::{Result, ResultExt}; @@ -15,15 +15,15 @@ lazy_static!{ #[derive(Debug)] pub struct ShortCode { name: String, - args: HashMap, + args: HashMap, body: String, } impl ShortCode { - pub fn new(name: &str, args: HashMap) -> ShortCode { + pub fn new(name: &str, args: HashMap) -> ShortCode { ShortCode { name: name.to_string(), - args: args, + args, body: String::new(), } } @@ -45,7 +45,7 @@ impl ShortCode { } /// Parse a shortcode without a body -pub fn parse_shortcode(input: &str) -> (String, HashMap) { +pub fn parse_shortcode(input: &str) -> (String, HashMap) { let mut args = HashMap::new(); let caps = SHORTCODE_RE.captures(input).unwrap(); // caps[0] is the full match @@ -54,7 +54,39 @@ pub fn parse_shortcode(input: &str) -> (String, HashMap) { if let Some(arg_list) = caps.get(2) { for arg in arg_list.as_str().split(',') { let bits = arg.split('=').collect::>(); - args.insert(bits[0].trim().to_string(), bits[1].replace("\"", "")); + let arg_name = bits[0].trim().to_string(); + let arg_val = bits[1].replace("\"", ""); + + // Regex captures will be str so we need to figure out if they are + // actually str or bool/number + if input.contains(&format!("{}=\"{}\"", arg_name, arg_val)) { + // that's a str, just add it + args.insert(arg_name, to_value(arg_val).unwrap()); + continue; + } + + if input.contains(&format!("{}=true", arg_name)) { + args.insert(arg_name, to_value(true).unwrap()); + continue; + } + + if input.contains(&format!("{}=false", arg_name)) { + args.insert(arg_name, to_value(false).unwrap()); + continue; + } + + // Not a string or a bool, a number then? + if arg_val.contains('.') { + if let Ok(float) = arg_val.parse::() { + args.insert(arg_name, to_value(float).unwrap()); + } + continue; + } + + // must be an integer + if let Ok(int) = arg_val.parse::() { + args.insert(arg_name, to_value(int).unwrap()); + } } } @@ -62,7 +94,7 @@ pub fn parse_shortcode(input: &str) -> (String, HashMap) { } /// Renders a shortcode or return an error -pub fn render_simple_shortcode(tera: &Tera, name: &str, args: &HashMap) -> Result { +pub fn render_simple_shortcode(tera: &Tera, name: &str, args: &HashMap) -> Result { let mut context = Context::new(); for (key, value) in args.iter() { context.add(key, value); @@ -117,7 +149,7 @@ mod tests { let (name, args) = parse_shortcode(r#"{{ youtube(id="w7Ft2ymGmfc", autoplay=true) }}"#); assert_eq!(name, "youtube"); assert_eq!(args["id"], "w7Ft2ymGmfc"); - assert_eq!(args["autoplay"], "true"); + assert_eq!(args["autoplay"], true); } #[test] @@ -125,6 +157,15 @@ mod tests { let (name, args) = parse_shortcode(r#"{% youtube(id="w7Ft2ymGmfc", autoplay=true) %}"#); assert_eq!(name, "youtube"); assert_eq!(args["id"], "w7Ft2ymGmfc"); - assert_eq!(args["autoplay"], "true"); + assert_eq!(args["autoplay"], true); + } + + #[test] + fn can_parse_shortcode_number() { + let (name, args) = parse_shortcode(r#"{% test(int=42, float=42.0, autoplay=true) %}"#); + assert_eq!(name, "test"); + assert_eq!(args["int"], 42); + assert_eq!(args["float"], 42.0); + assert_eq!(args["autoplay"], true); } } diff --git a/docs/content/documentation/content/shortcodes.md b/docs/content/documentation/content/shortcodes.md index 32060c2..3362f62 100644 --- a/docs/content/documentation/content/shortcodes.md +++ b/docs/content/documentation/content/shortcodes.md @@ -47,6 +47,15 @@ Lastly, a shortcode name (and thus the corresponding `.html` file) as well as th can only contain numbers, letters and underscores, or in Regex terms the following: `[0-9A-Za-z_]`. While theoretically an argument name could be a number, it will not be possible to use it in the template in that case. +Argument values can be of 4 types: + +- string: surrounded by double quotes `"..."` +- bool: `true` or `false` +- float: a number with a `.` in it +- integer: a number without a `.` in it + +Malformed values will be silently ignored. + ### Shortcodes without body On a new line, call the shortcode as if it was a Tera function in a variable block. All the examples below are valid