feat(positionals): add support for multiple values

Add support for #44 (multiple values for positional arguments) when the
positional argument is the last one (i.e. highest index)
This commit is contained in:
Kevin K 2015-03-29 16:44:30 -04:00
parent f244ca6f9a
commit 8078400941
3 changed files with 50 additions and 23 deletions

View file

@ -207,9 +207,9 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
if a.short.is_some() || a.long.is_some() {
panic!("Argument \"{}\" has conflicting requirements, both index() and short(), or long(), were supplied", a.name);
}
if a.multiple {
panic!("Argument \"{}\" has conflicting requirements, both index() and multiple(true) were supplied",a.name);
}
// if a.multiple {
// panic!("Argument \"{}\" has conflicting requirements, both index() and multiple(true) were supplied",a.name);
// }
if a.takes_value {
panic!("Argument \"{}\" has conflicting requirements, both index() and takes_value(true) were supplied", a.name);
}
@ -218,6 +218,7 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
name: a.name,
index: i,
required: a.required,
multiple: a.multiple,
blacklist: None,
requires: None,
possible_vals: None,
@ -652,10 +653,27 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
}
}
}
matches.positionals.insert(p.name, PosArg{
name: p.name.to_owned(),
value: arg.clone(),
});
// Have we made the update yet?
let mut done = false;
if p.multiple {
// Check if it's already existing and update if so...
if let Some(ref mut pa) = matches.positionals.get_mut(p.name) {
done = true;
pa.occurrences += 1;
pa.values.push(arg.clone());
}
} else {
// Only increment the positional counter if it doesn't allow multiples
pos_counter += 1;
}
// Was an update made, or is this the first occurrence?
if !done {
matches.positionals.insert(p.name, PosArg{
name: p.name.to_owned(),
occurrences: 1,
values: vec![arg.clone()],
});
}
if let Some(ref bl) = p.blacklist {
for name in bl {
@ -676,7 +694,6 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
self.required.insert(n);
}
}
pos_counter += 1;
} else {
self.report_error(format!("Positional argument \"{}\" was found, but {} wasn't expecting any", arg, self.name), true, true);
}

View file

@ -91,8 +91,8 @@ impl<'a> ArgMatches<'a> {
/// an additional value at runtime). If the option wasn't present at runtime
/// it returns `None`.
///
/// *NOTE:* If getting a value for an option argument that allows multiples, prefer `values_of()`
/// as `value_of()` will only return the _*first*_ value.
/// *NOTE:* If getting a value for an option or positional argument that allows multiples,
/// prefer `values_of()` as `value_of()` will only return the _*first*_ value.
///
/// # Example
///
@ -105,21 +105,21 @@ impl<'a> ArgMatches<'a> {
/// ```
pub fn value_of<'n>(&self, name: &'n str) -> Option<&str> {
if let Some(ref opt) = self.opts.get(name) {
if !opt.values.is_empty() {
if let Some(ref s) = opt.values.iter().nth(0) {
return Some(&s[..]);
}
}
if let Some(ref s) = opt.values.iter().nth(0) {
return Some(&s[..]);
}
}
if let Some(ref pos) = self.positionals.get(name) {
return Some(&pos.value[..]);
if let Some(ref s) = pos.values.iter().nth(0) {
return Some(&s[..]);
}
}
None
}
/// Gets the values of a specific option in a vector (i.e. an argument that takes
/// an additional value at runtime). If the option wasn't present at runtime
/// it returns `None`
/// Gets the values of a specific option or positional argument in a vector (i.e. an argument
/// that takes an additional value at runtime). If the option wasn't present at runtime it
/// returns `None`
///
/// # Example
///
@ -141,6 +141,11 @@ impl<'a> ArgMatches<'a> {
return Some(opt.values.iter().map(|s| &s[..]).collect::<Vec<_>>());
}
if let Some(ref pos) = self.positionals.get(name) {
if pos.values.is_empty() { return None; }
return Some(pos.values.iter().map(|s| &s[..]).collect::<Vec<_>>());
}
None
}
@ -167,13 +172,11 @@ impl<'a> ArgMatches<'a> {
false
}
/// Checks the number of occurrences of an option or flag at runtime.
/// Checks the number of occurrences of an option, flag, or positional argument at runtime.
/// If an option or flag isn't present it will return `0`, if the option or flag doesn't
/// allow multiple occurrences, it will return `1` no matter how many times it occurred
/// (unless it wasn't prsent) at all.
///
/// *NOTE:* This _*DOES NOT*_ work for positional arguments (use `.value_of()` instead).
///
///
/// # Example
///
@ -193,6 +196,9 @@ impl<'a> ArgMatches<'a> {
if let Some(ref o) = self.opts.get(name) {
return o.occurrences;
}
if let Some(ref p) = self.positionals.get(name) {
return p.occurrences;
}
0
}

View file

@ -16,8 +16,10 @@ use std::collections::HashSet;
pub struct PosArg {
/// The unique name of the argument, required
pub name: String,
/// How many occurences of this option have been found when parsing
pub occurrences: u8,
/// The value provided to the argument by the user
pub value: String,
pub values: Vec<String>
}
pub struct PosBuilder<'n> {
@ -30,6 +32,8 @@ pub struct PosBuilder<'n> {
/// **NOTE:** required by default means, it is required *until* mutually
/// exclusive arguments are evaluated.
pub required: bool,
/// Allow multiple occurrences of an option argument such as "-c some -c other"
pub multiple: bool,
/// A list of names of other arguments that are *required* to be used when
/// this flag is used
pub requires: Option<HashSet<&'n str>>,