Skip to content

Commit

Permalink
Properly parse shortcode arg value types
Browse files Browse the repository at this point in the history
  • Loading branch information
Vincent Prouillet committed Oct 26, 2017
1 parent 1d8df57 commit bfdfe3b
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
59 changes: 50 additions & 9 deletions components/rendering/src/short_code.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand All @@ -15,15 +15,15 @@ lazy_static!{
#[derive(Debug)]
pub struct ShortCode {
name: String,
args: HashMap<String, String>,
args: HashMap<String, Value>,
body: String,
}

impl ShortCode {
pub fn new(name: &str, args: HashMap<String, String>) -> ShortCode {
pub fn new(name: &str, args: HashMap<String, Value>) -> ShortCode {
ShortCode {
name: name.to_string(),
args: args,
args,
body: String::new(),
}
}
Expand All @@ -45,7 +45,7 @@ impl ShortCode {
}

/// Parse a shortcode without a body
pub fn parse_shortcode(input: &str) -> (String, HashMap<String, String>) {
pub fn parse_shortcode(input: &str) -> (String, HashMap<String, Value>) {
let mut args = HashMap::new();
let caps = SHORTCODE_RE.captures(input).unwrap();
// caps[0] is the full match
Expand All @@ -54,15 +54,47 @@ pub fn parse_shortcode(input: &str) -> (String, HashMap<String, String>) {
if let Some(arg_list) = caps.get(2) {
for arg in arg_list.as_str().split(',') {
let bits = arg.split('=').collect::<Vec<_>>();
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::<f64>() {
args.insert(arg_name, to_value(float).unwrap());
}
continue;
}

// must be an integer
if let Ok(int) = arg_val.parse::<i64>() {
args.insert(arg_name, to_value(int).unwrap());
}
}
}

(name.to_string(), args)
}

/// Renders a shortcode or return an error
pub fn render_simple_shortcode(tera: &Tera, name: &str, args: &HashMap<String, String>) -> Result<String> {
pub fn render_simple_shortcode(tera: &Tera, name: &str, args: &HashMap<String, Value>) -> Result<String> {
let mut context = Context::new();
for (key, value) in args.iter() {
context.add(key, value);
Expand Down Expand Up @@ -117,14 +149,23 @@ 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_block_shortcode_several_arg() {
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);
}
}
9 changes: 9 additions & 0 deletions docs/content/documentation/content/shortcodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit bfdfe3b

Please sign in to comment.