Skip to content

Commit

Permalink
feat: adds support with options with optional values
Browse files Browse the repository at this point in the history
Closes #367
  • Loading branch information
kbknapp committed Jan 28, 2016
1 parent da22401 commit 4555736
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 35 deletions.
19 changes: 11 additions & 8 deletions src/app/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ macro_rules! parse_positional {
$pos_counter == $_self.positionals.len()) {
$pos_only = true;
}

$matcher.inc_occurrence_of($p.name);
let _ = $_self.groups_for_arg($p.name).and_then(|vec| Some($matcher.inc_occurrences_of(&*vec)));
arg_post_processing!($_self, $p, $matcher);
// Only increment the positional counter if it doesn't allow multiples
if !$p.settings.is_set(ArgSettings::Multiple) {
Expand Down Expand Up @@ -156,7 +159,6 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
a.name);
}
let pb = PosBuilder::from_arg(&a, i as u8, &mut self.required);
// self.positionals_name.insert(pb.name, i);
self.positionals.insert(i, pb);
} else if a.takes_value {
let ob = OptBuilder::from_arg(&a, &mut self.required);
Expand Down Expand Up @@ -555,7 +557,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
try!(self.validate_required(matcher));
reqs_validated = true;
let should_err = if let Some(ref v) = matcher.0.args.get(&*o.name) {
v.vals.is_empty()
v.vals.is_empty() && !(o.min_vals.is_some() && o.min_vals.unwrap() == 0)
} else {
true
};
Expand Down Expand Up @@ -1037,6 +1039,10 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
try!(self.add_val_to_arg(opt, v, matcher));
} else { sdebugln!("None"); }

matcher.inc_occurrence_of(opt.name);
// Increment or create the group "args"
self.groups_for_arg(opt.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));

if (opt.is_set(ArgSettings::Multiple) || opt.num_vals().is_some())
|| val.is_none() {
return Ok(Some(opt.name));
Expand Down Expand Up @@ -1124,8 +1130,7 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
debugln!("fn=parse_flag;");
validate_multiples!(self, flag, matcher);

matcher.inc_occurrence_of(&*flag.name.clone());

matcher.inc_occurrence_of(flag.name);
// Increment or create the group "args"
self.groups_for_arg(flag.name).and_then(|vec| Some(matcher.inc_occurrences_of(&*vec)));

Expand Down Expand Up @@ -1295,11 +1300,9 @@ impl<'a, 'b> Parser<'a, 'b> where 'a: 'b {
}
if let Some(a) = self.flags.iter().filter(|f| &f.name == name).next() {
if self._validate_blacklist_required(a, matcher) { continue 'outer; }
}
if let Some(a) = self.opts.iter().filter(|o| &o.name == name).next() {
} else if let Some(a) = self.opts.iter().filter(|o| &o.name == name).next() {
if self._validate_blacklist_required(a, matcher) { continue 'outer; }
}
if let Some(a) = self.positionals.values().filter(|p| &p.name == name).next() {
} else if let Some(a) = self.positionals.values().filter(|p| &p.name == name).next() {
if self._validate_blacklist_required(a, matcher) { continue 'outer; }
}
let err = if self.settings.is_set(AppSettings::ArgRequiredElseHelp) && matcher.is_empty() {
Expand Down
23 changes: 8 additions & 15 deletions src/args/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -878,9 +878,10 @@ impl<'a, 'b> Arg<'a, 'b> {
/// `.max_values(3)`, and this argument would be satisfied if the user provided, 1, 2, or 3
/// values.
///
/// **NOTE:** `qty` must be > 1
///
/// **NOTE:** This implicitly sets `.multiple(true)`
/// **NOTE:** For positional arguments this implicitly sets `multiple(true)` but does *not*
/// for options. This is because `-o val -o val` is multiples occurrences but a single value
/// and `-o val1 val2` is a single occurence with multple values. For positional arguments
/// there is no way to determine the diffrence between multiple occureces and multiple values.
///
/// # Examples
///
Expand All @@ -892,13 +893,7 @@ impl<'a, 'b> Arg<'a, 'b> {
/// .max_values(3)
/// # ).get_matches();
pub fn max_values(mut self, qty: u8) -> Self {
if qty < 2 {
panic!("Arguments with max_values(qty) qty must be > 1. Prefer \
takes_value(true) for arguments with only one value, or flags for arguments \
with 0 values.");
}
self.max_vals = Some(qty);
self.multiple = true;
self
}

Expand All @@ -907,12 +902,11 @@ impl<'a, 'b> Arg<'a, 'b> {
/// `.min_values(2)`, and this argument would be satisfied if the user provided, 2 or more
/// values.
///
/// **NOTE:** This implicitly sets `.multiple(true)`
///
/// **NOTE:** `qty` must be > 0
/// **NOTE:** For positional arguments this implicitly sets `multiple(true)` but does *not*
/// for options. This is because `-o val -o val` is multiples occurrences but a single value
/// and `-o val1 val2` is a single occurence with multple values. For positional arguments
/// there is no way to determine the diffrence between multiple occureces and multiple values.
///
/// **NOTE:** `qty` *must* be > 0. If you wish to have an argument with 0 or more values prefer
/// two separate arguments (a flag, and an option with multiple values).
///
/// # Examples
///
Expand All @@ -925,7 +919,6 @@ impl<'a, 'b> Arg<'a, 'b> {
/// # ).get_matches();
pub fn min_values(mut self, qty: u8) -> Self {
self.min_vals = Some(qty);
self.multiple = true;
self
}

Expand Down
2 changes: 1 addition & 1 deletion src/args/arg_builder/positional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ impl<'n, 'e> PosBuilder<'n, 'e> {
help: a.help,
..Default::default()
};
if a.multiple {
if a.multiple || a.num_vals.is_some() || a.max_vals.is_some() || a.min_vals.is_some() {
pb.settings.set(ArgSettings::Multiple);
}
if a.required {
Expand Down
11 changes: 1 addition & 10 deletions src/args/arg_matcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,6 @@ impl<'a> ArgMatcher<'a> {
self.0.args.is_empty()
}

// pub fn values_of(&'a self, arg: &str) -> Values<'a> {
// self.0.values_of(arg)
// }

// pub fn os_values_of(&'a self, arg: &str) -> OsValues<'a> {
// self.0.os_values_of(arg)
// }

pub fn usage(&mut self, usage: String) {
self.0.usage = Some(usage);
}
Expand All @@ -71,6 +63,7 @@ impl<'a> ArgMatcher<'a> {

pub fn inc_occurrence_of(&mut self, arg: &'a str) {
if let Some(a) = self.get_mut(arg) {
debugln!("+1 to {}'s occurrences", arg);
a.occurs += 1;
return;
}
Expand All @@ -85,13 +78,11 @@ impl<'a> ArgMatcher<'a> {

pub fn add_val_to(&mut self, arg: &'a str, val: &OsStr) {
let ma = self.entry(arg).or_insert(MatchedArg {
// occurrences will be incremented on getting a value
occurs: 0,
vals: VecMap::new(),
});
let len = ma.vals.len() + 1;
ma.vals.insert(len, val.to_owned());
ma.occurs += 1;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,7 @@ impl Error {
{
let a = arg.into();
Error {
message: format!("{} The argument '{}' wasn't recognized, or isn't valid{}\n\
message: format!("{} The argument '{}' wasn't recognized, or isn't valid in this context{}\n\
{}\n\n\
For more information try {}",
Format::Error("error:"),
Expand Down

0 comments on commit 4555736

Please sign in to comment.