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() { if a.short.is_some() || a.long.is_some() {
panic!("Argument \"{}\" has conflicting requirements, both index() and short(), or long(), were supplied", a.name); panic!("Argument \"{}\" has conflicting requirements, both index() and short(), or long(), were supplied", a.name);
} }
if a.multiple { // if a.multiple {
panic!("Argument \"{}\" has conflicting requirements, both index() and multiple(true) were supplied",a.name); // panic!("Argument \"{}\" has conflicting requirements, both index() and multiple(true) were supplied",a.name);
} // }
if a.takes_value { if a.takes_value {
panic!("Argument \"{}\" has conflicting requirements, both index() and takes_value(true) were supplied", a.name); 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, name: a.name,
index: i, index: i,
required: a.required, required: a.required,
multiple: a.multiple,
blacklist: None, blacklist: None,
requires: None, requires: None,
possible_vals: 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{ // Have we made the update yet?
name: p.name.to_owned(), let mut done = false;
value: arg.clone(), 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 { if let Some(ref bl) = p.blacklist {
for name in bl { for name in bl {
@ -676,7 +694,6 @@ impl<'a, 'v, 'ab, 'u, 'ar> App<'a, 'v, 'ab, 'u, 'ar>{
self.required.insert(n); self.required.insert(n);
} }
} }
pos_counter += 1;
} else { } else {
self.report_error(format!("Positional argument \"{}\" was found, but {} wasn't expecting any", arg, self.name), true, true); 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 /// an additional value at runtime). If the option wasn't present at runtime
/// it returns `None`. /// it returns `None`.
/// ///
/// *NOTE:* If getting a value for an option argument that allows multiples, prefer `values_of()` /// *NOTE:* If getting a value for an option or positional argument that allows multiples,
/// as `value_of()` will only return the _*first*_ value. /// prefer `values_of()` as `value_of()` will only return the _*first*_ value.
/// ///
/// # Example /// # Example
/// ///
@ -105,21 +105,21 @@ impl<'a> ArgMatches<'a> {
/// ``` /// ```
pub fn value_of<'n>(&self, name: &'n str) -> Option<&str> { pub fn value_of<'n>(&self, name: &'n str) -> Option<&str> {
if let Some(ref opt) = self.opts.get(name) { if let Some(ref opt) = self.opts.get(name) {
if !opt.values.is_empty() { if let Some(ref s) = opt.values.iter().nth(0) {
if let Some(ref s) = opt.values.iter().nth(0) { return Some(&s[..]);
return Some(&s[..]); }
}
}
} }
if let Some(ref pos) = self.positionals.get(name) { 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 None
} }
/// Gets the values of a specific option in a vector (i.e. an argument that takes /// Gets the values of a specific option or positional argument in a vector (i.e. an argument
/// an additional value at runtime). If the option wasn't present at runtime /// that takes an additional value at runtime). If the option wasn't present at runtime it
/// it returns `None` /// returns `None`
/// ///
/// # Example /// # Example
/// ///
@ -141,6 +141,11 @@ impl<'a> ArgMatches<'a> {
return Some(opt.values.iter().map(|s| &s[..]).collect::<Vec<_>>()); 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 None
} }
@ -167,13 +172,11 @@ impl<'a> ArgMatches<'a> {
false 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 /// 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 /// allow multiple occurrences, it will return `1` no matter how many times it occurred
/// (unless it wasn't prsent) at all. /// (unless it wasn't prsent) at all.
/// ///
/// *NOTE:* This _*DOES NOT*_ work for positional arguments (use `.value_of()` instead).
///
/// ///
/// # Example /// # Example
/// ///
@ -193,6 +196,9 @@ impl<'a> ArgMatches<'a> {
if let Some(ref o) = self.opts.get(name) { if let Some(ref o) = self.opts.get(name) {
return o.occurrences; return o.occurrences;
} }
if let Some(ref p) = self.positionals.get(name) {
return p.occurrences;
}
0 0
} }

View file

@ -16,8 +16,10 @@ use std::collections::HashSet;
pub struct PosArg { pub struct PosArg {
/// The unique name of the argument, required /// The unique name of the argument, required
pub name: String, 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 /// The value provided to the argument by the user
pub value: String, pub values: Vec<String>
} }
pub struct PosBuilder<'n> { pub struct PosBuilder<'n> {
@ -30,6 +32,8 @@ pub struct PosBuilder<'n> {
/// **NOTE:** required by default means, it is required *until* mutually /// **NOTE:** required by default means, it is required *until* mutually
/// exclusive arguments are evaluated. /// exclusive arguments are evaluated.
pub required: bool, 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 /// A list of names of other arguments that are *required* to be used when
/// this flag is used /// this flag is used
pub requires: Option<HashSet<&'n str>>, pub requires: Option<HashSet<&'n str>>,