mirror of
https://github.com/clap-rs/clap
synced 2025-03-04 15:27:16 +00:00
feat(parser): Report what arg ids are present
For now, we are focusing only on iterating over the argument ids and not the values. This provides a building block for more obscure use cases like iterating over argument values, in order. We are not providing it out of the box at the moment both to not overly incentize a less common case, because it would abstract away a performance hit, and because we want to let people experiment with this and if a common path emerges we can consider it then if there is enough users. Fixes #1206
This commit is contained in:
parent
c45bd64941
commit
7486a0b4b9
4 changed files with 143 additions and 1 deletions
|
@ -303,6 +303,35 @@ impl ArgMatches {
|
|||
MatchesError::unwrap(id, self.try_contains_id(id))
|
||||
}
|
||||
|
||||
/// Iterate over [`Arg`][crate::Arg] and [`ArgGroup`][crate::ArgGroup] [`Id`][crate::Id]s via [`ArgMatches::ids`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use clap::{Command, arg, value_parser};
|
||||
///
|
||||
/// let m = Command::new("myprog")
|
||||
/// .arg(arg!(--color <when>)
|
||||
/// .value_parser(["auto", "always", "never"])
|
||||
/// .required(false))
|
||||
/// .arg(arg!(--config <path>)
|
||||
/// .value_parser(value_parser!(std::path::PathBuf))
|
||||
/// .required(false))
|
||||
/// .get_matches_from(["myprog", "--config=config.toml", "--color=auto"]);
|
||||
/// assert_eq!(m.ids().len(), 2);
|
||||
/// assert_eq!(
|
||||
/// m.ids()
|
||||
/// .map(|id| id.as_str())
|
||||
/// .collect::<Vec<_>>(),
|
||||
/// ["config", "color"]
|
||||
/// );
|
||||
/// ```
|
||||
pub fn ids(&self) -> IdsRef<'_> {
|
||||
IdsRef {
|
||||
iter: self.args.keys(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if any args were present on the command line
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -1066,6 +1095,52 @@ pub(crate) struct SubCommand {
|
|||
pub(crate) matches: ArgMatches,
|
||||
}
|
||||
|
||||
/// Iterate over [`Arg`][crate::Arg] and [`ArgGroup`][crate::ArgGroup] [`Id`][crate::Id]s via [`ArgMatches::ids`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use clap::{Command, arg, value_parser};
|
||||
///
|
||||
/// let m = Command::new("myprog")
|
||||
/// .arg(arg!(--color <when>)
|
||||
/// .value_parser(["auto", "always", "never"])
|
||||
/// .required(false))
|
||||
/// .arg(arg!(--config <path>)
|
||||
/// .value_parser(value_parser!(std::path::PathBuf))
|
||||
/// .required(false))
|
||||
/// .get_matches_from(["myprog", "--config=config.toml", "--color=auto"]);
|
||||
/// assert_eq!(
|
||||
/// m.ids()
|
||||
/// .map(|id| id.as_str())
|
||||
/// .collect::<Vec<_>>(),
|
||||
/// ["config", "color"]
|
||||
/// );
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IdsRef<'a> {
|
||||
iter: std::slice::Iter<'a, Id>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for IdsRef<'a> {
|
||||
type Item = &'a Id;
|
||||
|
||||
fn next(&mut self) -> Option<&'a Id> {
|
||||
self.iter.next()
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.iter.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> DoubleEndedIterator for IdsRef<'a> {
|
||||
fn next_back(&mut self) -> Option<&'a Id> {
|
||||
self.iter.next_back()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ExactSizeIterator for IdsRef<'a> {}
|
||||
|
||||
/// Iterate over multiple values for an argument via [`ArgMatches::remove_many`].
|
||||
///
|
||||
/// # Examples
|
||||
|
|
|
@ -4,6 +4,7 @@ mod matched_arg;
|
|||
mod value_source;
|
||||
|
||||
pub use any_value::AnyValueId;
|
||||
pub use arg_matches::IdsRef;
|
||||
pub use arg_matches::RawValues;
|
||||
pub use arg_matches::Values;
|
||||
pub use arg_matches::ValuesRef;
|
||||
|
|
|
@ -19,6 +19,7 @@ pub(crate) use self::parser::{ParseState, Parser};
|
|||
pub(crate) use self::validator::get_possible_values_cli;
|
||||
pub(crate) use self::validator::Validator;
|
||||
|
||||
pub use self::matches::IdsRef;
|
||||
pub use self::matches::RawValues;
|
||||
pub use self::matches::Values;
|
||||
pub use self::matches::ValuesRef;
|
||||
|
|
|
@ -1,5 +1,70 @@
|
|||
use clap::{arg, value_parser, Command};
|
||||
#[cfg(debug_assertions)]
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
use clap::{Arg, ArgAction};
|
||||
|
||||
#[test]
|
||||
fn ids() {
|
||||
let m = Command::new("test")
|
||||
.arg(
|
||||
arg!(--color <when>)
|
||||
.value_parser(["auto", "always", "never"])
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
arg!(--config <path>)
|
||||
.value_parser(value_parser!(std::path::PathBuf))
|
||||
.required(false),
|
||||
)
|
||||
.try_get_matches_from(["test", "--config=config.toml", "--color=auto"])
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
m.ids().map(|id| id.as_str()).collect::<Vec<_>>(),
|
||||
["config", "color"]
|
||||
);
|
||||
assert_eq!(m.ids().len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ids_ignore_unused() {
|
||||
let m = Command::new("test")
|
||||
.arg(
|
||||
arg!(--color <when>)
|
||||
.value_parser(["auto", "always", "never"])
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
arg!(--config <path>)
|
||||
.value_parser(value_parser!(std::path::PathBuf))
|
||||
.required(false),
|
||||
)
|
||||
.try_get_matches_from(["test", "--config=config.toml"])
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
m.ids().map(|id| id.as_str()).collect::<Vec<_>>(),
|
||||
["config"]
|
||||
);
|
||||
assert_eq!(m.ids().len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ids_ignore_overridden() {
|
||||
let m = Command::new("test")
|
||||
.arg(
|
||||
arg!(--color <when>)
|
||||
.value_parser(["auto", "always", "never"])
|
||||
.required(false),
|
||||
)
|
||||
.arg(
|
||||
arg!(--config <path>)
|
||||
.value_parser(value_parser!(std::path::PathBuf))
|
||||
.required(false)
|
||||
.overrides_with("color"),
|
||||
)
|
||||
.try_get_matches_from(["test", "--config=config.toml", "--color=auto"])
|
||||
.unwrap();
|
||||
assert_eq!(m.ids().map(|id| id.as_str()).collect::<Vec<_>>(), ["color"]);
|
||||
assert_eq!(m.ids().len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(debug_assertions)]
|
||||
|
|
Loading…
Add table
Reference in a new issue