imp(Traits): refactoring some configuration into traits

There is now an AnyArg trait which lets you (clap dev, not consumer) get
info about certain args regardless of their type. Allows more generic
and de-duplicated code
This commit is contained in:
Kevin K 2015-11-09 07:21:28 -05:00
parent 1fdecfd519
commit 5800cdec6d
4 changed files with 80 additions and 45 deletions

View file

@ -10,6 +10,7 @@ use std::path::Path;
use std::process; use std::process;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::borrow::Borrow; use std::borrow::Borrow;
use std::fmt::Display;
#[cfg(feature = "yaml")] #[cfg(feature = "yaml")]
use yaml_rust::Yaml; use yaml_rust::Yaml;
@ -18,7 +19,7 @@ use vec_map::VecMap;
use args::{Arg, ArgMatches, MatchedArg, SubCommand}; use args::{Arg, ArgMatches, MatchedArg, SubCommand};
use args::{FlagBuilder, OptBuilder, PosBuilder}; use args::{FlagBuilder, OptBuilder, PosBuilder};
use args::settings::{ArgFlags, ArgSettings}; use args::settings::{ArgFlags, ArgSettings};
use args::ArgGroup; use args::{ArgGroup, AnyArg};
use fmt::Format; use fmt::Format;
use self::settings::AppFlags; use self::settings::AppFlags;
use suggestions; use suggestions;
@ -3059,43 +3060,12 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar> {
matches: &mut ArgMatches<'ar, 'ar>, matches: &mut ArgMatches<'ar, 'ar>,
arg: char) arg: char)
-> ClapResult<bool> { -> ClapResult<bool> {
if let Some(v) = self.flags let v = self.flags.iter().filter(|&v| v.short.is_some() && v.short.unwrap() == arg).next();
.iter() if v.is_some() {
.filter(|&v| v.short.is_some() && v.short.unwrap() == arg) let flag = v.unwrap();
.next() { try!(self.validate_arg(flag, matches));
// Ensure this flag isn't on the mutually excludes list
if self.blacklist.contains(&v.name) {
matches.args.remove(v.name);
return Err(error_builder::ArgumentConflict(
v.to_string(),
self.blacklisted_from(v.name, &matches),
try!(self.create_current_usage(matches))));
}
if self.overrides.contains(&v.name) {
debugln!("it is...");
debugln!("checking who defined it...");
if let Some(ref name) = self.overriden_from(v.name, matches) {
debugln!("found {}", name);
matches.args.remove(name);
remove_overriden!(self, name);
}
}
if let Some(ref or) = v.overrides {
for pa in or {
matches.args.remove(pa);
remove_overriden!(self, pa);
self.overrides.push(pa);
}
}
// Make sure this isn't one being added multiple times if it doesn't suppor it if let Some(ref vec) = self.groups_for_arg(flag.name) {
if matches.args.contains_key(v.name) && !v.settings.is_set(&ArgSettings::Multiple) {
return Err(error_builder::UnexpectedMultipleUsage(
&*format!("-{}", arg),
&*try!(self.create_current_usage(matches))));
}
if let Some(ref vec) = self.groups_for_arg(v.name) {
for grp in vec { for grp in vec {
if let Some(ref mut f) = matches.args.get_mut(grp) { if let Some(ref mut f) = matches.args.get_mut(grp) {
f.occurrences = if v.settings.is_set(&ArgSettings::Multiple) { f.occurrences = if v.settings.is_set(&ArgSettings::Multiple) {
@ -3159,6 +3129,40 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar> {
Ok(false) Ok(false)
} }
fn validate_arg<A>(&mut self, arg: &A, matches: &mut ArgMatches<'ar, 'ar>) -> ClapResult<()>
where A: AnyArg<'ar> + Display {
// Ensure this arg isn't on the mutually excludes list
if self.blacklist.contains(&arg.name()) {
matches.args.remove(arg.name());
return Err(error_builder::ArgumentConflict(
arg.to_string(),
self.blacklisted_from(arg.name(), &matches),
try!(self.create_current_usage(matches))));
}
if self.overrides.contains(&arg.name()) {
if let Some(ref name) = self.overriden_from(arg.name(), matches) {
matches.args.remove(name);
remove_overriden!(self, name);
}
}
if let Some(or) = arg.overrides() {
for pa in or {
matches.args.remove(pa);
remove_overriden!(self, pa);
self.overrides.push(pa);
}
}
// Make sure this isn't one being added multiple times if it doesn't suppor it
if matches.args.contains_key(arg.name()) && !arg.is_set(&ArgSettings::Multiple) {
return Err(error_builder::UnexpectedMultipleUsage(
&*format!("-{}", arg),
&*try!(self.create_current_usage(matches))));
}
Ok(())
}
fn validate_blacklist(&self, matches: &mut ArgMatches<'ar, 'ar>) -> ClapResult<()> { fn validate_blacklist(&self, matches: &mut ArgMatches<'ar, 'ar>) -> ClapResult<()> {
for name in self.blacklist.iter() { for name in self.blacklist.iter() {
if matches.args.contains_key(name) { if matches.args.contains_key(name) {
@ -3254,8 +3258,8 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar> {
return Err(error_builder::TooManyValues( return Err(error_builder::TooManyValues(
vals.get(vals.keys() vals.get(vals.keys()
.last() .last()
.expect("error getting last key. This is a bug")) .expect(INTERNAL_ERROR_MSG))
.expect("failed to retrieve last value. This is a bug"), .expect(INTERNAL_ERROR_MSG),
&f.to_string(), &f.to_string(),
&try!(self.create_current_usage(matches)))); &try!(self.create_current_usage(matches))));
} }

8
src/args/any_arg.rs Normal file
View file

@ -0,0 +1,8 @@
use args::settings::ArgSettings;
pub trait AnyArg<'n> {
fn name(&self) -> &'n str;
fn overrides(&self) -> Option<&[&'n str]>;
fn is_set(&self, &ArgSettings) -> bool;
fn set(&mut self, &ArgSettings);
}

View file

@ -4,6 +4,7 @@ use std::convert::From;
use std::io; use std::io;
use Arg; use Arg;
use args::AnyArg;
use args::settings::{ArgFlags, ArgSettings}; use args::settings::{ArgFlags, ArgSettings};
#[derive(Debug)] #[derive(Debug)]
@ -167,6 +168,25 @@ impl<'n> Display for FlagBuilder<'n> {
} }
} }
} }
impl<'n> AnyArg<'n> for FlagBuilder<'n> {
fn name(&self) -> &'n str {
self.name
}
fn overrides(&self) -> Option<&[&'n str]> {
self.overrides.as_ref().map(|o| &o[..])
}
fn is_set(&self, s: &ArgSettings) -> bool {
self.settings.is_set(s)
}
fn set(&mut self, s: &ArgSettings) {
self.settings.set(s)
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::FlagBuilder; use super::FlagBuilder;

View file

@ -1,15 +1,18 @@
pub use self::arg::Arg; pub use self::arg::Arg;
pub use self::argmatches::ArgMatches; pub use self::arg_matches::ArgMatches;
pub use self::subcommand::SubCommand; pub use self::subcommand::SubCommand;
pub use self::argbuilder::{FlagBuilder, OptBuilder, PosBuilder}; pub use self::arg_builder::{FlagBuilder, OptBuilder, PosBuilder};
pub use self::matchedarg::MatchedArg; pub use self::matched_arg::MatchedArg;
pub use self::group::ArgGroup; pub use self::group::ArgGroup;
pub use self::any_arg::AnyArg;
mod arg; mod arg;
mod argmatches; pub mod any_arg;
mod arg_matches;
mod arg_matcher;
mod subcommand; mod subcommand;
mod argbuilder; mod arg_builder;
mod matchedarg; mod matched_arg;
mod group; mod group;
#[allow(dead_code)] #[allow(dead_code)]
pub mod settings; pub mod settings;