From 6b6b6035ed960b7ddf7e14952cc77a9c23b47187 Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Sun, 31 May 2020 04:39:24 +0300 Subject: [PATCH 1/9] Arg::required_unless_one => required_unless_eq_any --- src/build/arg/mod.rs | 18 +++++++++--------- tests/require.rs | 34 +++++++++++++++++----------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index a6e5759f..1f16aa85 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -689,7 +689,7 @@ impl<'help> Arg<'help> { /// all these other arguments are present). /// /// **NOTE:** If you wish for this argument to only be required if *one of* these args are - /// present see [`Arg::required_unless_one`] + /// present see [`Arg::required_unless_eq_any`] /// /// # Examples /// @@ -746,7 +746,7 @@ impl<'help> Arg<'help> { /// assert!(res.is_err()); /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); /// ``` - /// [`Arg::required_unless_one`]: ./struct.Arg.html#method.required_unless_one + /// [`Arg::required_unless_eq_any`]: ./struct.Arg.html#method.required_unless_eq_any /// [`Arg::required_unless_all(names)`]: ./struct.Arg.html#method.required_unless_all pub fn required_unless_all(mut self, names: &[&str]) -> Self { self.r_unless.extend(names.iter().map(Id::from)); @@ -768,7 +768,7 @@ impl<'help> Arg<'help> { /// # ; /// ``` /// - /// Setting [`Arg::required_unless_one(names)`] requires that the argument be used at runtime + /// Setting [`Arg::required_unless_eq_any(names)`] requires that the argument be used at runtime /// *unless* *at least one of* the args in `names` are present. In the following example, the /// required argument is *not* provided, but it's not an error because one the `unless` args /// have been supplied. @@ -777,7 +777,7 @@ impl<'help> Arg<'help> { /// # use clap::{App, Arg}; /// let res = App::new("prog") /// .arg(Arg::new("cfg") - /// .required_unless_one(&["dbg", "infile"]) + /// .required_unless_eq_any(&["dbg", "infile"]) /// .takes_value(true) /// .long("config")) /// .arg(Arg::new("dbg") @@ -792,14 +792,14 @@ impl<'help> Arg<'help> { /// assert!(res.is_ok()); /// ``` /// - /// Setting [`Arg::required_unless_one(names)`] and *not* supplying *at least one of* `names` + /// Setting [`Arg::required_unless_eq_any(names)`] and *not* supplying *at least one of* `names` /// or this arg is an error. /// /// ```rust /// # use clap::{App, Arg, ErrorKind}; /// let res = App::new("prog") /// .arg(Arg::new("cfg") - /// .required_unless_one(&["dbg", "infile"]) + /// .required_unless_eq_any(&["dbg", "infile"]) /// .takes_value(true) /// .long("config")) /// .arg(Arg::new("dbg") @@ -815,9 +815,9 @@ impl<'help> Arg<'help> { /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); /// ``` /// [required]: ./struct.Arg.html#method.required - /// [`Arg::required_unless_one(names)`]: ./struct.Arg.html#method.required_unless_one + /// [`Arg::required_unless_eq_any(names)`]: ./struct.Arg.html#method.required_unless_eq_any /// [`Arg::required_unless_all`]: ./struct.Arg.html#method.required_unless_all - pub fn required_unless_one(mut self, names: &[&str]) -> Self { + pub fn required_unless_eq_any(mut self, names: &[&str]) -> Self { self.r_unless.extend(names.iter().map(Id::from)); self } @@ -4323,7 +4323,7 @@ impl<'help> From<&'help Yaml> for Arg<'help> { "overrides_with" => yaml_vec_or_str!(v, a, overrides_with), "possible_values" => yaml_vec_or_str!(v, a, possible_value), "case_insensitive" => yaml_to_bool!(a, v, case_insensitive), - "required_unless_one" => yaml_vec_or_str!(v, a, required_unless), + "required_unless_eq_any" => yaml_vec_or_str!(v, a, required_unless), "required_unless_all" => { a = yaml_vec_or_str!(v, a, required_unless); a.set_mut(ArgSettings::RequiredUnlessAll); diff --git a/tests/require.rs b/tests/require.rs index df9871b2..7b3b0a1b 100644 --- a/tests/require.rs +++ b/tests/require.rs @@ -288,11 +288,11 @@ fn required_unless_all_err() { // REQUIRED_UNLESS_ONE #[test] -fn required_unless_one() { +fn required_unless_eq_any() { let res = App::new("unlessone") .arg( Arg::new("cfg") - .required_unless_one(&["dbg", "infile"]) + .required_unless_eq_any(&["dbg", "infile"]) .takes_value(true) .long("config"), ) @@ -307,13 +307,13 @@ fn required_unless_one() { } #[test] -fn required_unless_one_2() { - // This tests that the required_unless_one works when the second arg in the array is used +fn required_unless_any_2() { + // This tests that the required_unless_eq_any works when the second arg in the array is used // instead of the first. let res = App::new("unlessone") .arg( Arg::new("cfg") - .required_unless_one(&["dbg", "infile"]) + .required_unless_eq_any(&["dbg", "infile"]) .takes_value(true) .long("config"), ) @@ -328,48 +328,48 @@ fn required_unless_one_2() { } #[test] -fn required_unless_one_works_with_short() { +fn required_unless_any_works_with_short() { // GitHub issue: https://github.com/kbknapp/clap-rs/issues/1135 let res = App::new("unlessone") .arg(Arg::new("a").conflicts_with("b").short('a')) .arg(Arg::new("b").short('b')) - .arg(Arg::new("x").short('x').required_unless_one(&["a", "b"])) + .arg(Arg::new("x").short('x').required_unless_eq_any(&["a", "b"])) .try_get_matches_from(vec!["unlessone", "-a"]); assert!(res.is_ok()); } #[test] -fn required_unless_one_works_with_short_err() { +fn required_unless_any_works_with_short_err() { let res = App::new("unlessone") .arg(Arg::new("a").conflicts_with("b").short('a')) .arg(Arg::new("b").short('b')) - .arg(Arg::new("x").short('x').required_unless_one(&["a", "b"])) + .arg(Arg::new("x").short('x').required_unless_eq_any(&["a", "b"])) .try_get_matches_from(vec!["unlessone"]); assert!(!res.is_ok()); } #[test] -fn required_unless_one_works_without() { +fn required_unless_any_works_without() { let res = App::new("unlessone") .arg(Arg::new("a").conflicts_with("b").short('a')) .arg(Arg::new("b").short('b')) - .arg(Arg::new("x").required_unless_one(&["a", "b"])) + .arg(Arg::new("x").required_unless_eq_any(&["a", "b"])) .try_get_matches_from(vec!["unlessone", "-a"]); assert!(res.is_ok()); } #[test] -fn required_unless_one_works_with_long() { +fn required_unless_any_works_with_long() { let res = App::new("unlessone") .arg(Arg::new("a").conflicts_with("b").short('a')) .arg(Arg::new("b").short('b')) .arg( Arg::new("x") .long("x_is_the_option") - .required_unless_one(&["a", "b"]), + .required_unless_eq_any(&["a", "b"]), ) .try_get_matches_from(vec!["unlessone", "-a"]); @@ -377,11 +377,11 @@ fn required_unless_one_works_with_long() { } #[test] -fn required_unless_one_1() { +fn required_unless_any_1() { let res = App::new("unlessone") .arg( Arg::new("cfg") - .required_unless_one(&["dbg", "infile"]) + .required_unless_eq_any(&["dbg", "infile"]) .takes_value(true) .long("config"), ) @@ -397,11 +397,11 @@ fn required_unless_one_1() { } #[test] -fn required_unless_one_err() { +fn required_unless_any_err() { let res = App::new("unlessone") .arg( Arg::new("cfg") - .required_unless_one(&["dbg", "infile"]) + .required_unless_eq_any(&["dbg", "infile"]) .takes_value(true) .long("config"), ) From 8b85c4eceac5751cb4f0ce2c92c39ec1d8b72f06 Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Sat, 23 May 2020 16:02:19 +0300 Subject: [PATCH 2/9] Arg::required_ifs => required_if_eq_any --- src/build/arg/mod.rs | 14 +++++++------- tests/require.rs | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index 1f16aa85..424b1d9f 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -1371,14 +1371,14 @@ impl<'help> Arg<'help> { /// ```rust /// # use clap::Arg; /// Arg::new("config") - /// .required_ifs(&[ + /// .required_if_eq_any(&[ /// ("extra", "val"), /// ("option", "spec") /// ]) /// # ; /// ``` /// - /// Setting [`Arg::required_ifs(&[(arg, val)])`] makes this arg required if any of the `arg`s + /// Setting [`Arg::required_if_eq_any(&[(arg, val)])`] makes this arg required if any of the `arg`s /// are used at runtime and it's corresponding value is equal to `val`. If the `arg`'s value is /// anything other than `val`, this argument isn't required. /// @@ -1386,7 +1386,7 @@ impl<'help> Arg<'help> { /// # use clap::{App, Arg}; /// let res = App::new("prog") /// .arg(Arg::new("cfg") - /// .required_ifs(&[ + /// .required_if_eq_any(&[ /// ("extra", "val"), /// ("option", "spec") /// ]) @@ -1405,14 +1405,14 @@ impl<'help> Arg<'help> { /// assert!(res.is_ok()); // We didn't use --option=spec, or --extra=val so "cfg" isn't required /// ``` /// - /// Setting [`Arg::required_ifs(&[(arg, val)])`] and having any of the `arg`s used with its + /// Setting [`Arg::required_if_eq_any(&[(arg, val)])`] and having any of the `arg`s used with it's /// value of `val` but *not* using this arg is an error. /// /// ```rust /// # use clap::{App, Arg, ErrorKind}; /// let res = App::new("prog") /// .arg(Arg::new("cfg") - /// .required_ifs(&[ + /// .required_if_eq_any(&[ /// ("extra", "val"), /// ("option", "spec") /// ]) @@ -1434,7 +1434,7 @@ impl<'help> Arg<'help> { /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires /// [Conflicting]: ./struct.Arg.html#method.conflicts_with /// [required]: ./struct.Arg.html#method.required - pub fn required_ifs(mut self, ifs: &[(T, &'help str)]) -> Self { + pub fn required_if_eq_any(mut self, ifs: &[(T, &'help str)]) -> Self { self.r_ifs .extend(ifs.iter().map(|(id, val)| (Id::from_ref(id), *val))); self @@ -4287,7 +4287,7 @@ impl<'help> From<&'help Yaml> for Arg<'help> { "long_help" => yaml_to_str!(a, v, long_about), "required" => yaml_to_bool!(a, v, required), "required_if" => yaml_tuple2!(a, v, required_if), - "required_ifs" => yaml_tuple2!(a, v, required_if), + "required_if_eq_any" => yaml_tuple2!(a, v, required_if), "takes_value" => yaml_to_bool!(a, v, takes_value), "index" => yaml_to_u64!(a, v, index), "global" => yaml_to_bool!(a, v, global), diff --git a/tests/require.rs b/tests/require.rs index 7b3b0a1b..95ce6080 100644 --- a/tests/require.rs +++ b/tests/require.rs @@ -610,7 +610,7 @@ fn required_ifs_val_present_pass() { let res = App::new("ri") .arg( Arg::new("cfg") - .required_ifs(&[("extra", "val"), ("option", "spec")]) + .required_if_eq_any(&[("extra", "val"), ("option", "spec")]) .takes_value(true) .long("config"), ) @@ -626,7 +626,7 @@ fn required_ifs_val_present_fail() { let res = App::new("ri") .arg( Arg::new("cfg") - .required_ifs(&[("extra", "val"), ("option", "spec")]) + .required_if_eq_any(&[("extra", "val"), ("option", "spec")]) .takes_value(true) .long("config"), ) @@ -643,7 +643,7 @@ fn required_ifs_wrong_val() { let res = App::new("ri") .arg( Arg::new("cfg") - .required_ifs(&[("extra", "val"), ("option", "spec")]) + .required_if_eq_any(&[("extra", "val"), ("option", "spec")]) .takes_value(true) .long("config"), ) @@ -659,7 +659,7 @@ fn required_ifs_wrong_val_mult_fail() { let res = App::new("ri") .arg( Arg::new("cfg") - .required_ifs(&[("extra", "val"), ("option", "spec")]) + .required_if_eq_any(&[("extra", "val"), ("option", "spec")]) .takes_value(true) .long("config"), ) From 233af6e7a1343a89f0515645a51991bfbff21f24 Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Sat, 23 May 2020 17:02:03 +0300 Subject: [PATCH 3/9] Arg::required_if => required_if_eq --- src/build/arg/mod.rs | 20 ++++++++++---------- tests/default_vals.rs | 4 ++-- tests/fixtures/app.yaml | 4 ++-- tests/require.rs | 12 ++++++------ 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index 424b1d9f..4a8619ce 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -1292,7 +1292,7 @@ impl<'help> Arg<'help> { /// **NOTE:** If using YAML the values should be laid out as follows /// /// ```yaml - /// required_if: + /// required_if_eq: /// - [arg, val] /// ``` /// @@ -1301,11 +1301,11 @@ impl<'help> Arg<'help> { /// ```rust /// # use clap::Arg; /// Arg::new("config") - /// .required_if("other_arg", "value") + /// .required_if_eq("other_arg", "value") /// # ; /// ``` /// - /// Setting [`Arg::required_if(arg, val)`] makes this arg required if the `arg` is used at + /// Setting [`Arg::required_if_eq(arg, val)`] makes this arg required if the `arg` is used at /// runtime and it's value is equal to `val`. If the `arg`'s value is anything other than `val`, /// this argument isn't required. /// @@ -1314,7 +1314,7 @@ impl<'help> Arg<'help> { /// let res = App::new("prog") /// .arg(Arg::new("cfg") /// .takes_value(true) - /// .required_if("other", "special") + /// .required_if_eq("other", "special") /// .long("config")) /// .arg(Arg::new("other") /// .long("other") @@ -1326,7 +1326,7 @@ impl<'help> Arg<'help> { /// assert!(res.is_ok()); // We didn't use --other=special, so "cfg" wasn't required /// ``` /// - /// Setting [`Arg::required_if(arg, val)`] and having `arg` used with a value of `val` but *not* + /// Setting [`Arg::required_if_eq(arg, val)`] and having `arg` used with a value of `val` but *not* /// using this arg is an error. /// /// ```rust @@ -1334,7 +1334,7 @@ impl<'help> Arg<'help> { /// let res = App::new("prog") /// .arg(Arg::new("cfg") /// .takes_value(true) - /// .required_if("other", "special") + /// .required_if_eq("other", "special") /// .long("config")) /// .arg(Arg::new("other") /// .long("other") @@ -1349,7 +1349,7 @@ impl<'help> Arg<'help> { /// [`Arg::requires(name)`]: ./struct.Arg.html#method.requires /// [Conflicting]: ./struct.Arg.html#method.conflicts_with /// [required]: ./struct.Arg.html#method.required - pub fn required_if(mut self, arg_id: T, val: &'help str) -> Self { + pub fn required_if_eq(mut self, arg_id: T, val: &'help str) -> Self { self.r_ifs.push((arg_id.into(), val)); self } @@ -1361,7 +1361,7 @@ impl<'help> Arg<'help> { /// **NOTE:** If using YAML the values should be laid out as follows /// /// ```yaml - /// required_if: + /// required_if_eq: /// - [arg, val] /// - [arg2, val2] /// ``` @@ -4286,8 +4286,8 @@ impl<'help> From<&'help Yaml> for Arg<'help> { "help" => yaml_to_str!(a, v, about), "long_help" => yaml_to_str!(a, v, long_about), "required" => yaml_to_bool!(a, v, required), - "required_if" => yaml_tuple2!(a, v, required_if), - "required_if_eq_any" => yaml_tuple2!(a, v, required_if), + "required_if_eq" => yaml_tuple2!(a, v, required_if_eq), + "required_if_eq_any" => yaml_tuple2!(a, v, required_if_eq), "takes_value" => yaml_to_bool!(a, v, takes_value), "index" => yaml_to_u64!(a, v, index), "global" => yaml_to_bool!(a, v, global), diff --git a/tests/default_vals.rs b/tests/default_vals.rs index 75abf60c..3c1866d0 100644 --- a/tests/default_vals.rs +++ b/tests/default_vals.rs @@ -400,7 +400,7 @@ fn conditional_reqs_fail() { .arg( Arg::new("output") .takes_value(true) - .required_if("target", "file") + .required_if_eq("target", "file") .long("output"), ) .try_get_matches_from(vec!["test", "--input", "some"]); @@ -431,7 +431,7 @@ fn conditional_reqs_pass() { .arg( Arg::new("output") .takes_value(true) - .required_if("target", "file") + .required_if_eq("target", "file") .long("output"), ) .try_get_matches_from(vec!["test", "--input", "some", "--output", "other"]); diff --git a/tests/fixtures/app.yaml b/tests/fixtures/app.yaml index b8f2988e..71c386b0 100644 --- a/tests/fixtures/app.yaml +++ b/tests/fixtures/app.yaml @@ -77,7 +77,7 @@ args: long: singlealias about: Tests single alias aliases: [alias] - required_if: + required_if_eq: - [multvalsmo, two] - multaliases: long: multaliases @@ -87,7 +87,7 @@ args: long: singleshortalias about: Tests single short alias short_aliases: [a] - required_if: + required_if_eq: - [multvalsmo, two] - multshortaliases: long: multshortaliases diff --git a/tests/require.rs b/tests/require.rs index 95ce6080..0d05b114 100644 --- a/tests/require.rs +++ b/tests/require.rs @@ -496,7 +496,7 @@ fn required_if_val_present_pass() { let res = App::new("ri") .arg( Arg::new("cfg") - .required_if("extra", "val") + .required_if_eq("extra", "val") .takes_value(true) .long("config"), ) @@ -511,7 +511,7 @@ fn required_if_val_present_fail() { let res = App::new("ri") .arg( Arg::new("cfg") - .required_if("extra", "val") + .required_if_eq("extra", "val") .takes_value(true) .long("config"), ) @@ -578,7 +578,7 @@ fn required_if_val_present_fail_error_output() { .arg( Arg::new("output") .takes_value(true) - .required_if("target", "file") + .required_if_eq("target", "file") .long("output"), ); @@ -595,7 +595,7 @@ fn required_if_wrong_val() { let res = App::new("ri") .arg( Arg::new("cfg") - .required_if("extra", "val") + .required_if_eq("extra", "val") .takes_value(true) .long("config"), ) @@ -858,12 +858,12 @@ fn requires_if_invalid_arg() { #[cfg(debug_assertions)] #[test] -#[should_panic = "Argument or group 'extra' specified in 'required_if*' for 'config' does not exist"] +#[should_panic = "Argument or group 'extra' specified in 'required_if_eq*' for 'config' does not exist"] fn required_if_invalid_arg() { let _ = App::new("prog") .arg( Arg::new("config") - .required_if("extra", "val") + .required_if_eq("extra", "val") .long("config"), ) .try_get_matches_from(vec!["", "--config"]); From 55dceca819f30b840901c5a9d478e465ffc29299 Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Sun, 31 May 2020 03:20:17 +0300 Subject: [PATCH 4/9] Improve documentation --- src/build/arg/mod.rs | 68 +++++++++++++++++++------------------------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index 4a8619ce..75fa48eb 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -624,10 +624,9 @@ impl<'help> Arg<'help> { self } - /// Sets an arg that override this arg's required setting. (i.e. this arg will be required - /// unless this other argument is present). + /// Set this arg as [required] as long as the specified argument is not present at runtime. /// - /// **Pro Tip:** Using [`Arg::required_unless`] implies [`Arg::required`] and is therefore not + /// **Pro Tip:** Using `Arg::required_unless` implies [`Arg::required`] and is therefore not /// mandatory to also set. /// /// # Examples @@ -639,9 +638,8 @@ impl<'help> Arg<'help> { /// # ; /// ``` /// - /// Setting [`Arg::required_unless(name)`] requires that the argument be used at runtime - /// *unless* `name` is present. In the following example, the required argument is *not* - /// provided, but it's not an error because the `unless` arg has been supplied. + /// In the following example, the required argument is *not* provided, + /// but it's not an error because the `unless` arg has been supplied. /// /// ```rust /// # use clap::{App, Arg}; @@ -659,7 +657,7 @@ impl<'help> Arg<'help> { /// assert!(res.is_ok()); /// ``` /// - /// Setting [`Arg::required_unless(name)`] and *not* supplying `name` or this arg is an error. + /// Setting `Arg::required_unless(name)` and *not* supplying `name` or this arg is an error. /// /// ```rust /// # use clap::{App, Arg, ErrorKind}; @@ -677,16 +675,17 @@ impl<'help> Arg<'help> { /// assert!(res.is_err()); /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); /// ``` - /// [`Arg::required_unless`]: ./struct.Arg.html#method.required_unless - /// [`Arg::required`]: ./struct.Arg.html#method.required - /// [`Arg::required_unless(name)`]: ./struct.Arg.html#method.required_unless + /// [required]: ./struct.Arg.html#method.required pub fn required_unless(mut self, arg_id: T) -> Self { self.r_unless.push(arg_id.into()); self } - /// Sets args that override this arg's required setting. (i.e. this arg will be required unless - /// all these other arguments are present). + /// Sets this arg as [required] unless *all* of the specified arguments are present at runtime. + /// + /// In other words, parsing will succeed only if user either + /// * supplies the `self` arg. + /// * supplies *all* of the `names` arguments. /// /// **NOTE:** If you wish for this argument to only be required if *one of* these args are /// present see [`Arg::required_unless_eq_any`] @@ -700,10 +699,8 @@ impl<'help> Arg<'help> { /// # ; /// ``` /// - /// Setting [`Arg::required_unless_all(names)`] requires that the argument be used at runtime - /// *unless* *all* the args in `names` are present. In the following example, the required - /// argument is *not* provided, but it's not an error because all the `unless` args have been - /// supplied. + /// In the following example, the required argument is *not* provided, but it's not an error + /// because *all* of the `names` args have been supplied. /// /// ```rust /// # use clap::{App, Arg}; @@ -724,8 +721,8 @@ impl<'help> Arg<'help> { /// assert!(res.is_ok()); /// ``` /// - /// Setting [`Arg::required_unless_all(names)`] and *not* supplying *all* of `names` or this - /// arg is an error. + /// Setting [`Arg::required_unless_all(names)`] and *not* supplying + /// either *all* of `unless` args or the `self` arg is an error. /// /// ```rust /// # use clap::{App, Arg, ErrorKind}; @@ -753,11 +750,11 @@ impl<'help> Arg<'help> { self.setting(ArgSettings::RequiredUnlessAll) } - /// Sets args that override this arg's [required] setting. (i.e. this arg will be required - /// unless *at least one of* these other arguments are present). + /// Sets this arg as [required] unless *any* of the specified arguments are present at runtime. /// - /// **NOTE:** If you wish for this argument to only be required if *all of* these args are - /// present see [`Arg::required_unless_all`] + /// In other words, parsing will succeed only if user either + /// * supplies the `self` arg. + /// * supplies *one or more* of the `unless` arguments. /// /// # Examples /// @@ -866,7 +863,6 @@ impl<'help> Arg<'help> { /// /// [`Arg::conflicts_with_all(names)`]: ./struct.Arg.html#method.conflicts_with_all /// [`Arg::exclusive(true)`]: ./struct.Arg.html#method.exclusive - pub fn conflicts_with(mut self, arg_id: T) -> Self { self.blacklist.push(arg_id.into()); self @@ -1165,8 +1161,11 @@ impl<'help> Arg<'help> { self } - /// Allows a conditional requirement. The requirement will only become valid if this arg's value - /// equals `val`. + /// Require another argument if this arg was present on runtime, and its value equals to `val`. + /// + /// This method takes `value, another_arg` pair. At runtime, clap will check + /// if this arg (`self`) is is present and its value equals to `val`. + /// If it does, `another_arg` will be marked as required. /// /// **NOTE:** If using YAML the values should be laid out as follows /// @@ -1286,8 +1285,8 @@ impl<'help> Arg<'help> { self } - /// Allows specifying that an argument is [required] conditionally. The requirement will only - /// become valid if the specified `arg`'s value equals `val`. + /// Allows specifying that this argument is [required] only if the specified + /// `arg` is present at runtime and its value equals `val`. /// /// **NOTE:** If using YAML the values should be laid out as follows /// @@ -1305,12 +1304,8 @@ impl<'help> Arg<'help> { /// # ; /// ``` /// - /// Setting [`Arg::required_if_eq(arg, val)`] makes this arg required if the `arg` is used at - /// runtime and it's value is equal to `val`. If the `arg`'s value is anything other than `val`, - /// this argument isn't required. - /// /// ```rust - /// # use clap::{App, Arg}; + /// # use clap::{App, Arg, ErrorKind}; /// let res = App::new("prog") /// .arg(Arg::new("cfg") /// .takes_value(true) @@ -1324,13 +1319,7 @@ impl<'help> Arg<'help> { /// ]); /// /// assert!(res.is_ok()); // We didn't use --other=special, so "cfg" wasn't required - /// ``` /// - /// Setting [`Arg::required_if_eq(arg, val)`] and having `arg` used with a value of `val` but *not* - /// using this arg is an error. - /// - /// ```rust - /// # use clap::{App, Arg, ErrorKind}; /// let res = App::new("prog") /// .arg(Arg::new("cfg") /// .takes_value(true) @@ -1343,6 +1332,7 @@ impl<'help> Arg<'help> { /// "prog", "--other", "special" /// ]); /// + /// // We did use --other=special so "cfg" had become required but was missing. /// assert!(res.is_err()); /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); /// ``` @@ -1354,7 +1344,7 @@ impl<'help> Arg<'help> { self } - /// Allows specifying that an argument is [required] based on multiple conditions. The + /// Allows specifying that this argument is [required] based on multiple conditions. The /// conditions are set up in a `(arg, val)` style tuple. The requirement will only become valid /// if one of the specified `arg`'s value equals it's corresponding `val`. /// From b12102c8325c2dd706ebe6164d27a5ffeead63c7 Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Sun, 31 May 2020 04:50:53 +0300 Subject: [PATCH 5/9] Arg::required_unless -> required_unless_present --- src/build/arg/mod.rs | 16 ++++++++-------- tests/require.rs | 25 ++++++++++++++++--------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index 75fa48eb..bfdad780 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -626,7 +626,7 @@ impl<'help> Arg<'help> { /// Set this arg as [required] as long as the specified argument is not present at runtime. /// - /// **Pro Tip:** Using `Arg::required_unless` implies [`Arg::required`] and is therefore not + /// **Pro Tip:** Using `Arg::required_unless_present` implies [`Arg::required`] and is therefore not /// mandatory to also set. /// /// # Examples @@ -634,7 +634,7 @@ impl<'help> Arg<'help> { /// ```rust /// # use clap::Arg; /// Arg::new("config") - /// .required_unless("debug") + /// .required_unless_present("debug") /// # ; /// ``` /// @@ -645,7 +645,7 @@ impl<'help> Arg<'help> { /// # use clap::{App, Arg}; /// let res = App::new("prog") /// .arg(Arg::new("cfg") - /// .required_unless("dbg") + /// .required_unless_present("dbg") /// .takes_value(true) /// .long("config")) /// .arg(Arg::new("dbg") @@ -657,13 +657,13 @@ impl<'help> Arg<'help> { /// assert!(res.is_ok()); /// ``` /// - /// Setting `Arg::required_unless(name)` and *not* supplying `name` or this arg is an error. + /// Setting `Arg::required_unless_present(name)` and *not* supplying `name` or this arg is an error. /// /// ```rust /// # use clap::{App, Arg, ErrorKind}; /// let res = App::new("prog") /// .arg(Arg::new("cfg") - /// .required_unless("dbg") + /// .required_unless_present("dbg") /// .takes_value(true) /// .long("config")) /// .arg(Arg::new("dbg") @@ -676,7 +676,7 @@ impl<'help> Arg<'help> { /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); /// ``` /// [required]: ./struct.Arg.html#method.required - pub fn required_unless(mut self, arg_id: T) -> Self { + pub fn required_unless_present(mut self, arg_id: T) -> Self { self.r_unless.push(arg_id.into()); self } @@ -4294,7 +4294,7 @@ impl<'help> From<&'help Yaml> for Arg<'help> { "require_equals" => yaml_to_bool!(a, v, require_equals), "require_delimiter" => yaml_to_bool!(a, v, require_delimiter), "value_delimiter" => yaml_to_str!(a, v, value_delimiter), - "required_unless" => yaml_to_str!(a, v, required_unless), + "required_unless_present" => yaml_to_str!(a, v, required_unless_present), "display_order" => yaml_to_usize!(a, v, display_order), "default_value" => yaml_to_str!(a, v, default_value), "default_value_if" => yaml_tuple3!(a, v, default_value_if), @@ -4315,7 +4315,7 @@ impl<'help> From<&'help Yaml> for Arg<'help> { "case_insensitive" => yaml_to_bool!(a, v, case_insensitive), "required_unless_eq_any" => yaml_vec_or_str!(v, a, required_unless), "required_unless_all" => { - a = yaml_vec_or_str!(v, a, required_unless); + a = yaml_vec_or_str!(v, a, required_unless_present); a.set_mut(ArgSettings::RequiredUnlessAll); a } diff --git a/tests/require.rs b/tests/require.rs index 0d05b114..72da9d6d 100644 --- a/tests/require.rs +++ b/tests/require.rs @@ -199,25 +199,28 @@ fn issue_753() { )) .arg( Arg::from("-i, --iface=[INTERFACE] 'Ethernet interface for fetching NTP packets'") - .required_unless("list"), + .required_unless_present("list"), ) .arg( Arg::from("-f, --file=[TESTFILE] 'Fetch NTP packets from pcap file'") .conflicts_with("iface") - .required_unless("list"), + .required_unless_present("list"), + ) + .arg( + Arg::from("-s, --server=[SERVER_IP] 'NTP server IP address'") + .required_unless_present("list"), ) - .arg(Arg::from("-s, --server=[SERVER_IP] 'NTP server IP address'").required_unless("list")) .arg(Arg::from("-p, --port=[SERVER_PORT] 'NTP server port'").default_value("123")) .try_get_matches_from(vec!["test", "--list"]); assert!(m.is_ok()); } #[test] -fn required_unless() { +fn required_unless_present() { let res = App::new("unlesstest") .arg( Arg::new("cfg") - .required_unless("dbg") + .required_unless_present("dbg") .takes_value(true) .long("config"), ) @@ -235,7 +238,7 @@ fn required_unless_err() { let res = App::new("unlesstest") .arg( Arg::new("cfg") - .required_unless("dbg") + .required_unless_present("dbg") .takes_value(true) .long("config"), ) @@ -781,12 +784,12 @@ fn issue_1158_app() -> App<'static> { App::new("example") .arg( Arg::from("-c, --config [FILE] 'Custom config file.'") - .required_unless("ID") + .required_unless_present("ID") .conflicts_with("ID"), ) .arg( Arg::from("[ID] 'ID'") - .required_unless("config") + .required_unless_present("config") .conflicts_with("config") .requires_all(&["x", "y", "z"]), ) @@ -874,6 +877,10 @@ fn required_if_invalid_arg() { #[should_panic = "Argument or group 'extra' specified in 'required_unless*' for 'config' does not exist"] fn required_unless_invalid_arg() { let _ = App::new("prog") - .arg(Arg::new("config").required_unless("extra").long("config")) + .arg( + Arg::new("config") + .required_unless_present("extra") + .long("config"), + ) .try_get_matches_from(vec![""]); } From ce3171ace59d962c640fbfdf89fa65693f4b4504 Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Sun, 31 May 2020 04:41:52 +0300 Subject: [PATCH 6/9] Arg::required_unless_all => required_unless_eq_all --- src/build/arg/mod.rs | 22 +++++++++++----------- tests/require.rs | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index bfdad780..c116b9ca 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -695,7 +695,7 @@ impl<'help> Arg<'help> { /// ```rust /// # use clap::Arg; /// Arg::new("config") - /// .required_unless_all(&["cfg", "dbg"]) + /// .required_unless_eq_all(&["cfg", "dbg"]) /// # ; /// ``` /// @@ -706,7 +706,7 @@ impl<'help> Arg<'help> { /// # use clap::{App, Arg}; /// let res = App::new("prog") /// .arg(Arg::new("cfg") - /// .required_unless_all(&["dbg", "infile"]) + /// .required_unless_eq_all(&["dbg", "infile"]) /// .takes_value(true) /// .long("config")) /// .arg(Arg::new("dbg") @@ -721,14 +721,14 @@ impl<'help> Arg<'help> { /// assert!(res.is_ok()); /// ``` /// - /// Setting [`Arg::required_unless_all(names)`] and *not* supplying + /// Setting [`Arg::required_unless_eq_all(names)`] and *not* supplying /// either *all* of `unless` args or the `self` arg is an error. /// /// ```rust /// # use clap::{App, Arg, ErrorKind}; /// let res = App::new("prog") /// .arg(Arg::new("cfg") - /// .required_unless_all(&["dbg", "infile"]) + /// .required_unless_eq_all(&["dbg", "infile"]) /// .takes_value(true) /// .long("config")) /// .arg(Arg::new("dbg") @@ -744,8 +744,8 @@ impl<'help> Arg<'help> { /// assert_eq!(res.unwrap_err().kind, ErrorKind::MissingRequiredArgument); /// ``` /// [`Arg::required_unless_eq_any`]: ./struct.Arg.html#method.required_unless_eq_any - /// [`Arg::required_unless_all(names)`]: ./struct.Arg.html#method.required_unless_all - pub fn required_unless_all(mut self, names: &[&str]) -> Self { + /// [`Arg::required_unless_eq_all(names)`]: ./struct.Arg.html#method.required_unless_eq_all + pub fn required_unless_eq_all(mut self, names: &[&str]) -> Self { self.r_unless.extend(names.iter().map(Id::from)); self.setting(ArgSettings::RequiredUnlessAll) } @@ -761,7 +761,7 @@ impl<'help> Arg<'help> { /// ```rust /// # use clap::Arg; /// Arg::new("config") - /// .required_unless_all(&["cfg", "dbg"]) + /// .required_unless_eq_all(&["cfg", "dbg"]) /// # ; /// ``` /// @@ -813,7 +813,7 @@ impl<'help> Arg<'help> { /// ``` /// [required]: ./struct.Arg.html#method.required /// [`Arg::required_unless_eq_any(names)`]: ./struct.Arg.html#method.required_unless_eq_any - /// [`Arg::required_unless_all`]: ./struct.Arg.html#method.required_unless_all + /// [`Arg::required_unless_eq_all`]: ./struct.Arg.html#method.required_unless_eq_all pub fn required_unless_eq_any(mut self, names: &[&str]) -> Self { self.r_unless.extend(names.iter().map(Id::from)); self @@ -4313,9 +4313,9 @@ impl<'help> From<&'help Yaml> for Arg<'help> { "overrides_with" => yaml_vec_or_str!(v, a, overrides_with), "possible_values" => yaml_vec_or_str!(v, a, possible_value), "case_insensitive" => yaml_to_bool!(a, v, case_insensitive), - "required_unless_eq_any" => yaml_vec_or_str!(v, a, required_unless), - "required_unless_all" => { - a = yaml_vec_or_str!(v, a, required_unless_present); + "required_unless_eq_any" => yaml_vec_or_str!(v, a, required_unless_eq_any), + "required_unless_eq_all" => { + a = yaml_vec_or_str!(v, a, required_unless_eq_all); a.set_mut(ArgSettings::RequiredUnlessAll); a } diff --git a/tests/require.rs b/tests/require.rs index 72da9d6d..026d4625 100644 --- a/tests/require.rs +++ b/tests/require.rs @@ -252,11 +252,11 @@ fn required_unless_err() { // REQUIRED_UNLESS_ALL #[test] -fn required_unless_all() { +fn required_unless_eq_all() { let res = App::new("unlessall") .arg( Arg::new("cfg") - .required_unless_all(&["dbg", "infile"]) + .required_unless_eq_all(&["dbg", "infile"]) .takes_value(true) .long("config"), ) @@ -276,7 +276,7 @@ fn required_unless_all_err() { let res = App::new("unlessall") .arg( Arg::new("cfg") - .required_unless_all(&["dbg", "infile"]) + .required_unless_eq_all(&["dbg", "infile"]) .takes_value(true) .long("config"), ) From 0b2eac4da7ac06663146ce67b558c3b39715bc18 Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Sat, 15 Aug 2020 20:11:50 +0300 Subject: [PATCH 7/9] Fix yaml support --- examples/23_flag_subcommands_pacman.rs | 2 +- src/build/app/debug_asserts.rs | 2 +- src/build/arg/mod.rs | 34 ++++++++++++++++---------- src/build/arg_group.rs | 6 ++--- src/build/macros.rs | 22 ++++++++++++++++- 5 files changed, 47 insertions(+), 19 deletions(-) diff --git a/examples/23_flag_subcommands_pacman.rs b/examples/23_flag_subcommands_pacman.rs index 42aea7f5..7f2ed61f 100644 --- a/examples/23_flag_subcommands_pacman.rs +++ b/examples/23_flag_subcommands_pacman.rs @@ -79,7 +79,7 @@ fn main() { Arg::new("package") .about("packages") .multiple(true) - .required_unless_one(&["search"]) + .required_unless_present("search") .takes_value(true), ), ) diff --git a/src/build/app/debug_asserts.rs b/src/build/app/debug_asserts.rs index c4e52ca5..f3ace5ac 100644 --- a/src/build/app/debug_asserts.rs +++ b/src/build/app/debug_asserts.rs @@ -138,7 +138,7 @@ pub(crate) fn assert_app(app: &App) { for req in &arg.r_ifs { assert!( app.id_exists(&req.0), - "Argument or group '{:?}' specified in 'required_if*' for '{}' does not exist", + "Argument or group '{:?}' specified in 'required_if_eq*' for '{}' does not exist", req.0, arg.name ); diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index c116b9ca..6df28d92 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -745,8 +745,12 @@ impl<'help> Arg<'help> { /// ``` /// [`Arg::required_unless_eq_any`]: ./struct.Arg.html#method.required_unless_eq_any /// [`Arg::required_unless_eq_all(names)`]: ./struct.Arg.html#method.required_unless_eq_all - pub fn required_unless_eq_all(mut self, names: &[&str]) -> Self { - self.r_unless.extend(names.iter().map(Id::from)); + pub fn required_unless_eq_all(mut self, names: I) -> Self + where + I: IntoIterator, + T: Key + { + self.r_unless.extend(names.into_iter().map(Id::from)); self.setting(ArgSettings::RequiredUnlessAll) } @@ -814,8 +818,12 @@ impl<'help> Arg<'help> { /// [required]: ./struct.Arg.html#method.required /// [`Arg::required_unless_eq_any(names)`]: ./struct.Arg.html#method.required_unless_eq_any /// [`Arg::required_unless_eq_all`]: ./struct.Arg.html#method.required_unless_eq_all - pub fn required_unless_eq_any(mut self, names: &[&str]) -> Self { - self.r_unless.extend(names.iter().map(Id::from)); + pub fn required_unless_eq_any(mut self, names: I) -> Self + where + I: IntoIterator, + T: Key + { + self.r_unless.extend(names.into_iter().map(Id::from)); self } @@ -4269,7 +4277,7 @@ impl<'help> From<&'help Yaml> for Arg<'help> { a = match k.as_str().unwrap() { "short" => yaml_to_char!(a, v, short), "long" => yaml_to_str!(a, v, long), - "aliases" => yaml_vec_or_str!(v, a, alias), + "aliases" => yaml_vec_or_str!(a, v, alias), "short_aliases" => yaml_to_chars!(a, v, short_aliases), "about" => yaml_to_str!(a, v, about), "long_about" => yaml_to_str!(a, v, long_about), @@ -4301,21 +4309,21 @@ impl<'help> From<&'help Yaml> for Arg<'help> { "default_value_ifs" => yaml_tuple3!(a, v, default_value_if), "default_missing_value" => yaml_to_str!(a, v, default_missing_value), "env" => yaml_to_str!(a, v, env), - "value_names" => yaml_vec_or_str!(v, a, value_name), - "groups" => yaml_vec_or_str!(v, a, group), - "requires" => yaml_vec_or_str!(v, a, requires), + "value_names" => yaml_vec_or_str!(a, v, value_name), + "groups" => yaml_vec_or_str!(a, v, group), + "requires" => yaml_vec_or_str!(a, v, requires), "requires_if" => yaml_tuple2!(a, v, requires_if), "requires_ifs" => yaml_tuple2!(a, v, requires_if), - "conflicts_with" => yaml_vec_or_str!(v, a, conflicts_with), + "conflicts_with" => yaml_vec_or_str!(a, v, conflicts_with), "exclusive" => yaml_to_bool!(a, v, exclusive), "value_hint" => yaml_str_parse!(a, v, value_hint), "hide_default_value" => yaml_to_bool!(a, v, hide_default_value), - "overrides_with" => yaml_vec_or_str!(v, a, overrides_with), - "possible_values" => yaml_vec_or_str!(v, a, possible_value), + "overrides_with" => yaml_vec_or_str!(a, v, overrides_with), + "possible_values" => yaml_vec_or_str!(a, v, possible_value), "case_insensitive" => yaml_to_bool!(a, v, case_insensitive), - "required_unless_eq_any" => yaml_vec_or_str!(v, a, required_unless_eq_any), + "required_unless_eq_any" => yaml_vec!(a, v, required_unless_eq_any), "required_unless_eq_all" => { - a = yaml_vec_or_str!(v, a, required_unless_eq_all); + a = yaml_vec!(a, v, required_unless_eq_all); a.set_mut(ArgSettings::RequiredUnlessAll); a } diff --git a/src/build/arg_group.rs b/src/build/arg_group.rs index bb0c478a..0cbd34f1 100644 --- a/src/build/arg_group.rs +++ b/src/build/arg_group.rs @@ -442,15 +442,15 @@ impl<'help> From<&'help Yaml> for ArgGroup<'help> { a = match k.as_str().unwrap() { "required" => a.required(v.as_bool().unwrap()), "multiple" => a.multiple(v.as_bool().unwrap()), - "args" => yaml_vec_or_str!(v, a, arg), + "args" => yaml_vec_or_str!(a, v, arg), "arg" => { if let Some(ys) = v.as_str() { a = a.arg(ys); } a } - "requires" => yaml_vec_or_str!(v, a, requires), - "conflicts_with" => yaml_vec_or_str!(v, a, conflicts_with), + "requires" => yaml_vec_or_str!(a, v, requires), + "conflicts_with" => yaml_vec_or_str!(a, v, conflicts_with), "name" => { if let Some(ys) = v.as_str() { a.name = ys; diff --git a/src/build/macros.rs b/src/build/macros.rs index 899840ab..62727c15 100644 --- a/src/build/macros.rs +++ b/src/build/macros.rs @@ -38,7 +38,7 @@ macro_rules! yaml_tuple3 { #[cfg(feature = "yaml")] macro_rules! yaml_vec_or_str { - ($v:ident, $a:ident, $c:ident) => {{ + ($a:ident, $v:ident, $c:ident) => {{ let maybe_vec = $v.as_vec(); if let Some(vec) = maybe_vec { for ys in vec { @@ -62,6 +62,26 @@ macro_rules! yaml_vec_or_str { }}; } +#[cfg(feature = "yaml")] +macro_rules! yaml_vec { + ($a:ident, $v:ident, $c:ident) => {{ + let maybe_vec = $v.as_vec(); + if let Some(vec) = maybe_vec { + let content = vec.into_iter().map(|ys| { + if let Some(s) = ys.as_str() { + s + } else { + panic!("Failed to convert YAML value {:?} to a string", ys); + } + }); + $a = $a.$c(content) + } else { + panic!("Failed to convert YAML value {:?} to a vec", $v); + } + $a + }}; +} + #[cfg(feature = "yaml")] macro_rules! yaml_opt_str { ($v:expr) => {{ From f4fb9db65cf1f6c6836aa8cb92e461d8711abd70 Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Sun, 16 Aug 2020 00:29:30 +0300 Subject: [PATCH 8/9] cargo fmt --- src/build/arg/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/build/arg/mod.rs b/src/build/arg/mod.rs index 6df28d92..50c0cc98 100644 --- a/src/build/arg/mod.rs +++ b/src/build/arg/mod.rs @@ -747,8 +747,8 @@ impl<'help> Arg<'help> { /// [`Arg::required_unless_eq_all(names)`]: ./struct.Arg.html#method.required_unless_eq_all pub fn required_unless_eq_all(mut self, names: I) -> Self where - I: IntoIterator, - T: Key + I: IntoIterator, + T: Key, { self.r_unless.extend(names.into_iter().map(Id::from)); self.setting(ArgSettings::RequiredUnlessAll) @@ -820,8 +820,8 @@ impl<'help> Arg<'help> { /// [`Arg::required_unless_eq_all`]: ./struct.Arg.html#method.required_unless_eq_all pub fn required_unless_eq_any(mut self, names: I) -> Self where - I: IntoIterator, - T: Key + I: IntoIterator, + T: Key, { self.r_unless.extend(names.into_iter().map(Id::from)); self From 0cc8663db32d5e9c7389bd12b20659d632e02730 Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Mon, 17 Aug 2020 22:23:29 +0300 Subject: [PATCH 9/9] Fix benches --- benches/05_ripgrep.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/05_ripgrep.rs b/benches/05_ripgrep.rs index 3ae76eb1..9117d829 100644 --- a/benches/05_ripgrep.rs +++ b/benches/05_ripgrep.rs @@ -315,7 +315,7 @@ where .arg(flag("help")) .arg(flag("version").short('V')) // First, set up primary positional/flag arguments. - .arg(arg("pattern").required_unless_one(&[ + .arg(arg("pattern").required_unless_eq_any(&[ "file", "files", "help-short",