Skip to content

Commit

Permalink
imp(ArgGroup): Add multiple ArgGroups per Arg
Browse files Browse the repository at this point in the history
Add the function `Arg.groups` that can take a `Vec<&'a str>` to add the `Arg` to multiple `ArgGroup`'s at once.

ex:
```rust
Arg::with_name("arg")
    .groups(&["grp1", "grp2"])
```

Closes #426
  • Loading branch information
brianp committed Jun 24, 2016
1 parent 16c693a commit 902e182
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 7 deletions.
8 changes: 5 additions & 3 deletions src/app/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,11 @@ impl<'a, 'b> Parser<'a, 'b>
self.opts.iter().any(|o| o.name == a.name) ||
self.positionals.values().any(|p| p.name == a.name)),
format!("Non-unique argument name: {} is already in use", a.name));
if let Some(grp) = a.group {
let ag = self.groups.entry(grp).or_insert_with(|| ArgGroup::with_name(grp));
ag.args.push(a.name);
if let Some(ref grps) = a.group {
for g in grps {
let ag = self.groups.entry(g).or_insert_with(|| ArgGroup::with_name(g));
ag.args.push(a.name);
}
}
if let Some(s) = a.short {
debug_assert!(!self.short_list.contains(&s),
Expand Down
60 changes: 56 additions & 4 deletions src/args/arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub struct Arg<'a, 'b>
#[doc(hidden)]
pub requires: Option<Vec<&'a str>>,
#[doc(hidden)]
pub group: Option<&'a str>,
pub group: Option<Vec<&'a str>>,
#[doc(hidden)]
pub val_names: Option<VecMap<&'b str>>,
#[doc(hidden)]
Expand Down Expand Up @@ -176,6 +176,14 @@ impl<'a, 'b> Arg<'a, 'b> {
}
a
}
"groups" => {
for ys in v.as_vec().unwrap() {
if let Some(s) = ys.as_str() {
a = a.group(s);
}
}
a
}
"requires" => {
for ys in v.as_vec().unwrap() {
if let Some(s) = ys.as_str() {
Expand Down Expand Up @@ -1612,7 +1620,51 @@ impl<'a, 'b> Arg<'a, 'b> {
/// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html
pub fn group(mut self, name: &'a str) -> Self {
self.group = Some(name);
if let Some(ref mut vec) = self.requires {
vec.push(name);
} else {
self.group = Some(vec![name]);
}
self
}

/// Specifies the names of multiple [`ArgGroup`]'s the argument belongs to.
///
/// # Examples
///
/// ```rust
/// # use clap::{App, Arg};
/// Arg::with_name("debug")
/// .long("debug")
/// .groups(&["mode", "verbosity"])
/// # ;
/// ```
///
/// Arguments can be members of multiple groups and then the group checked as if it
/// was one of said arguments.
///
/// ```rust
/// # use clap::{App, Arg};
/// let m = App::new("groups")
/// .arg(Arg::with_name("debug")
/// .long("debug")
/// .groups(&["mode", "verbosity"]))
/// .arg(Arg::with_name("verbose")
/// .long("verbose")
/// .groups(&["mode", "verbosity"]))
/// .get_matches_from(vec!["posvals", "--debug"]);
/// assert!(m.is_present("mode"));
/// assert!(m.is_present("verbosity"));
/// ```
/// [`ArgGroup`]: ./struct.ArgGroup.html
pub fn groups(mut self, names: &[&'a str]) -> Self {
if let Some(ref mut vec) = self.group {
for s in names {
vec.push(s);
}
} else {
self.group = Some(names.into_iter().map(|s| *s).collect::<Vec<_>>());
}
self
}

Expand Down Expand Up @@ -2234,7 +2286,7 @@ impl<'a, 'b, 'z> From<&'z Arg<'a, 'b>> for Arg<'a, 'b> {
min_vals: a.min_vals,
max_vals: a.max_vals,
val_names: a.val_names.clone(),
group: a.group,
group: a.group.clone(),
validator: a.validator.clone(),
overrides: a.overrides.clone(),
settings: a.settings,
Expand All @@ -2261,7 +2313,7 @@ impl<'a, 'b> Clone for Arg<'a, 'b> {
min_vals: self.min_vals,
max_vals: self.max_vals,
val_names: self.val_names.clone(),
group: self.group,
group: self.group.clone(),
validator: self.validator.clone(),
overrides: self.overrides.clone(),
settings: self.settings,
Expand Down

0 comments on commit 902e182

Please sign in to comment.