Browse Source

Properly parse shortcode arg value types

index-subcmd
Vincent Prouillet 7 years ago
parent
commit
bfdfe3bba3
3 changed files with 60 additions and 9 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +50
    -9
      components/rendering/src/short_code.rs
  3. +9
    -0
      docs/content/documentation/content/shortcodes.md

+ 1
- 0
CHANGELOG.md View File

@@ -9,6 +9,7 @@
- Fix permalink generation for index page - Fix permalink generation for index page
- Add Nim syntax highlighting - Add Nim syntax highlighting
- Allow static folder to be missing - Allow static folder to be missing
- Fix shortcodes args being only passed as strings




## 0.2.1 (2017-10-17) ## 0.2.1 (2017-10-17)


+ 50
- 9
components/rendering/src/short_code.rs View File

@@ -1,7 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;


use regex::Regex; use regex::Regex;
use tera::{Tera, Context};
use tera::{Tera, Context, Value, to_value};


use errors::{Result, ResultExt}; use errors::{Result, ResultExt};


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


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


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


@@ -62,7 +94,7 @@ pub fn parse_shortcode(input: &str) -> (String, HashMap<String, String>) {
} }


/// Renders a shortcode or return an error /// 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(); let mut context = Context::new();
for (key, value) in args.iter() { for (key, value) in args.iter() {
context.add(key, value); context.add(key, value);
@@ -117,7 +149,7 @@ mod tests {
let (name, args) = parse_shortcode(r#"{{ youtube(id="w7Ft2ymGmfc", autoplay=true) }}"#); let (name, args) = parse_shortcode(r#"{{ youtube(id="w7Ft2ymGmfc", autoplay=true) }}"#);
assert_eq!(name, "youtube"); assert_eq!(name, "youtube");
assert_eq!(args["id"], "w7Ft2ymGmfc"); assert_eq!(args["id"], "w7Ft2ymGmfc");
assert_eq!(args["autoplay"], "true");
assert_eq!(args["autoplay"], true);
} }


#[test] #[test]
@@ -125,6 +157,15 @@ mod tests {
let (name, args) = parse_shortcode(r#"{% youtube(id="w7Ft2ymGmfc", autoplay=true) %}"#); let (name, args) = parse_shortcode(r#"{% youtube(id="w7Ft2ymGmfc", autoplay=true) %}"#);
assert_eq!(name, "youtube"); assert_eq!(name, "youtube");
assert_eq!(args["id"], "w7Ft2ymGmfc"); 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
- 0
docs/content/documentation/content/shortcodes.md View File

@@ -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_]`. 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. 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 ### 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 On a new line, call the shortcode as if it was a Tera function in a variable block. All the examples below are valid


Loading…
Cancel
Save