docs(tutorial): Demonstrate custom parsing

Adds a more in depth validator to validate that the port is in range in the derive and builder tutorial (section 4.2).

This supersedes #3416
This commit is contained in:
josh rotenberg 2022-02-07 20:50:39 -08:00 committed by Ed Page
parent 1b5f9e6450
commit ee3eab1614
7 changed files with 143 additions and 11 deletions

View file

@ -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"

View file

@ -0,0 +1,17 @@
use clap::{app_from_crate, arg};
fn main() {
let matches = app_from_crate!()
.arg(
arg!(<PORT>)
.help("Network port to use")
.validator(|s| s.parse::<usize>()),
)
.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);
}

View file

@ -1,12 +1,24 @@
use clap::{app_from_crate, arg};
use std::ops::RangeInclusive;
use std::str::FromStr;
const PORT_RANGE: RangeInclusive<usize> = 1..=65535;
fn main() {
let matches = app_from_crate!()
.arg(
arg!(<PORT>)
.help("Network port to use")
.validator(|s| s.parse::<usize>()),
)
.arg(arg!(<PORT>).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

View file

@ -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] <PORT>
ARGS:
<PORT> 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 '<PORT>': 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 '<PORT>': invalid digit found in string
error: Invalid value "0" for '<PORT>': Port not in range 1-65535
For more information try --help

View file

@ -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);
}

View file

@ -1,10 +1,14 @@
use clap::Parser;
use std::ops::RangeInclusive;
use std::str::FromStr;
const PORT_RANGE: RangeInclusive<usize> = 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()
)),
})
}

View file

@ -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] <PORT>
ARGS:
<PORT> 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 '<PORT>': 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 '<PORT>': invalid digit found in string
error: Invalid value "0" for '<PORT>': Port not in range 1-65535
For more information try --help