clap/src/args/group.rs

635 lines
22 KiB
Rust
Raw Normal View History

#[cfg(feature = "yaml")]
use std::collections::BTreeMap;
use std::fmt::{Debug, Formatter, Result};
#[cfg(feature = "yaml")]
use yaml_rust::Yaml;
/// `ArgGroup`s are a family of related [arguments] and way for you to express, "Any of these
2016-01-26 19:02:10 +00:00
/// arguments". By placing arguments in a logical group, you can create easier requirement and
/// exclusion rules instead of having to list each argument individually, or when you want a rule
/// to apply "any but not all" arguments.
///
/// For instance, you can make an entire `ArgGroup` required. If [`ArgGroup::multiple(true)`] is
/// set, this means that at least one argument from that group must be present. If
/// [`ArgGroup::multiple(false)`] is set (the default), one and *only* one must be present.
2015-05-01 18:44:20 +00:00
///
/// You can also do things such as name an entire `ArgGroup` as a [conflict] or [requirement] for
2016-01-26 19:02:10 +00:00
/// another argument, meaning any of the arguments that belong to that group will cause a failure
/// if present, or must present respectively.
///
2015-05-01 18:44:20 +00:00
/// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
/// present out of a given set. Imagine that you had multiple arguments, and you want one of them
/// to be required, but making all of them required isn't feasible because perhaps they conflict
/// with each other. For example, lets say that you were building an application where one could
/// set a given version number by supplying a string with an option argument, i.e.
/// `--set-ver v1.2.3`, you also wanted to support automatically using a previous version number
/// and simply incrementing one of the three numbers. So you create three flags `--major`,
/// `--minor`, and `--patch`. All of these arguments shouldn't be used at one time but you want to
/// specify that *at least one* of them is used. For this, you can create a group.
///
2016-01-26 19:02:10 +00:00
/// Finally, you may use `ArgGroup`s to pull a value from a group of arguments when you don't care
2016-06-24 10:23:08 +00:00
/// exactly which argument was actually used at runtime.
2016-01-26 19:02:10 +00:00
///
/// # Examples
///
2016-01-26 19:02:10 +00:00
/// The following example demonstrates using an `ArgGroup` to ensure that one, and only one, of
/// the arguments from the specified group is present at runtime.
///
/// ```rust
/// # use clap::{App, ArgGroup, ErrorKind};
/// let result = App::new("app")
/// .args_from_usage(
/// "--set-ver [ver] 'set the version manually'
/// --major 'auto increase major'
/// --minor 'auto increase minor'
/// --patch 'auto increase patch'")
/// .group(ArgGroup::with_name("vers")
/// .args(&["set-ver", "major", "minor","patch"])
/// .required(true))
/// .get_matches_from_safe(vec!["app", "--major", "--patch"]);
/// // Because we used two args in the group it's an error
/// assert!(result.is_err());
/// let err = result.unwrap_err();
/// assert_eq!(err.kind, ErrorKind::ArgumentConflict);
/// ```
/// This next example shows a passing parse of the same scenario
///
/// ```rust
/// # use clap::{App, ArgGroup};
/// let result = App::new("app")
2016-01-26 19:02:10 +00:00
/// .args_from_usage(
/// "--set-ver [ver] 'set the version manually'
/// --major 'auto increase major'
/// --minor 'auto increase minor'
/// --patch 'auto increase patch'")
/// .group(ArgGroup::with_name("vers")
/// .args(&["set-ver", "major", "minor","patch"])
/// .required(true))
/// .get_matches_from_safe(vec!["app", "--major"]);
/// assert!(result.is_ok());
/// let matches = result.unwrap();
/// // We may not know which of the args was used, so we can test for the group...
/// assert!(matches.is_present("vers"));
/// // we could also alternatively check each arg individually (not shown here)
2016-01-26 19:02:10 +00:00
/// ```
/// [`ArgGroup::multiple(true)`]: ./struct.ArgGroup.html#method.multiple
/// [arguments]: ./struct.Arg.html
/// [conflict]: ./struct.Arg.html#method.conflicts_with
/// [requirement]: ./struct.Arg.html#method.requires
#[derive(Default)]
pub struct ArgGroup<'a> {
#[doc(hidden)]
pub name: &'a str,
#[doc(hidden)]
pub args: Vec<&'a str>,
#[doc(hidden)]
pub required: bool,
#[doc(hidden)]
pub requires: Option<Vec<&'a str>>,
#[doc(hidden)]
pub conflicts: Option<Vec<&'a str>>,
#[doc(hidden)]
pub multiple: bool,
}
impl<'a> ArgGroup<'a> {
2016-01-26 19:02:10 +00:00
/// Creates a new instance of `ArgGroup` using a unique string name. The name will be used to
/// get values from the group or refer to the group inside of conflict and requirement rules.
///
/// # Examples
///
2016-01-26 19:02:10 +00:00
/// ```rust
/// # use clap::{App, ArgGroup};
2015-11-01 14:02:37 +00:00
/// ArgGroup::with_name("config")
2016-01-26 19:02:10 +00:00
/// # ;
/// ```
pub fn with_name(n: &'a str) -> Self {
ArgGroup {
name: n,
required: false,
2015-09-04 18:05:13 +00:00
args: vec![],
requires: None,
2015-10-28 14:23:59 +00:00
conflicts: None,
multiple: false,
}
}
2015-11-01 14:02:37 +00:00
/// Creates a new instance of `ArgGroup` from a .yml (YAML) file.
///
/// # Examples
///
/// ```ignore
/// # #[macro_use]
/// # extern crate clap;
/// # use clap::ArgGroup;
/// # fn main() {
/// let yml = load_yaml!("group.yml");
/// let ag = ArgGroup::from_yaml(yml);
/// # }
/// ```
#[cfg(feature = "yaml")]
2016-11-20 19:41:15 +00:00
pub fn from_yaml(y: &'a Yaml) -> ArgGroup<'a> { ArgGroup::from(y.as_hash().unwrap()) }
/// Adds an [argument] to this group by name
///
/// # Examples
///
2016-01-26 19:02:10 +00:00
/// ```rust
/// # use clap::{App, Arg, ArgGroup};
/// let m = App::new("myprog")
/// .arg(Arg::with_name("flag")
/// .short("f"))
/// .arg(Arg::with_name("color")
/// .short("c"))
/// .group(ArgGroup::with_name("req_flags")
/// .arg("flag")
/// .arg("color"))
/// .get_matches_from(vec!["myprog", "-f"]);
/// // maybe we don't know which of the two flags was used...
/// assert!(m.is_present("req_flags"));
/// // but we can also check individually if needed
/// assert!(m.is_present("flag"));
2016-01-26 19:02:10 +00:00
/// ```
/// [argument]: ./struct.Arg.html
2017-03-10 03:32:32 +00:00
#[cfg_attr(feature = "lints", allow(should_assert_eq))]
pub fn arg(mut self, n: &'a str) -> Self {
2015-10-28 14:23:59 +00:00
assert!(self.name != n,
"ArgGroup '{}' can not have same name as arg inside it",
&*self.name);
2015-09-04 18:05:13 +00:00
self.args.push(n);
self
}
/// Adds multiple [arguments] to this group by name
///
/// # Examples
///
2016-01-26 19:02:10 +00:00
/// ```rust
/// # use clap::{App, Arg, ArgGroup};
/// let m = App::new("myprog")
/// .arg(Arg::with_name("flag")
/// .short("f"))
/// .arg(Arg::with_name("color")
/// .short("c"))
/// .group(ArgGroup::with_name("req_flags")
/// .args(&["flag", "color"]))
/// .get_matches_from(vec!["myprog", "-f"]);
/// // maybe we don't know which of the two flags was used...
/// assert!(m.is_present("req_flags"));
/// // but we can also check individually if needed
/// assert!(m.is_present("flag"));
2016-01-26 19:02:10 +00:00
/// ```
/// [arguments]: ./struct.Arg.html
pub fn args(mut self, ns: &[&'a str]) -> Self {
for n in ns {
self = self.arg(n);
}
self
}
/// Allows more than one of the ['Arg']s in this group to be used. (Default: `false`)
///
/// # Examples
///
/// Notice in this example we use *both* the `-f` and `-c` flags which are both part of the
/// group
///
/// ```rust
/// # use clap::{App, Arg, ArgGroup};
/// let m = App::new("myprog")
/// .arg(Arg::with_name("flag")
/// .short("f"))
/// .arg(Arg::with_name("color")
/// .short("c"))
/// .group(ArgGroup::with_name("req_flags")
/// .args(&["flag", "color"])
/// .multiple(true))
/// .get_matches_from(vec!["myprog", "-f", "-c"]);
/// // maybe we don't know which of the two flags was used...
/// assert!(m.is_present("req_flags"));
/// ```
2016-06-24 10:23:08 +00:00
/// In this next example, we show the default behavior (i.e. `multiple(false)) which will throw
/// an error if more than one of the args in the group was used.
///
/// ```rust
/// # use clap::{App, Arg, ArgGroup, ErrorKind};
/// let result = App::new("myprog")
/// .arg(Arg::with_name("flag")
/// .short("f"))
/// .arg(Arg::with_name("color")
/// .short("c"))
/// .group(ArgGroup::with_name("req_flags")
/// .args(&["flag", "color"]))
/// .get_matches_from_safe(vec!["myprog", "-f", "-c"]);
/// // Because we used both args in the group it's an error
/// assert!(result.is_err());
/// let err = result.unwrap_err();
/// assert_eq!(err.kind, ErrorKind::ArgumentConflict);
/// ```
/// ['Arg']: ./struct.Arg.html
pub fn multiple(mut self, m: bool) -> Self {
self.multiple = m;
self
}
2016-01-26 19:02:10 +00:00
/// Sets the group as required or not. A required group will be displayed in the usage string
/// of the application in the format `<arg|arg2|arg3>`. A required `ArgGroup` simply states
/// that one argument from this group *must* be present at runtime (unless
/// conflicting with another argument).
///
/// **NOTE:** This setting only applies to the current [`App`] / [`SubCommand`], and not
/// globally.
///
/// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with
/// `ArgGroup::required(true)` states, "One and *only one* arg must be used from this group.
/// Use of more than one arg is an error." Vice setting `ArgGroup::multiple(true)` which
/// states, '*At least* one arg from this group must be used. Using multiple is OK."
///
/// # Examples
///
2016-01-26 19:02:10 +00:00
/// ```rust
/// # use clap::{App, Arg, ArgGroup, ErrorKind};
/// let result = App::new("myprog")
/// .arg(Arg::with_name("flag")
/// .short("f"))
/// .arg(Arg::with_name("color")
/// .short("c"))
/// .group(ArgGroup::with_name("req_flags")
/// .args(&["flag", "color"])
/// .required(true))
/// .get_matches_from_safe(vec!["myprog"]);
/// // Because we didn't use any of the args in the group, it's an error
/// assert!(result.is_err());
/// let err = result.unwrap_err();
/// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
2016-01-26 19:02:10 +00:00
/// ```
/// [`App`]: ./struct.App.html
/// [`SubCommand`]: ./struct.SubCommand.html
/// [`ArgGroup::multiple`]: ./struct.ArgGroup.html#method.multiple
2015-10-28 14:23:59 +00:00
pub fn required(mut self, r: bool) -> Self {
self.required = r;
self
}
/// Sets the requirement rules of this group. This is not to be confused with a
/// [required group]. Requirement rules function just like [argument requirement rules], you
/// can name other arguments or groups that must be present when any one of the arguments from
/// this group is used.
///
/// **NOTE:** The name provided may be an argument, or group name
///
/// # Examples
///
2016-01-26 19:02:10 +00:00
/// ```rust
/// # use clap::{App, Arg, ArgGroup, ErrorKind};
/// let result = App::new("myprog")
/// .arg(Arg::with_name("flag")
/// .short("f"))
/// .arg(Arg::with_name("color")
/// .short("c"))
/// .arg(Arg::with_name("debug")
/// .short("d"))
/// .group(ArgGroup::with_name("req_flags")
/// .args(&["flag", "color"])
/// .requires("debug"))
/// .get_matches_from_safe(vec!["myprog", "-c"]);
/// // because we used an arg from the group, and the group requires "-d" to be used, it's an
/// // error
/// assert!(result.is_err());
/// let err = result.unwrap_err();
/// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
2016-01-26 19:02:10 +00:00
/// ```
/// [required group]: ./struct.ArgGroup.html#method.required
/// [argument requirement rules]: ./struct.Arg.html#method.requires
pub fn requires(mut self, n: &'a str) -> Self {
if let Some(ref mut reqs) = self.requires {
2015-09-04 18:05:13 +00:00
reqs.push(n);
} else {
2015-09-04 18:05:13 +00:00
self.requires = Some(vec![n]);
}
self
}
/// Sets the requirement rules of this group. This is not to be confused with a
/// [required group]. Requirement rules function just like [argument requirement rules], you
/// can name other arguments or groups that must be present when one of the arguments from this
/// group is used.
///
/// **NOTE:** The names provided may be an argument, or group name
///
/// # Examples
///
2016-01-26 19:02:10 +00:00
/// ```rust
/// # use clap::{App, Arg, ArgGroup, ErrorKind};
/// let result = App::new("myprog")
/// .arg(Arg::with_name("flag")
/// .short("f"))
/// .arg(Arg::with_name("color")
/// .short("c"))
/// .arg(Arg::with_name("debug")
/// .short("d"))
/// .arg(Arg::with_name("verb")
/// .short("v"))
/// .group(ArgGroup::with_name("req_flags")
/// .args(&["flag", "color"])
/// .requires_all(&["debug", "verb"]))
/// .get_matches_from_safe(vec!["myprog", "-c", "-d"]);
/// // because we used an arg from the group, and the group requires "-d" and "-v" to be used,
/// // yet we only used "-d" it's an error
/// assert!(result.is_err());
/// let err = result.unwrap_err();
/// assert_eq!(err.kind, ErrorKind::MissingRequiredArgument);
2016-01-26 19:02:10 +00:00
/// ```
/// [required group]: ./struct.ArgGroup.html#method.required
/// [argument requirement rules]: ./struct.Arg.html#method.requires_all
pub fn requires_all(mut self, ns: &[&'a str]) -> Self {
for n in ns {
self = self.requires(n);
}
self
}
2016-01-26 19:02:10 +00:00
/// Sets the exclusion rules of this group. Exclusion (aka conflict) rules function just like
/// [argument exclusion rules], you can name other arguments or groups that must *not* be
/// present when one of the arguments from this group are used.
///
/// **NOTE:** The name provided may be an argument, or group name
///
/// # Examples
///
2016-01-26 19:02:10 +00:00
/// ```rust
/// # use clap::{App, Arg, ArgGroup, ErrorKind};
/// let result = App::new("myprog")
/// .arg(Arg::with_name("flag")
/// .short("f"))
/// .arg(Arg::with_name("color")
/// .short("c"))
/// .arg(Arg::with_name("debug")
/// .short("d"))
/// .group(ArgGroup::with_name("req_flags")
/// .args(&["flag", "color"])
/// .conflicts_with("debug"))
/// .get_matches_from_safe(vec!["myprog", "-c", "-d"]);
/// // because we used an arg from the group, and the group conflicts with "-d", it's an error
/// assert!(result.is_err());
/// let err = result.unwrap_err();
/// assert_eq!(err.kind, ErrorKind::ArgumentConflict);
2016-01-26 19:02:10 +00:00
/// ```
/// [argument exclusion rules]: ./struct.Arg.html#method.conflicts_with
pub fn conflicts_with(mut self, n: &'a str) -> Self {
if let Some(ref mut confs) = self.conflicts {
2015-09-04 18:05:13 +00:00
confs.push(n);
} else {
2015-09-04 18:05:13 +00:00
self.conflicts = Some(vec![n]);
}
self
}
/// Sets the exclusion rules of this group. Exclusion rules function just like
/// [argument exclusion rules], you can name other arguments or groups that must *not* be
/// present when one of the arguments from this group are used.
///
/// **NOTE:** The names provided may be an argument, or group name
///
/// # Examples
///
2016-01-26 19:02:10 +00:00
/// ```rust
/// # use clap::{App, Arg, ArgGroup, ErrorKind};
/// let result = App::new("myprog")
/// .arg(Arg::with_name("flag")
/// .short("f"))
/// .arg(Arg::with_name("color")
/// .short("c"))
/// .arg(Arg::with_name("debug")
/// .short("d"))
/// .arg(Arg::with_name("verb")
/// .short("v"))
/// .group(ArgGroup::with_name("req_flags")
/// .args(&["flag", "color"])
/// .conflicts_with_all(&["debug", "verb"]))
/// .get_matches_from_safe(vec!["myprog", "-c", "-v"]);
/// // because we used an arg from the group, and the group conflicts with either "-v" or "-d"
/// // it's an error
/// assert!(result.is_err());
/// let err = result.unwrap_err();
/// assert_eq!(err.kind, ErrorKind::ArgumentConflict);
2016-01-26 19:02:10 +00:00
/// ```
/// [argument exclusion rules]: ./struct.Arg.html#method.conflicts_with_all
pub fn conflicts_with_all(mut self, ns: &[&'a str]) -> Self {
for n in ns {
self = self.conflicts_with(n);
}
self
}
}
impl<'a> Debug for ArgGroup<'a> {
2015-10-28 14:23:59 +00:00
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f,
"{{\n\
\tname: {:?},\n\
\targs: {:?},\n\
\trequired: {:?},\n\
\trequires: {:?},\n\
\tconflicts: {:?},\n\
}}",
2015-10-28 14:23:59 +00:00
self.name,
self.args,
self.required,
self.requires,
self.conflicts)
}
}
2015-09-04 17:58:00 +00:00
impl<'a, 'z> From<&'z ArgGroup<'a>> for ArgGroup<'a> {
fn from(g: &'z ArgGroup<'a>) -> Self {
ArgGroup {
2016-02-14 06:10:44 +00:00
name: g.name,
required: g.required,
args: g.args.clone(),
requires: g.requires.clone(),
conflicts: g.conflicts.clone(),
multiple: g.multiple,
}
}
}
#[cfg(feature = "yaml")]
impl<'a> From<&'a BTreeMap<Yaml, Yaml>> for ArgGroup<'a> {
fn from(b: &'a BTreeMap<Yaml, Yaml>) -> Self {
// We WANT this to panic on error...so expect() is good.
let mut a = ArgGroup::default();
let group_settings = if b.len() == 1 {
let name_yml = b.keys().nth(0).expect("failed to get name");
Issues rollup (#637) * feat: adds App::with_defaults to automatically use crate_authors! and crate_version! macros One can now use ```rust let a = App::with_defaults("My Program"); // same as let a2 = App::new("My Program") .version(crate_version!()) .author(crate_authors!()); ``` Closes #600 * imp(YAML Errors): vastly improves error messages when using YAML When errors are made while developing, the panic error messages have been improved instead of relying on the default panic message which is extremely unhelpful. Closes #574 * imp(Completions): uses standard conventions for bash completion files, namely '{bin}.bash-completion' Closes #567 * imp(Help): automatically moves help text to the next line and wraps when term width is determined to be too small, or help text is too long Now `clap` will check if it should automatically place long help messages on the next line after the flag/option. This is determined by checking to see if the space taken by flag/option plus spaces and values doesn't leave enough room for the entirety of the help message, with the single exception of of if the flag/option/spaces/values is less than 25% of the width. Closes #597 * tests: updates help tests to new forced new line rules * fix(Groups): fixes some usage strings that contain both args in groups and ones that conflict with each other Args that conflict *and* are in a group will now only display in the group and not in the usage string itself. Closes #616 * chore: updates dep graph Closes #633 * chore: clippy run * style: changes debug header to match other Rust projects * chore: increase version
2016-08-28 03:42:31 +00:00
let name_str = name_yml.as_str().expect("failed to convert arg YAML name to str");
a.name = name_str;
2016-05-06 21:35:53 +00:00
b.get(name_yml)
2016-09-05 21:03:45 +00:00
.expect("failed to get name_str")
.as_hash()
.expect("failed to convert to a hash")
} else {
b
};
2017-06-09 14:50:25 +00:00
for (k, v) in group_settings {
a = match k.as_str().unwrap() {
"required" => a.required(v.as_bool().unwrap()),
"multiple" => a.multiple(v.as_bool().unwrap()),
2016-09-05 21:03:45 +00:00
"args" => yaml_vec_or_str!(v, a, arg),
"arg" => {
if let Some(ys) = v.as_str() {
a = a.arg(ys);
}
a
}
2016-09-05 21:03:45 +00:00
"requires" => yaml_vec_or_str!(v, a, requires),
"conflicts_with" => yaml_vec_or_str!(v, a, conflicts_with),
"name" => {
if let Some(ys) = v.as_str() {
a.name = ys;
}
a
}
2016-05-06 21:35:53 +00:00
s => {
panic!("Unknown ArgGroup setting '{}' in YAML file for \
ArgGroup '{}'",
2016-05-06 21:35:53 +00:00
s,
a.name)
}
}
}
a
}
}
2015-09-04 17:58:00 +00:00
#[cfg(test)]
mod test {
use super::ArgGroup;
#[cfg(feature = "yaml")]
use yaml_rust::YamlLoader;
2015-09-04 17:58:00 +00:00
#[test]
fn groups() {
let g = ArgGroup::with_name("test")
2016-09-05 21:03:45 +00:00
.arg("a1")
.arg("a4")
.args(&["a2", "a3"])
.required(true)
.conflicts_with("c1")
.conflicts_with_all(&["c2", "c3"])
.conflicts_with("c4")
.requires("r1")
.requires_all(&["r2", "r3"])
.requires("r4");
2015-09-04 17:58:00 +00:00
let args = vec!["a1", "a4", "a2", "a3"];
2015-09-07 01:07:46 +00:00
let reqs = vec!["r1", "r2", "r3", "r4"];
2015-09-04 18:05:13 +00:00
let confs = vec!["c1", "c2", "c3", "c4"];
2015-09-04 17:58:00 +00:00
assert_eq!(g.args, args);
assert_eq!(g.requires, Some(reqs));
assert_eq!(g.conflicts, Some(confs));
}
#[test]
fn test_debug() {
let g = ArgGroup::with_name("test")
2016-09-05 21:03:45 +00:00
.arg("a1")
.arg("a4")
.args(&["a2", "a3"])
.required(true)
.conflicts_with("c1")
.conflicts_with_all(&["c2", "c3"])
.conflicts_with("c4")
.requires("r1")
.requires_all(&["r2", "r3"])
.requires("r4");
let args = vec!["a1", "a4", "a2", "a3"];
let reqs = vec!["r1", "r2", "r3", "r4"];
let confs = vec!["c1", "c2", "c3", "c4"];
2016-05-06 21:35:53 +00:00
let debug_str = format!("{{\n\
\tname: \"test\",\n\
\targs: {:?},\n\
\trequired: {:?},\n\
\trequires: {:?},\n\
\tconflicts: {:?},\n\
2016-05-06 21:35:53 +00:00
}}",
args,
true,
Some(reqs),
Some(confs));
assert_eq!(&*format!("{:?}", g), &*debug_str);
}
2015-09-04 17:58:00 +00:00
#[test]
fn test_from() {
let g = ArgGroup::with_name("test")
2016-09-05 21:03:45 +00:00
.arg("a1")
.arg("a4")
.args(&["a2", "a3"])
.required(true)
.conflicts_with("c1")
.conflicts_with_all(&["c2", "c3"])
.conflicts_with("c4")
.requires("r1")
.requires_all(&["r2", "r3"])
.requires("r4");
let args = vec!["a1", "a4", "a2", "a3"];
let reqs = vec!["r1", "r2", "r3", "r4"];
let confs = vec!["c1", "c2", "c3", "c4"];
let g2 = ArgGroup::from(&g);
assert_eq!(g2.args, args);
assert_eq!(g2.requires, Some(reqs));
assert_eq!(g2.conflicts, Some(confs));
}
#[cfg(feature="yaml")]
#[cfg_attr(feature = "yaml", test)]
fn test_yaml() {
2016-05-06 21:35:53 +00:00
let g_yaml = "name: test
args:
- a1
- a4
- a2
- a3
conflicts_with:
- c1
- c2
- c3
- c4
requires:
- r1
- r2
- r3
- r4";
let yml = &YamlLoader::load_from_str(g_yaml).expect("failed to load YAML file")[0];
let g = ArgGroup::from_yaml(yml);
let args = vec!["a1", "a4", "a2", "a3"];
let reqs = vec!["r1", "r2", "r3", "r4"];
let confs = vec!["c1", "c2", "c3", "c4"];
assert_eq!(g.args, args);
assert_eq!(g.requires, Some(reqs));
assert_eq!(g.conflicts, Some(confs));
2015-09-04 17:58:00 +00:00
}
2015-09-07 01:07:46 +00:00
}
impl<'a> Clone for ArgGroup<'a> {
fn clone(&self) -> Self {
ArgGroup {
name: self.name,
required: self.required,
args: self.args.clone(),
requires: self.requires.clone(),
conflicts: self.conflicts.clone(),
multiple: self.multiple,
}
}
}