From 2770fbf3c3e27c459761257c09fa05f1bebbe151 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Sat, 17 Nov 2018 11:28:26 +0100 Subject: [PATCH] getopt parser fixes and cleanups --- src/api/schema.rs | 14 ++++++--- src/getopts.rs | 80 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/api/schema.rs b/src/api/schema.rs index 8599b0be..21ecdeee 100644 --- a/src/api/schema.rs +++ b/src/api/schema.rs @@ -171,6 +171,14 @@ macro_rules! parameter { }}; } +pub fn parse_boolean(value_str: &str) -> Result { + match value_str.to_lowercase().as_str() { + "1" | "on" | "yes" | "true" => Ok(true), + "0" | "off" | "no" | "false" => Ok(false), + _ => bail!("Unable to parse boolean option."), + } +} + fn parse_simple_value(value_str: &str, schema: &Schema) -> Result { let value = match schema { @@ -178,11 +186,7 @@ fn parse_simple_value(value_str: &str, schema: &Schema) -> Result bail!("internal error - found Null schema."); } Schema::Boolean(_boolean_schema) => { - let res = match value_str.to_lowercase().as_str() { - "1" | "on" | "yes" | "true" => true, - "0" | "off" | "no" | "false" => false, - _ => bail!("Unable to parse boolean option."), - }; + let res = parse_boolean(value_str)?; Value::Bool(res) } Schema::Integer(integer_schema) => { diff --git a/src/getopts.rs b/src/getopts.rs index 13a13482..8eb0cdef 100644 --- a/src/getopts.rs +++ b/src/getopts.rs @@ -1,6 +1,7 @@ use crate::api::schema::*; use failure::*; +use std::collections::HashMap; use serde_json::{json, Value}; #[derive(Debug)] @@ -72,23 +73,43 @@ pub fn parse_arguments( RawArgument::Option { name, value } => { match value { None => { - if pos < args.len() { - if let RawArgument::Argument { value: next } = parse_argument(&args[pos+1]) { - pos += 1; - data.push((name, next)); - } else { - if let Some(Schema::Boolean(boolean_schema)) = properties.get::(&name) { - if let Some(default) = boolean_schema.default { - if default == false { - data.push((name, "true".to_string())); - } else { - errors.push(format_err!("parameter '{}': {}", name, - "boolean requires argument.")); - } - } else { - data.push((name, "true".to_string())); - } + let param_schema = properties.get::(&name); + let (want_bool, can_default) = match param_schema { + Some(Schema::Boolean(boolean_schema)) => { + if let Some(default) = boolean_schema.default { + if default == true { (true, false); } } + (true, true) + } + _ => (false, false), + }; + + if want_bool { + + let mut next_is_bool = false; + if (pos + 1) < args.len() { + let next = &args[pos+1]; + if let Ok(_) = parse_boolean(next) { next_is_bool = true; } + } + + if next_is_bool { + pos += 1; + data.push((name, args[pos].clone())); + } else if can_default { + data.push((name, "true".to_string())); + } else { + errors.push(format_err!("parameter '{}': {}", name, + "missing boolean value.")); + } + + } else { + + if (pos + 1) < args.len() { + pos += 1; + data.push((name, args[pos].clone())); + } else { + errors.push(format_err!("parameter '{}': {}", name, + "missing parameter value.")); } } } @@ -113,3 +134,30 @@ pub fn parse_arguments( Ok((options,rest)) } + + +#[test] +fn test_boolean_arg() { + + let schema = parameter!{enable => Boolean!{ optional => false }}; + + let mut variants: Vec> = vec![]; + variants.push(vec!["-enable"]); + variants.push(vec!["-enable=1"]); + variants.push(vec!["-enable", "yes"]); + variants.push(vec!["--enable", "1"]); + + for args in variants { + let string_args = args.iter().map(|s| s.to_string()).collect(); + let res = parse_arguments(&string_args, &schema); + println!("RES: {:?}", res); + assert!(res.is_ok()); + if let Ok((options, rest)) = res { + assert!(options["enable"] == true); + assert!(rest.len() == 0); + } + } + + //Ok((options, rest)) => { + +}