clap/src/args/group.rs

347 lines
11 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 say, "Any of these arguments".
/// By placing arguments in a logical group, you can make easier requirement and exclusion rules
2015-11-01 14:02:37 +00:00
/// instead of having to list each individually, or when you want a rule to apply "any but not all"
2015-05-01 18:44:20 +00:00
/// arguments.
///
/// For instance, you can make an entire ArgGroup required, this means that one (and *only* one)
/// argument. from that group must be present. Using more than one argument from an ArgGroup causes
/// a failure (graceful exit).
2015-05-01 18:44:20 +00:00
///
/// You can also do things such as name an ArgGroup as a confliction or requirement, 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.
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, ArgGroup};
/// let _ = 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(&["ver", "major", "minor","patch"])
/// .required(true))
/// # .get_matches();
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>>,
}
impl<'a> ArgGroup<'a> {
2015-11-01 14:02:37 +00:00
/// Creates a new instance of `ArgGroup` using a unique string name.
/// The name will only be used by the library consumer and not displayed to the use.
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, ArgGroup};
/// # let matches = App::new("myprog")
/// # .group(
2015-11-01 14:02:37 +00:00
/// ArgGroup::with_name("config")
/// # ).get_matches();
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,
}
}
2015-11-01 14:02:37 +00:00
/// Creates a new instance of `ArgGroup` from a .yml (YAML) file.
///
/// # Examples
///
/// ```ignore
/// # use clap::ArgGroup;
/// let yml = load_yaml!("group.yml");
/// let ag = ArgGroup::from_yaml(yml);
/// ```
#[cfg(feature = "yaml")]
pub fn from_yaml<'y>(y: &'y BTreeMap<Yaml, Yaml>) -> ArgGroup<'y> {
// We WANT this to panic on error...so expect() is good.
let name_yml = y.keys().nth(0).unwrap();
let name_str = name_yml.as_str().unwrap();
let mut a = ArgGroup::with_name(name_str);
let group_settings = y.get(name_yml).unwrap().as_hash().unwrap();
for (k, v) in group_settings.iter() {
a = match k.as_str().unwrap() {
2016-01-25 23:52:55 +00:00
"required" => a.required(v.as_bool().unwrap()),
2015-09-07 01:07:46 +00:00
"args" => {
for ys in v.as_vec().unwrap() {
if let Some(s) = ys.as_str() {
a = a.arg(s);
}
}
a
2015-09-07 01:07:46 +00:00
}
"requires" => {
for ys in v.as_vec().unwrap() {
if let Some(s) = ys.as_str() {
a = a.requires(s);
}
}
a
2015-09-07 01:07:46 +00:00
}
"conflicts_with" => {
for ys in v.as_vec().unwrap() {
if let Some(s) = ys.as_str() {
a = a.conflicts_with(s);
}
}
a
2015-09-07 01:07:46 +00:00
}
s => panic!("Unknown ArgGroup setting '{}' in YAML file for \
2015-10-28 14:23:59 +00:00
ArgGroup '{}'",
s,
name_str),
}
}
a
}
/// Adds an argument to this group by name
///
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, ArgGroup};
/// # let matches = App::new("myprog")
/// # .group(
2015-11-01 14:02:37 +00:00
/// # ArgGroup::with_name("config")
/// .arg("config")
/// # ).get_matches();
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
///
/// ```no_run
/// # use clap::{App, ArgGroup};
/// # let matches = App::new("myprog")
/// # .group(
2015-11-01 14:02:37 +00:00
/// # ArgGroup::with_name("config")
/// .args(&["config", "input", "output"])
/// # ).get_matches();
pub fn args(mut self, ns: &[&'a str]) -> Self {
for n in ns {
self = self.arg(n);
}
self
}
/// Sets the requirement of this group. 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, and only one argument from this group *must* be present at runtime (unless
/// conflicting with another argument).
///
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, ArgGroup};
/// # let matches = App::new("myprog")
/// # .group(
2015-11-01 14:02:37 +00:00
/// # ArgGroup::with_name("config")
/// .required(true)
/// # ).get_matches();
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 one of the arguments from this group is used.
///
/// **NOTE:** The name provided may be an argument, or group name
///
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, ArgGroup};
/// # let matches = App::new("myprog")
/// # .group(
2015-11-01 14:02:37 +00:00
/// # ArgGroup::with_name("config")
/// .requires("config")
/// # ).get_matches();
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
///
/// ```no_run
/// # use clap::{App, ArgGroup};
/// # let matches = App::new("myprog")
/// # .group(
2015-11-01 14:02:37 +00:00
/// # ArgGroup::with_name("config")
/// .requires_all(&["config", "input"])
/// # ).get_matches();
pub fn requires_all(mut self, ns: &[&'a str]) -> Self {
for n in ns {
self = self.requires(n);
}
self
}
2015-05-01 18:44:20 +00:00
/// 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 name provided may be an argument, or group name
///
///
/// # Examples
///
/// ```no_run
/// # use clap::{App, ArgGroup};
/// # let matches = App::new("myprog")
/// # .group(
2015-11-01 14:02:37 +00:00
/// # ArgGroup::with_name("config")
/// .conflicts_with("config")
/// # ).get_matches();
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
///
/// ```no_run
/// # use clap::{App, ArgGroup};
/// # let matches = App::new("myprog")
/// # .group(
2015-11-01 14:02:37 +00:00
/// # ArgGroup::with_name("config")
/// .conflicts_with_all(&["config", "input"])
/// # ).get_matches();
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,
"{{
name:{:?},
args: {:?},
required: {:?},
requires: {:?},
conflicts: {:?},
}}",
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 {
name: g.name.clone(),
required: g.required,
args: g.args.clone(),
requires: g.requires.clone(),
conflicts: g.conflicts.clone(),
}
}
}
2015-09-04 17:58:00 +00:00
#[cfg(test)]
mod test {
use super::ArgGroup;
#[test]
fn groups() {
let g = ArgGroup::with_name("test")
.arg("a1")
.arg("a4")
.args(&["a2", "a3"])
2015-10-28 14:23:59 +00:00
.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.unwrap(), reqs);
assert_eq!(g.conflicts.unwrap(), confs);
}
2015-09-07 01:07:46 +00:00
}