Skip to content

Commit

Permalink
Auto merge of #283 - kbknapp:issue-279, r=kbknapp
Browse files Browse the repository at this point in the history
Issue 279

Allows accessing values by group name, and checking presence of any arg in a group in matches.
  • Loading branch information
homu committed Sep 28, 2015
2 parents 5943ec0 + e102c1b commit 9352117
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 5 deletions.
141 changes: 140 additions & 1 deletion src/app/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1302,6 +1302,22 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
self
}

fn groups_for(&self, name: &str) -> Option<Vec<&'ar str>> {
if self.groups.is_empty() { return None; }
let mut res = vec![];
for (g_name, grp) in &self.groups {
for a in &grp.args {
if a == &name {
res.push(*g_name);
}
}
}
res.dedup();
if res.is_empty() { return None }

Some(res)
}

fn get_group_members(&self,
group: &str)
-> Vec<String> {
Expand Down Expand Up @@ -2387,6 +2403,23 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
));
}

if let Some(ref vec) = self.groups_for(opt.name) {
for grp in vec {
if let Some(ref mut o) = matches.args.get_mut(grp) {
o.occurrences = if opt.multiple {
o.occurrences + 1
} else {
1
};
// Values must be inserted in order...the user may care about that!
if let Some(ref mut vals) = o.values {
let len = vals.len() as u8 + 1;
vals.insert(len, arg_slice.to_owned());
}
}

}
}
// save the value to matched option
if let Some(ref mut o) = matches.args.get_mut(opt.name) {
// if it's multiple; the occurrences are increased when originally
Expand Down Expand Up @@ -2632,6 +2665,14 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
}
bm.insert(1, arg_slice.to_owned());
if let Some(ref vec) = self.groups_for(p.name) {
for grp in vec {
matches.args.insert(grp, MatchedArg{
occurrences: 1,
values: Some(bm.clone()),
});
}
}
matches.args.insert(p.name, MatchedArg{
occurrences: 1,
values: Some(bm),
Expand Down Expand Up @@ -2988,6 +3029,14 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
.filter(|&v| v.long.unwrap() == arg).nth(0) {
// prevents "--config= value" typo
if arg_vec[1].len() == 0 && !v.empty_vals {
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
matches.args.insert(grp, MatchedArg{
occurrences: 1,
values: None,
});
}
}
matches.args.insert(v.name, MatchedArg {
occurrences: 1,
values: None
Expand Down Expand Up @@ -3020,12 +3069,22 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
debugln!("checking who defined it...");
if let Some(name) = self.overriden_from(v.name, matches) {
debugln!("found {}", name);
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
matches.args.remove(grp);
}
}
matches.args.remove(name);
remove_override!(self, name);
}
}
if let Some(ref or) = v.overrides {
for pa in or {
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
matches.args.remove(grp);
}
}
matches.args.remove(pa);
remove_override!(self, pa);
self.overrides.push(pa);
Expand All @@ -3041,6 +3100,17 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
App::get_args(matches)));
}
if let Some(av) = arg_val {
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
if let Some(ref mut o) = matches.args.get_mut(grp) {
o.occurrences += 1;
if let Some(ref mut vals) = o.values {
let len = (vals.len() + 1) as u8;
vals.insert(len, av.to_owned());
}
}
}
}
if let Some(ref mut o) = matches.args.get_mut(v.name) {
o.occurrences += 1;
if let Some(ref mut vals) = o.values {
Expand All @@ -3058,6 +3128,14 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
let mut bm = BTreeMap::new();
if let Some(val) = arg_val {
bm.insert(1, val.to_owned());
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
matches.args.insert(grp, MatchedArg{
occurrences: 1,
values: Some(bm.clone()),
});
}
}
matches.args.insert(v.name, MatchedArg{
occurrences: 1,
values: Some(bm)
Expand All @@ -3068,6 +3146,14 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
return Err(e);
}
} else {
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
matches.args.insert(grp, MatchedArg{
occurrences: 1,
values: Some(bm.clone()),
});
}
}
matches.args.insert(v.name, MatchedArg{
occurrences: 0,
values: Some(bm)
Expand Down Expand Up @@ -3161,6 +3247,14 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
};
}
if !done {
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
matches.args.insert(grp, MatchedArg{
occurrences: 1,
values: None,
});
}
}
matches.args.insert(v.name, MatchedArg{
// name: v.name.to_owned(),
occurrences: 1,
Expand Down Expand Up @@ -3212,6 +3306,14 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
})
.next() {
if let Some(ref vec) = self.groups_for(opt) {
for grp in vec {
matches.args.insert(grp, MatchedArg{
occurrences: 1,
values: None,
});
}
}
matches.args.insert(opt, MatchedArg {
occurrences: 0,
values: None
Expand All @@ -3225,6 +3327,14 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
}
})
.next() {
if let Some(ref vec) = self.groups_for(flg) {
for grp in vec {
matches.args.insert(grp, MatchedArg{
occurrences: 1,
values: None,
});
}
}
matches.args.insert(flg, MatchedArg {
occurrences: 0,
values: None
Expand Down Expand Up @@ -3360,6 +3470,14 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
App::get_args(matches)));
}
} else {
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
matches.args.insert(grp, MatchedArg{
occurrences: 1,
values: Some(BTreeMap::new()),
});
}
}
matches.args.insert(v.name, MatchedArg{
// occurrences will be incremented on getting a value
occurrences: 0,
Expand Down Expand Up @@ -3447,6 +3565,17 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
App::get_args(matches)));
}

if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
if let Some(ref mut f) = matches.args.get_mut(grp) {
f.occurrences = if v.multiple {
f.occurrences + 1
} else {
1
};
}
}
}
let mut done = false;
if let Some(ref mut f) = matches.args.get_mut(v.name) {
done = true;
Expand All @@ -3457,6 +3586,14 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
};
}
if !done {
if let Some(ref vec) = self.groups_for(v.name) {
for grp in vec {
matches.args.insert(grp, MatchedArg{
occurrences: 1,
values: None,
});
}
}
matches.args.insert(v.name, MatchedArg{
// name: v.name.to_owned(),
occurrences: 1,
Expand Down Expand Up @@ -3543,7 +3680,9 @@ impl<'a, 'v, 'ab, 'u, 'h, 'ar> App<'a, 'v, 'ab, 'u, 'h, 'ar>{
matches: &mut ArgMatches<'ar, 'ar>)
-> Result<(), ClapError> {
for (name, ma) in matches.args.iter() {
if let Some(ref vals) = ma.values {
if self.groups.contains_key(name) {
continue;
} else if let Some(ref vals) = ma.values {
if let Some(f) = self.opts.get(name) {
if let Some(num) = f.num_vals {
let should_err = if f.multiple {
Expand Down
3 changes: 0 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,3 @@ mod app;
mod args;
mod usageparser;
mod fmt;

#[cfg(test)]
mod tests;
57 changes: 57 additions & 0 deletions tests/groups.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
extern crate clap;

use clap::{App, ArgGroup, ClapErrorType};

#[test]
fn required_group_missing_arg() {
let result = App::new("group")
.args_from_usage("-f, --flag 'some flag'
-c, --color 'some other flag'")
.arg_group(ArgGroup::with_name("req")
.add_all(&["flag", "color"])
.required(true))
.get_matches_from_safe(vec![""]);
assert!(result.is_err());
let err = result.err().unwrap();
assert_eq!(err.error_type, ClapErrorType::MissingRequiredArgument);
}

#[test]
fn group_single_value() {
let m = App::new("group")
.args_from_usage("-f, --flag 'some flag'
-c, --color [color] 'some option'")
.arg_group(ArgGroup::with_name("grp")
.add_all(&["flag", "color"]))
.get_matches_from(vec!["", "-c", "blue"]);
assert!(m.is_present("grp"));
assert_eq!(m.value_of("grp").unwrap(), "blue");
let m = App::new("group")
.args_from_usage("-f, --flag 'some flag'
-c, --color [color] 'some option'")
.arg_group(ArgGroup::with_name("grp")
.add_all(&["flag", "color"]))
.get_matches_from(vec!["", "-f"]);
assert!(m.is_present("grp"));
assert!(m.value_of("grp").is_none());
let m = App::new("group")
.args_from_usage("-f, --flag 'some flag'
-c, --color [color] 'some option'")
.arg_group(ArgGroup::with_name("grp")
.add_all(&["flag", "color"]))
.get_matches_from(vec![""]);
assert!(!m.is_present("grp"));
assert!(m.value_of("grp").is_none());
}

#[test]
fn group_multi_value_single_arg() {
let m = App::new("group")
.args_from_usage("-f, --flag 'some flag'
-c, --color [color]... 'some option'")
.arg_group(ArgGroup::with_name("grp")
.add_all(&["flag", "color"]))
.get_matches_from(vec!["", "-c", "blue", "red", "green"]);
assert!(m.is_present("grp"));
assert_eq!(m.values_of("grp").unwrap(), &["blue", "red", "green"]);
}
5 changes: 4 additions & 1 deletion src/tests.rs → tests/tests.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#[macro_use]
extern crate clap;

use std::collections::HashSet;

use super::{App, Arg, ArgGroup, SubCommand};
use clap::{App, Arg, ArgGroup, SubCommand};
use std::vec::Vec;

arg_enum!{
Expand Down

0 comments on commit 9352117

Please sign in to comment.