diff --git a/src/app/mod.rs b/src/app/mod.rs index 8bb1a440..90264346 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -98,74 +98,8 @@ impl<'a, 'b> App<'a, 'b> { /// // continued logic goes here, such as `app.get_matches()` etc. /// ``` #[cfg(feature = "yaml")] - pub fn from_yaml<'y>(mut yaml: &'y Yaml) -> App<'y, 'y> { - use args::SubCommand; - // We WANT this to panic on error...so expect() is good. - let mut is_sc = None; - let mut a = if let Some(name) = yaml["name"].as_str() { - App::new(name) - } else { - let yaml_hash = yaml.as_hash().unwrap(); - let sc_key = yaml_hash.keys().nth(0).unwrap(); - is_sc = Some(yaml_hash.get(sc_key).unwrap()); - App::new(sc_key.as_str().unwrap()) - }; - yaml = if let Some(sc) = is_sc { - sc - } else { - yaml - }; - if let Some(v) = yaml["version"].as_str() { - a = a.version(v); - } - if let Some(v) = yaml["author"].as_str() { - a = a.author(v); - } - if let Some(v) = yaml["bin_name"].as_str() { - a = a.bin_name(v); - } - if let Some(v) = yaml["about"].as_str() { - a = a.about(v); - } - if let Some(v) = yaml["after_help"].as_str() { - a = a.after_help(v); - } - if let Some(v) = yaml["usage"].as_str() { - a = a.usage(v); - } - if let Some(v) = yaml["help"].as_str() { - a = a.help(v); - } - if let Some(v) = yaml["help_short"].as_str() { - a = a.help_short(v); - } - if let Some(v) = yaml["version_short"].as_str() { - a = a.version_short(v); - } - if let Some(v) = yaml["settings"].as_vec() { - for ys in v { - if let Some(s) = ys.as_str() { - a = a.setting(s.parse().ok().expect("unknown AppSetting found in YAML file")); - } - } - } - if let Some(v) = yaml["args"].as_vec() { - for arg_yaml in v { - a = a.arg(Arg::from_yaml(&arg_yaml.as_hash().unwrap())); - } - } - if let Some(v) = yaml["subcommands"].as_vec() { - for sc_yaml in v { - a = a.subcommand(SubCommand::from_yaml(&sc_yaml)); - } - } - if let Some(v) = yaml["groups"].as_vec() { - for ag_yaml in v { - a = a.group(ArgGroup::from_yaml(&ag_yaml.as_hash().unwrap())); - } - } - - a + pub fn from_yaml(yaml: &'a Yaml) -> App<'a, 'a> { + App::from(yaml) } /// Sets a string of author(s) that will be displayed to the user when they request the help @@ -810,3 +744,76 @@ impl<'a, 'b> App<'a, 'b> { e.exit() } } + +#[cfg(feature = "yaml")] +impl<'a> From<&'a Yaml> for App<'a, 'a> { + fn from(mut yaml: &'a Yaml) -> Self { + use args::SubCommand; + // We WANT this to panic on error...so expect() is good. + let mut is_sc = None; + let mut a = if let Some(name) = yaml["name"].as_str() { + App::new(name) + } else { + let yaml_hash = yaml.as_hash().unwrap(); + let sc_key = yaml_hash.keys().nth(0).unwrap(); + is_sc = Some(yaml_hash.get(sc_key).unwrap()); + App::new(sc_key.as_str().unwrap()) + }; + yaml = if let Some(sc) = is_sc { + sc + } else { + yaml + }; + if let Some(v) = yaml["version"].as_str() { + a = a.version(v); + } + if let Some(v) = yaml["author"].as_str() { + a = a.author(v); + } + if let Some(v) = yaml["bin_name"].as_str() { + a = a.bin_name(v); + } + if let Some(v) = yaml["about"].as_str() { + a = a.about(v); + } + if let Some(v) = yaml["after_help"].as_str() { + a = a.after_help(v); + } + if let Some(v) = yaml["usage"].as_str() { + a = a.usage(v); + } + if let Some(v) = yaml["help"].as_str() { + a = a.help(v); + } + if let Some(v) = yaml["help_short"].as_str() { + a = a.help_short(v); + } + if let Some(v) = yaml["version_short"].as_str() { + a = a.version_short(v); + } + if let Some(v) = yaml["settings"].as_vec() { + for ys in v { + if let Some(s) = ys.as_str() { + a = a.setting(s.parse().ok().expect("unknown AppSetting found in YAML file")); + } + } + } + if let Some(v) = yaml["args"].as_vec() { + for arg_yaml in v { + a = a.arg(Arg::from_yaml(&arg_yaml.as_hash().unwrap())); + } + } + if let Some(v) = yaml["subcommands"].as_vec() { + for sc_yaml in v { + a = a.subcommand(SubCommand::from_yaml(&sc_yaml)); + } + } + if let Some(v) = yaml["groups"].as_vec() { + for ag_yaml in v { + a = a.group(ArgGroup::from(ag_yaml.as_hash().unwrap())); + } + } + + a + } +} diff --git a/src/args/group.rs b/src/args/group.rs index c6987ef0..22ffa680 100644 --- a/src/args/group.rs +++ b/src/args/group.rs @@ -49,6 +49,7 @@ use yaml_rust::Yaml; /// .required(true)) /// # ; /// ``` +#[derive(Default)] pub struct ArgGroup<'a> { #[doc(hidden)] pub name: &'a str, @@ -93,54 +94,8 @@ impl<'a> ArgGroup<'a> { /// let ag = ArgGroup::from_yaml(yml); /// ``` #[cfg(feature = "yaml")] - pub fn from_yaml<'y>(y: &'y BTreeMap) -> ArgGroup<'y> { - // We WANT this to panic on error...so expect() is good. - let name_yml = y.keys().nth(0).unwrap(); - let name_str = name_yml.as_str().unwrap(); - let mut a = ArgGroup::with_name(name_str); - let group_settings = y.get(name_yml).unwrap().as_hash().unwrap(); - - for (k, v) in group_settings.iter() { - a = match k.as_str().unwrap() { - "required" => a.required(v.as_bool().unwrap()), - "args" => { - for ys in v.as_vec().unwrap() { - if let Some(s) = ys.as_str() { - a = a.arg(s); - } - } - a - } - "arg" => { - if let Some(ys) = v.as_str() { - a = a.arg(ys); - } - a - } - "requires" => { - for ys in v.as_vec().unwrap() { - if let Some(s) = ys.as_str() { - a = a.requires(s); - } - } - a - } - "conflicts_with" => { - for ys in v.as_vec().unwrap() { - if let Some(s) = ys.as_str() { - a = a.conflicts_with(s); - } - } - a - } - s => panic!("Unknown ArgGroup setting '{}' in YAML file for \ - ArgGroup '{}'", - s, - name_str), - } - } - - a + pub fn from_yaml(y: &'a Yaml) -> ArgGroup<'a> { + ArgGroup::from(y.as_hash().unwrap()) } /// Adds an argument to this group by name @@ -325,13 +280,13 @@ impl<'a> ArgGroup<'a> { impl<'a> Debug for ArgGroup<'a> { fn fmt(&self, f: &mut Formatter) -> Result { write!(f, - "{{ - name:{:?}, - args: {:?}, - required: {:?}, - requires: {:?}, - conflicts: {:?}, - }}", + "{{\n\ + \tname: {:?},\n\ + \targs: {:?},\n\ + \trequired: {:?},\n\ + \trequires: {:?},\n\ + \tconflicts: {:?},\n\ + }}", self.name, self.args, self.required, @@ -352,9 +307,75 @@ impl<'a, 'z> From<&'z ArgGroup<'a>> for ArgGroup<'a> { } } +#[cfg(feature = "yaml")] +impl<'a> From<&'a BTreeMap> for ArgGroup<'a> { + fn from(b: &'a BTreeMap) -> Self { + // We WANT this to panic on error...so expect() is good. + let mut a = ArgGroup::default(); + let group_settings = if b.len() == 1 { + let name_yml = b.keys().nth(0).expect("failed to get name"); + let name_str = name_yml.as_str().expect("failed to convert name to str"); + a.name = name_str; + b.get(name_yml).expect("failed to get name_str").as_hash().expect("failed to convert to a hash") + } else { + b + }; + + for (k, v) in group_settings.iter() { + a = match k.as_str().unwrap() { + "required" => a.required(v.as_bool().unwrap()), + "args" => { + for ys in v.as_vec().unwrap() { + if let Some(s) = ys.as_str() { + a = a.arg(s); + } + } + a + } + "arg" => { + if let Some(ys) = v.as_str() { + a = a.arg(ys); + } + a + } + "requires" => { + for ys in v.as_vec().unwrap() { + if let Some(s) = ys.as_str() { + a = a.requires(s); + } + } + a + } + "conflicts_with" => { + for ys in v.as_vec().unwrap() { + if let Some(s) = ys.as_str() { + a = a.conflicts_with(s); + } + } + a + } + "name" => { + if let Some(ys) = v.as_str() { + a.name = ys; + } + a + } + s => panic!("Unknown ArgGroup setting '{}' in YAML file for \ + ArgGroup '{}'", + s, + a.name), + } + } + + a + } +} + #[cfg(test)] mod test { use super::ArgGroup; + #[cfg(feature = "yaml")] + use yaml_rust::YamlLoader; #[test] fn groups() {