Skip to content

Commit

Permalink
imp(Traits): refactoring some configuration into traits
Browse files Browse the repository at this point in the history
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
  • Loading branch information
kbknapp committed Nov 11, 2015
1 parent 1fdecfd commit 5800cde
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 45 deletions.
82 changes: 43 additions & 39 deletions src/app/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::path::Path;
use std::process;
use std::ffi::OsStr;
use std::borrow::Borrow;
use std::fmt::Display;

#[cfg(feature = "yaml")]
use yaml_rust::Yaml;
Expand All @@ -18,7 +19,7 @@ use vec_map::VecMap;
use args::{Arg, ArgMatches, MatchedArg, SubCommand};
use args::{FlagBuilder, OptBuilder, PosBuilder};
use args::settings::{ArgFlags, ArgSettings};
use args::ArgGroup;
use args::{ArgGroup, AnyArg};
use fmt::Format;
use self::settings::AppFlags;
use suggestions;
Expand Down Expand Up @@ -3059,43 +3060,12 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar> {
matches: &mut ArgMatches<'ar, 'ar>,
arg: char)
-> ClapResult<bool> {
if let Some(v) = self.flags
.iter()
.filter(|&v| v.short.is_some() && v.short.unwrap() == arg)
.next() {
// 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 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))));
}
let v = self.flags.iter().filter(|&v| v.short.is_some() && v.short.unwrap() == arg).next();
if v.is_some() {
let flag = v.unwrap();
try!(self.validate_arg(flag, matches));

if let Some(ref vec) = self.groups_for_arg(v.name) {
if let Some(ref vec) = self.groups_for_arg(flag.name) {
for grp in vec {
if let Some(ref mut f) = matches.args.get_mut(grp) {
f.occurrences = if v.settings.is_set(&ArgSettings::Multiple) {
Expand Down Expand Up @@ -3159,6 +3129,40 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar> {
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<()> {
for name in self.blacklist.iter() {
if matches.args.contains_key(name) {
Expand Down Expand Up @@ -3254,8 +3258,8 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar> {
return Err(error_builder::TooManyValues(
vals.get(vals.keys()
.last()
.expect("error getting last key. This is a bug"))
.expect("failed to retrieve last value. This is a bug"),
.expect(INTERNAL_ERROR_MSG))
.expect(INTERNAL_ERROR_MSG),
&f.to_string(),
&try!(self.create_current_usage(matches))));
}
Expand Down
8 changes: 8 additions & 0 deletions src/args/any_arg.rs
Original file line number Diff line number Diff line change
@@ -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);
}
20 changes: 20 additions & 0 deletions src/args/arg_builder/flag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::convert::From;
use std::io;

use Arg;
use args::AnyArg;
use args::settings::{ArgFlags, ArgSettings};

#[derive(Debug)]
Expand Down Expand Up @@ -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)]
mod test {
use super::FlagBuilder;
Expand Down
15 changes: 9 additions & 6 deletions src/args/mod.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
pub use self::arg::Arg;
pub use self::argmatches::ArgMatches;
pub use self::arg_matches::ArgMatches;
pub use self::subcommand::SubCommand;
pub use self::argbuilder::{FlagBuilder, OptBuilder, PosBuilder};
pub use self::matchedarg::MatchedArg;
pub use self::arg_builder::{FlagBuilder, OptBuilder, PosBuilder};
pub use self::matched_arg::MatchedArg;
pub use self::group::ArgGroup;
pub use self::any_arg::AnyArg;

mod arg;
mod argmatches;
pub mod any_arg;
mod arg_matches;
mod arg_matcher;
mod subcommand;
mod argbuilder;
mod matchedarg;
mod arg_builder;
mod matched_arg;
mod group;
#[allow(dead_code)]
pub mod settings;

0 comments on commit 5800cde

Please sign in to comment.