Skip to content

Commit

Permalink
feat(parser): Add type information to arg values
Browse files Browse the repository at this point in the history
To set the type, we offer
- `ValueParser::<type>` short cuts for natively supported types
- `TypedValueParser` for fn pointers and custom implementations
- `value_parser!(T)` for specialized lookup of an implementation
  (inspired by clap-rs#2298)

The main motivation for `value_parser!` is to help with `clap_derive`s
implementation but it can also be convinient for end-users.

When reading, this replaces nearly all of our current `ArgMatches` getters with:
- `get_one`: like `value_of_t`
- `get_many`: like `values_of_t`

It also adds a `get_raw` that allows accessing the `OsStr`s without
panicing.

The naming is to invoke the idea of a more general container which I
want to move this to.

The return type is a bit complicated so that
- Users choose whether to panic on invalid types so they can do their
  own querying, like `get_raw`
- Users can choose how to handle not present easily (clap-rs#2505)

We had to defer setting the `value_parser` on external subcommands,
for consistency sake, because `Command` requires `PartialEq` and
`ValueParser` does not impl that trait.  It'll have to wait until a
breaking change.

Fixes clap-rs#2505
  • Loading branch information
epage committed May 16, 2022
1 parent dcf69d1 commit 200f662
Show file tree
Hide file tree
Showing 5 changed files with 526 additions and 4 deletions.
37 changes: 36 additions & 1 deletion src/builder/arg.rs
Expand Up @@ -1001,6 +1001,27 @@ impl<'help> Arg<'help> {
}
}

/// Specify the type of the argument.
///
/// This allows parsing and validating a value before storing it into
/// [`ArgMatches`][crate::ArgMatches].
///
/// ```rust
/// let cmd = clap::Command::new("raw")
/// .arg(
/// clap::Arg::new("port")
/// .value_parser(clap::value_parser!(usize))
/// );
/// let value_parser = cmd.get_arguments()
/// .find(|a| a.get_id() == "port").unwrap()
/// .get_value_parser();
/// println!("{:?}", value_parser);
/// ```
pub fn value_parser(mut self, parser: impl Into<super::ValueParser>) -> Self {
self.value_parser = Some(parser.into());
self
}

/// Specifies that the argument may have an unknown number of values
///
/// Without any other settings, this argument may appear only *once*.
Expand Down Expand Up @@ -4739,7 +4760,21 @@ impl<'help> Arg<'help> {
}

/// Configured parser for argument values
pub(crate) fn get_value_parser(&self) -> &super::ValueParser {
///
/// # Example
///
/// ```rust
/// let cmd = clap::Command::new("raw")
/// .arg(
/// clap::Arg::new("port")
/// .value_parser(clap::value_parser!(usize))
/// );
/// let value_parser = cmd.get_arguments()
/// .find(|a| a.get_id() == "port").unwrap()
/// .get_value_parser();
/// println!("{:?}", value_parser);
/// ```
pub fn get_value_parser(&self) -> &super::ValueParser {
if let Some(value_parser) = self.value_parser.as_ref() {
value_parser
} else if self.is_allow_invalid_utf8_set() {
Expand Down
12 changes: 11 additions & 1 deletion src/builder/command.rs
Expand Up @@ -3679,7 +3679,17 @@ impl<'help> App<'help> {
}

/// Configured parser for values passed to an external subcommand
pub(crate) fn get_external_subcommand_value_parser(&self) -> Option<&super::ValueParser> {
///
/// # Example
///
/// ```rust
/// let cmd = clap::Command::new("raw")
/// .allow_external_subcommands(true)
/// .allow_invalid_utf8_for_external_subcommands(true);
/// let value_parser = cmd.get_external_subcommand_value_parser();
/// println!("{:?}", value_parser);
/// ```
pub fn get_external_subcommand_value_parser(&self) -> Option<&super::ValueParser> {
if !self.is_allow_external_subcommands_set() {
None
} else if self.is_allow_invalid_utf8_for_external_subcommands_set() {
Expand Down
7 changes: 6 additions & 1 deletion src/builder/mod.rs
Expand Up @@ -30,7 +30,12 @@ pub use arg_settings::{ArgFlags, ArgSettings};
pub use command::Command;
pub use possible_value::PossibleValue;
pub use value_hint::ValueHint;
pub(crate) use value_parser::ValueParser;
pub use value_parser::AnyValueParser;
pub use value_parser::AutoValueParser;
pub use value_parser::TypedValueParser;
pub use value_parser::ValueParser;
pub use value_parser::ValueParserViaBuiltIn;
pub use value_parser::ValueParserViaFromStr;

#[allow(deprecated)]
pub use command::App;
Expand Down

0 comments on commit 200f662

Please sign in to comment.