diff --git a/Cargo.toml b/Cargo.toml index ec0f18f4..dedb10a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -240,6 +240,11 @@ name = "04_01_enum" path = "examples/tutorial_builder/04_01_enum.rs" required-features = ["cargo", "derive"] +[[example]] +name = "04_02_parse" +path = "examples/tutorial_builder/04_02_parse.rs" +required-features = ["cargo"] + [[example]] name = "04_02_validate" path = "examples/tutorial_builder/04_02_validate.rs" @@ -316,6 +321,11 @@ name = "04_01_enum_derive" path = "examples/tutorial_derive/04_01_enum.rs" required-features = ["derive"] +[[example]] +name = "04_02_parse_derive" +path = "examples/tutorial_derive/04_02_parse.rs" +required-features = ["derive"] + [[example]] name = "04_02_validate_derive" path = "examples/tutorial_derive/04_02_validate.rs" diff --git a/examples/tutorial_builder/04_02_parse.rs b/examples/tutorial_builder/04_02_parse.rs new file mode 100644 index 00000000..ff2bebbe --- /dev/null +++ b/examples/tutorial_builder/04_02_parse.rs @@ -0,0 +1,17 @@ +use clap::{app_from_crate, arg}; + +fn main() { + let matches = app_from_crate!() + .arg( + arg!() + .help("Network port to use") + .validator(|s| s.parse::()), + ) + .get_matches(); + + // Note, it's safe to call unwrap() because the arg is required + let port: usize = matches + .value_of_t("PORT") + .expect("'PORT' is required and parsing will fail if its missing"); + println!("PORT = {}", port); +} diff --git a/examples/tutorial_builder/04_02_validate.rs b/examples/tutorial_builder/04_02_validate.rs index ff2bebbe..1867dbf9 100644 --- a/examples/tutorial_builder/04_02_validate.rs +++ b/examples/tutorial_builder/04_02_validate.rs @@ -1,12 +1,24 @@ use clap::{app_from_crate, arg}; +use std::ops::RangeInclusive; +use std::str::FromStr; + +const PORT_RANGE: RangeInclusive = 1..=65535; fn main() { let matches = app_from_crate!() - .arg( - arg!() - .help("Network port to use") - .validator(|s| s.parse::()), - ) + .arg(arg!().help("Network port to use").validator(|s| { + usize::from_str(s) + .map(|port| PORT_RANGE.contains(&port)) + .map_err(|e| e.to_string()) + .and_then(|result| match result { + true => Ok(()), + false => Err(format!( + "Port not in range {}-{}", + PORT_RANGE.start(), + PORT_RANGE.end() + )), + }) + })) .get_matches(); // Note, it's safe to call unwrap() because the arg is required diff --git a/examples/tutorial_builder/README.md b/examples/tutorial_builder/README.md index 2ef1788f..a081d7c0 100644 --- a/examples/tutorial_builder/README.md +++ b/examples/tutorial_builder/README.md @@ -449,7 +449,36 @@ For more information try --help ### Validated values -More generally, you can validate and parse into any data type. +More generally, you can parse into any data type. + +[Example:](04_02_parse.rs) +```console +$ 04_02_parse --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_02_parse[EXE] + +ARGS: + Network port to use + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 04_02_parse 22 +PORT = 22 + +$ 04_02_parse foobar +? failed +error: Invalid value "foobar" for '': invalid digit found in string + +For more information try --help + +``` + +A custom validator can be used to improve the error messages or provide additional validation: [Example:](04_02_validate.rs) ```console @@ -470,9 +499,9 @@ OPTIONS: $ 04_02_validate 22 PORT = 22 -$ 04_02_validate foobar +$ 04_02_validate 0 ? failed -error: Invalid value "foobar" for '': invalid digit found in string +error: Invalid value "0" for '': Port not in range 1-65535 For more information try --help diff --git a/examples/tutorial_derive/04_02_parse.rs b/examples/tutorial_derive/04_02_parse.rs new file mode 100644 index 00000000..5f4cbadc --- /dev/null +++ b/examples/tutorial_derive/04_02_parse.rs @@ -0,0 +1,15 @@ +use clap::Parser; + +#[derive(Parser)] +#[clap(author, version, about, long_about = None)] +struct Cli { + /// Network port to use + #[clap(parse(try_from_str))] + port: usize, +} + +fn main() { + let cli = Cli::parse(); + + println!("PORT = {}", cli.port); +} diff --git a/examples/tutorial_derive/04_02_validate.rs b/examples/tutorial_derive/04_02_validate.rs index 5f4cbadc..df3c7c0f 100644 --- a/examples/tutorial_derive/04_02_validate.rs +++ b/examples/tutorial_derive/04_02_validate.rs @@ -1,10 +1,14 @@ use clap::Parser; +use std::ops::RangeInclusive; +use std::str::FromStr; + +const PORT_RANGE: RangeInclusive = 1..=65535; #[derive(Parser)] #[clap(author, version, about, long_about = None)] struct Cli { /// Network port to use - #[clap(parse(try_from_str))] + #[clap(validator = port_in_range)] port: usize, } @@ -13,3 +17,17 @@ fn main() { println!("PORT = {}", cli.port); } + +fn port_in_range(s: &str) -> Result<(), String> { + usize::from_str(s) + .map(|port| PORT_RANGE.contains(&port)) + .map_err(|e| e.to_string()) + .and_then(|result| match result { + true => Ok(()), + false => Err(format!( + "Port not in range {}-{}", + PORT_RANGE.start(), + PORT_RANGE.end() + )), + }) +} diff --git a/examples/tutorial_derive/README.md b/examples/tutorial_derive/README.md index 7160237c..45f582d1 100644 --- a/examples/tutorial_derive/README.md +++ b/examples/tutorial_derive/README.md @@ -417,6 +417,37 @@ For more information try --help More generally, you can validate and parse into any data type. +More generally, you can parse into any data type. + +[Example:](04_02_parse.rs) +```console +$ 04_02_parse_derive --help +clap [..] +A simple to use, efficient, and full-featured Command Line Argument Parser + +USAGE: + 04_02_parse_derive[EXE] + +ARGS: + Network port to use + +OPTIONS: + -h, --help Print help information + -V, --version Print version information + +$ 04_02_parse_derive 22 +PORT = 22 + +$ 04_02_parse_derive foobar +? failed +error: Invalid value "foobar" for '': invalid digit found in string + +For more information try --help + +``` + +A custom validator can be used to improve the error messages or provide additional validation: + [Example:](04_02_validate.rs) ```console $ 04_02_validate_derive --help @@ -436,9 +467,9 @@ OPTIONS: $ 04_02_validate_derive 22 PORT = 22 -$ 04_02_validate_derive foobar +$ 04_02_validate_derive 0 ? failed -error: Invalid value "foobar" for '': invalid digit found in string +error: Invalid value "0" for '': Port not in range 1-65535 For more information try --help