From d2a1f5a8f86be5cf8374db2f56533a6b8e93a624 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 1 Sep 2022 19:19:55 -0500 Subject: [PATCH 1/2] feat(parser): Provide convenience accessor for Counts --- examples/tutorial_builder/03_01_flag_count.rs | 7 +---- src/builder/action.rs | 8 ++--- src/parser/matches/arg_matches.rs | 31 +++++++++++++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/examples/tutorial_builder/03_01_flag_count.rs b/examples/tutorial_builder/03_01_flag_count.rs index 059a3f30256..7f23649d685 100644 --- a/examples/tutorial_builder/03_01_flag_count.rs +++ b/examples/tutorial_builder/03_01_flag_count.rs @@ -5,10 +5,5 @@ fn main() { .arg(arg!(-v - -verbose).action(ArgAction::Count)) .get_matches(); - println!( - "verbose: {:?}", - matches - .get_one::("verbose") - .expect("Count always defaulted") - ); + println!("verbose: {:?}", matches.get_count("verbose")); } diff --git a/src/builder/action.rs b/src/builder/action.rs index ab331429092..71a91a8b1b3 100644 --- a/src/builder/action.rs +++ b/src/builder/action.rs @@ -183,16 +183,16 @@ pub enum ArgAction { /// assert!(matches.contains_id("flag")); /// assert_eq!(matches.occurrences_of("flag"), 0); /// assert_eq!( - /// matches.get_one::("flag").copied(), - /// Some(2) + /// matches.get_count("flag"), + /// 2 /// ); /// /// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap(); /// assert!(matches.contains_id("flag")); /// assert_eq!(matches.occurrences_of("flag"), 0); /// assert_eq!( - /// matches.get_one::("flag").copied(), - /// Some(0) + /// matches.get_count("flag"), + /// 0 /// ); /// ``` Count, diff --git a/src/parser/matches/arg_matches.rs b/src/parser/matches/arg_matches.rs index d0df68441ff..69f96b92502 100644 --- a/src/parser/matches/arg_matches.rs +++ b/src/parser/matches/arg_matches.rs @@ -119,6 +119,37 @@ impl ArgMatches { MatchesError::unwrap(&internal_id, self.try_get_one(id)) } + /// Gets the value of a specific [`ArgAction::Count`][crate::ArgAction::Count] flag + /// + /// # Panic + /// + /// If the argument's action is not [`ArgAction::Count`][crate::ArgAction::Count] + /// + /// # Examples + /// + /// ```rust + /// # use clap::Command; + /// # use clap::Arg; + /// let cmd = Command::new("mycmd") + /// .arg( + /// Arg::new("flag") + /// .long("flag") + /// .action(clap::ArgAction::Count) + /// ); + /// + /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap(); + /// assert_eq!( + /// matches.get_count("flag"), + /// 2 + /// ); + /// ``` + #[track_caller] + pub fn get_count(&self, id: &str) -> u8 { + *self + .get_one::(id) + .expect("ArgAction::Count is defaulted") + } + /// Iterate over values of a specific option or positional argument. /// /// i.e. an argument that takes multiple values at runtime. From 2d5fea50b96b68f8bad4030820837cfd767530d8 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Thu, 1 Sep 2022 19:40:56 -0500 Subject: [PATCH 2/2] feat(parser): Provide convenience for SetTrue I wanted to make `bool` a defaulted type parameter but https://github.com/rust-lang/rust/issues/36887 --- examples/derive_ref/augment_args.rs | 7 ++--- examples/derive_ref/flatten_hand_args.rs | 8 ++--- examples/escaped-positional.rs | 5 +-- examples/pacman.rs | 5 +-- examples/tutorial_builder/03_01_flag_bool.rs | 7 +---- examples/tutorial_builder/04_03_relations.rs | 6 ++-- examples/tutorial_builder/04_04_custom.rs | 11 +++---- src/parser/matches/arg_matches.rs | 32 ++++++++++++++++++++ 8 files changed, 48 insertions(+), 33 deletions(-) diff --git a/examples/derive_ref/augment_args.rs b/examples/derive_ref/augment_args.rs index 8a07f6743c5..310556914e6 100644 --- a/examples/derive_ref/augment_args.rs +++ b/examples/derive_ref/augment_args.rs @@ -12,13 +12,10 @@ fn main() { let cli = DerivedArgs::augment_args(cli); let matches = cli.get_matches(); - println!( - "Value of built: {:?}", - *matches.get_one::("built").unwrap() - ); + println!("Value of built: {:?}", matches.get_flag("built")); println!( "Value of derived via ArgMatches: {:?}", - *matches.get_one::("derived").unwrap() + matches.get_flag("derived") ); // Since DerivedArgs implements FromArgMatches, we can extract it from the unstructured ArgMatches. diff --git a/examples/derive_ref/flatten_hand_args.rs b/examples/derive_ref/flatten_hand_args.rs index 74d10edec5f..c10e0b29f27 100644 --- a/examples/derive_ref/flatten_hand_args.rs +++ b/examples/derive_ref/flatten_hand_args.rs @@ -15,8 +15,8 @@ impl FromArgMatches for CliArgs { } fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result { Ok(Self { - foo: *matches.get_one::("foo").expect("defaulted by clap"), - bar: *matches.get_one::("bar").expect("defaulted by clap"), + foo: matches.get_flag("foo"), + bar: matches.get_flag("bar"), quuz: matches.remove_one::("quuz"), }) } @@ -25,8 +25,8 @@ impl FromArgMatches for CliArgs { self.update_from_arg_matches_mut(&mut matches) } fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> { - self.foo |= *matches.get_one::("foo").expect("defaulted by clap"); - self.bar |= *matches.get_one::("bar").expect("defaulted by clap"); + self.foo |= matches.get_flag("foo"); + self.bar |= matches.get_flag("bar"); if let Some(quuz) = matches.remove_one::("quuz") { self.quuz = Some(quuz); } diff --git a/examples/escaped-positional.rs b/examples/escaped-positional.rs index 02420010022..fdcb930fb03 100644 --- a/examples/escaped-positional.rs +++ b/examples/escaped-positional.rs @@ -20,10 +20,7 @@ fn main() { // This is what will happen with `myprog -f -p=bob -- sloppy slop slop`... // -f used: true - println!( - "-f used: {:?}", - *matches.get_one::("eff").expect("defaulted by clap") - ); + println!("-f used: {:?}", matches.get_flag("eff")); // -p's value: Some("bob") println!("-p's value: {:?}", matches.get_one::("pea")); // 'slops' values: Some(["sloppy", "slop", "slop"]) diff --git a/examples/pacman.rs b/examples/pacman.rs index 6a60a8bf5ca..aee7cd8923e 100644 --- a/examples/pacman.rs +++ b/examples/pacman.rs @@ -89,10 +89,7 @@ fn main() { .collect(); let values = packages.join(", "); - if *sync_matches - .get_one::("info") - .expect("defaulted by clap") - { + if sync_matches.get_flag("info") { println!("Retrieving info for {}...", values); } else { println!("Installing {}...", values); diff --git a/examples/tutorial_builder/03_01_flag_bool.rs b/examples/tutorial_builder/03_01_flag_bool.rs index 5aa55be9516..03f2f1756f6 100644 --- a/examples/tutorial_builder/03_01_flag_bool.rs +++ b/examples/tutorial_builder/03_01_flag_bool.rs @@ -10,10 +10,5 @@ fn main() { ) .get_matches(); - println!( - "verbose: {:?}", - *matches - .get_one::("verbose") - .expect("defaulted by clap") - ); + println!("verbose: {:?}", matches.get_flag("verbose")); } diff --git a/examples/tutorial_builder/04_03_relations.rs b/examples/tutorial_builder/04_03_relations.rs index 37e097558f1..8e26d3ea919 100644 --- a/examples/tutorial_builder/04_03_relations.rs +++ b/examples/tutorial_builder/04_03_relations.rs @@ -50,9 +50,9 @@ fn main() { } else { // Increment the one requested (in a real program, we'd reset the lower numbers) let (maj, min, pat) = ( - *matches.get_one::("major").expect("defaulted by clap"), - *matches.get_one::("minor").expect("defaulted by clap"), - *matches.get_one::("patch").expect("defaulted by clap"), + matches.get_flag("major"), + matches.get_flag("minor"), + matches.get_flag("patch"), ); match (maj, min, pat) { (true, _, _) => major += 1, diff --git a/examples/tutorial_builder/04_04_custom.rs b/examples/tutorial_builder/04_04_custom.rs index bd97f7ee275..fb40b2fc41d 100644 --- a/examples/tutorial_builder/04_04_custom.rs +++ b/examples/tutorial_builder/04_04_custom.rs @@ -34,10 +34,7 @@ fn main() { // See if --set-ver was used to set the version manually let version = if let Some(ver) = matches.get_one::("set-ver") { - if *matches.get_one::("major").expect("defaulted by clap") - || *matches.get_one::("minor").expect("defaulted by clap") - || *matches.get_one::("patch").expect("defaulted by clap") - { + if matches.get_flag("major") || matches.get_flag("minor") || matches.get_flag("patch") { cmd.error( ErrorKind::ArgumentConflict, "Can't do relative and absolute version change", @@ -48,9 +45,9 @@ fn main() { } else { // Increment the one requested (in a real program, we'd reset the lower numbers) let (maj, min, pat) = ( - *matches.get_one::("major").expect("defaulted by clap"), - *matches.get_one::("minor").expect("defaulted by clap"), - *matches.get_one::("patch").expect("defaulted by clap"), + matches.get_flag("major"), + matches.get_flag("minor"), + matches.get_flag("patch"), ); match (maj, min, pat) { (true, false, false) => major += 1, diff --git a/src/parser/matches/arg_matches.rs b/src/parser/matches/arg_matches.rs index 69f96b92502..2585c02199f 100644 --- a/src/parser/matches/arg_matches.rs +++ b/src/parser/matches/arg_matches.rs @@ -150,6 +150,38 @@ impl ArgMatches { .expect("ArgAction::Count is defaulted") } + /// Gets the value of a specific [`ArgAction::SetTrue`][crate::ArgAction::SetTrue] or [`ArgAction::SetFalse`][crate::ArgAction::SetFalse] flag + /// + /// # Panic + /// + /// If the argument's action is not [`ArgAction::SetTrue`][crate::ArgAction::SetTrue] or [`ArgAction::SetFalse`][crate::ArgAction::SetFalse] + /// + /// # Examples + /// + /// ```rust + /// # use clap::Command; + /// # use clap::Arg; + /// let cmd = Command::new("mycmd") + /// .arg( + /// Arg::new("flag") + /// .long("flag") + /// .action(clap::ArgAction::SetTrue) + /// ); + /// + /// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap(); + /// assert!(matches.contains_id("flag")); + /// assert_eq!( + /// matches.get_flag("flag"), + /// true + /// ); + /// ``` + #[track_caller] + pub fn get_flag(&self, id: &str) -> bool { + *self + .get_one::(id) + .expect("ArgAction::SetTrue / ArgAction::SetFalse is defaulted") + } + /// Iterate over values of a specific option or positional argument. /// /// i.e. an argument that takes multiple values at runtime.