Skip to content

Commit 29b946f

Browse files
committed
docs(cookbook): Split up value parsers into sections
1 parent b043ed3 commit 29b946f

File tree

10 files changed

+281
-264
lines changed

10 files changed

+281
-264
lines changed

examples/typed-derive/builtin.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
Help:
2+
```console
3+
$ typed-derive builtin --help
4+
Usage: typed-derive builtin [OPTIONS]
5+
6+
Options:
7+
--port <PORT> Support for discrete numbers [default: 22] [possible values: 22, 80]
8+
--log-level <LOG_LEVEL> Support enums from a foreign crate that don't implement `ValueEnum` [default: info] [possible values: trace, debug, info, warn, error]
9+
-h, --help Print help
10+
11+
```
12+
13+
Discrete numbers
14+
```console
15+
$ typed-derive builtin --port 22
16+
Builtin(BuiltInParsers { port: 22, log_level: Info })
17+
18+
$ typed-derive builtin --port 80
19+
Builtin(BuiltInParsers { port: 80, log_level: Info })
20+
21+
$ typed-derive builtin --port
22+
? failed
23+
error: a value is required for '--port <PORT>' but none was supplied
24+
[possible values: 22, 80]
25+
26+
For more information, try '--help'.
27+
28+
$ typed-derive builtin --port 3000
29+
? failed
30+
error: invalid value '3000' for '--port <PORT>'
31+
[possible values: 22, 80]
32+
33+
For more information, try '--help'.
34+
35+
```
36+
37+
Enums from crates that can't implement `ValueEnum`
38+
```console
39+
$ typed-derive builtin --log-level debug
40+
Builtin(BuiltInParsers { port: 22, log_level: Debug })
41+
42+
$ typed-derive builtin --log-level error
43+
Builtin(BuiltInParsers { port: 22, log_level: Error })
44+
45+
$ typed-derive builtin --log-level
46+
? failed
47+
error: a value is required for '--log-level <LOG_LEVEL>' but none was supplied
48+
[possible values: trace, debug, info, warn, error]
49+
50+
For more information, try '--help'.
51+
52+
$ typed-derive builtin --log-level critical
53+
? failed
54+
error: invalid value 'critical' for '--log-level <LOG_LEVEL>'
55+
[possible values: trace, debug, info, warn, error]
56+
57+
For more information, try '--help'.
58+
59+
```

examples/typed-derive/builtin.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use clap::builder::TypedValueParser as _;
2+
use clap::Args;
3+
4+
use crate::foreign_crate;
5+
6+
#[derive(Args, Debug)]
7+
pub(crate) struct BuiltInParsers {
8+
/// Support for discrete numbers
9+
#[arg(
10+
long,
11+
default_value_t = 22,
12+
value_parser = clap::builder::PossibleValuesParser::new(["22", "80"])
13+
.map(|s| s.parse::<usize>().unwrap()),
14+
)]
15+
port: usize,
16+
17+
/// Support enums from a foreign crate that don't implement `ValueEnum`
18+
#[arg(
19+
long,
20+
default_value_t = foreign_crate::LogLevel::Info,
21+
value_parser = clap::builder::PossibleValuesParser::new(["trace", "debug", "info", "warn", "error"])
22+
.map(|s| s.parse::<foreign_crate::LogLevel>().unwrap()),
23+
)]
24+
log_level: foreign_crate::LogLevel,
25+
}

examples/typed-derive/fn_parser.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Help:
2+
```console
3+
$ typed-derive fn-parser --help
4+
Usage: typed-derive fn-parser [OPTIONS]
5+
6+
Options:
7+
-D <DEFINES> Hand-written parser for tuples
8+
-h, --help Print help
9+
10+
```
11+
12+
Defines (key-value pairs)
13+
```console
14+
$ typed-derive fn-parser -D Foo=10 -D Alice=30
15+
FnParser(FnParser { defines: [("Foo", 10), ("Alice", 30)] })
16+
17+
$ typed-derive fn-parser -D Foo
18+
? failed
19+
error: invalid value 'Foo' for '-D <DEFINES>': invalid KEY=value: no `=` found in `Foo`
20+
21+
For more information, try '--help'.
22+
23+
$ typed-derive fn-parser -D Foo=Bar
24+
? failed
25+
error: invalid value 'Foo=Bar' for '-D <DEFINES>': invalid digit found in string
26+
27+
For more information, try '--help'.
28+
29+
```

examples/typed-derive/fn_parser.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use std::error::Error;
2+
3+
use clap::Args;
4+
5+
#[derive(Args, Debug)]
6+
pub(crate) struct FnParser {
7+
/// Hand-written parser for tuples
8+
#[arg(short = 'D', value_parser = parse_key_val::<String, i32>)]
9+
defines: Vec<(String, i32)>,
10+
}
11+
12+
/// Parse a single key-value pair
13+
fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error + Send + Sync + 'static>>
14+
where
15+
T: std::str::FromStr,
16+
T::Err: Error + Send + Sync + 'static,
17+
U: std::str::FromStr,
18+
U::Err: Error + Send + Sync + 'static,
19+
{
20+
let pos = s
21+
.find('=')
22+
.ok_or_else(|| format!("invalid KEY=value: no `=` found in `{s}`"))?;
23+
Ok((s[..pos].parse()?, s[pos + 1..].parse()?))
24+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
2+
pub(crate) enum LogLevel {
3+
Trace,
4+
Debug,
5+
Info,
6+
Warn,
7+
Error,
8+
}
9+
10+
impl std::fmt::Display for LogLevel {
11+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12+
let s = match self {
13+
Self::Trace => "trace",
14+
Self::Debug => "debug",
15+
Self::Info => "info",
16+
Self::Warn => "warn",
17+
Self::Error => "error",
18+
};
19+
s.fmt(f)
20+
}
21+
}
22+
impl std::str::FromStr for LogLevel {
23+
type Err = String;
24+
25+
fn from_str(s: &str) -> Result<Self, Self::Err> {
26+
match s {
27+
"trace" => Ok(Self::Trace),
28+
"debug" => Ok(Self::Debug),
29+
"info" => Ok(Self::Info),
30+
"warn" => Ok(Self::Warn),
31+
"error" => Ok(Self::Error),
32+
_ => Err(format!("Unknown log level: {s}")),
33+
}
34+
}
35+
}

examples/typed-derive/implicit.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
Help:
2+
```console
3+
$ typed-derive implicit --help
4+
Usage: typed-derive implicit [OPTIONS]
5+
6+
Options:
7+
-O <OPTIMIZATION> Implicitly using `std::str::FromStr`
8+
-I <DIR> Allow invalid UTF-8 paths
9+
--bind <BIND> Handle IP addresses
10+
--sleep <SLEEP> Allow human-readable durations
11+
-h, --help Print help
12+
13+
```
14+
15+
Optimization-level (number)
16+
```console
17+
$ typed-derive implicit -O 1
18+
Implicit(ImplicitParsers { optimization: Some(1), include: None, bind: None, sleep: None })
19+
20+
$ typed-derive implicit -O plaid
21+
? failed
22+
error: invalid value 'plaid' for '-O <OPTIMIZATION>': invalid digit found in string
23+
24+
For more information, try '--help'.
25+
26+
```
27+
28+
Include (path)
29+
```console
30+
$ typed-derive implicit -I../hello
31+
Implicit(ImplicitParsers { optimization: None, include: Some("../hello"), bind: None, sleep: None })
32+
33+
```
34+
35+
IP Address
36+
```console
37+
$ typed-derive implicit --bind 192.0.0.1
38+
Implicit(ImplicitParsers { optimization: None, include: None, bind: Some(192.0.0.1), sleep: None })
39+
40+
$ typed-derive implicit --bind localhost
41+
? failed
42+
error: invalid value 'localhost' for '--bind <BIND>': invalid IP address syntax
43+
44+
For more information, try '--help'.
45+
46+
```
47+
48+
Time
49+
```console
50+
$ typed-derive implicit --sleep 10s
51+
Implicit(ImplicitParsers { optimization: None, include: None, bind: None, sleep: Some(10s) })
52+
53+
$ typed-derive implicit --sleep forever
54+
? failed
55+
error: invalid value 'forever' for '--sleep <SLEEP>': failed to parse "forever" in the "friendly" format: parsing a friendly duration requires it to start with a unit value (a decimal integer) after an optional sign, but no integer was found
56+
57+
For more information, try '--help'.
58+
59+
```

examples/typed-derive/implicit.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use clap::Args;
2+
3+
#[derive(Args, Debug)]
4+
pub(crate) struct ImplicitParsers {
5+
/// Implicitly using `std::str::FromStr`
6+
#[arg(short = 'O')]
7+
optimization: Option<usize>,
8+
9+
/// Allow invalid UTF-8 paths
10+
#[arg(short = 'I', value_name = "DIR", value_hint = clap::ValueHint::DirPath)]
11+
include: Option<std::path::PathBuf>,
12+
13+
/// Handle IP addresses
14+
#[arg(long)]
15+
bind: Option<std::net::IpAddr>,
16+
17+
/// Allow human-readable durations
18+
#[arg(long)]
19+
sleep: Option<jiff::SignedDuration>,
20+
}

examples/typed-derive/main.rs

Lines changed: 8 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,16 @@
1-
use clap::builder::TypedValueParser as _;
2-
use clap::Args;
31
use clap::Parser;
4-
use std::error::Error;
2+
3+
mod builtin;
4+
mod fn_parser;
5+
mod foreign_crate;
6+
mod implicit;
57

68
#[derive(Parser, Debug)] // requires `derive` feature
79
#[command(term_width = 0)] // Just to make testing across clap features easier
810
enum Cli {
9-
Implicit(ImplicitParsers),
10-
Builtin(BuiltInParsers),
11-
FnParser(FnParser),
12-
}
13-
14-
#[derive(Args, Debug)]
15-
struct ImplicitParsers {
16-
/// Implicitly using `std::str::FromStr`
17-
#[arg(short = 'O')]
18-
optimization: Option<usize>,
19-
20-
/// Allow invalid UTF-8 paths
21-
#[arg(short = 'I', value_name = "DIR", value_hint = clap::ValueHint::DirPath)]
22-
include: Option<std::path::PathBuf>,
23-
24-
/// Handle IP addresses
25-
#[arg(long)]
26-
bind: Option<std::net::IpAddr>,
27-
28-
/// Allow human-readable durations
29-
#[arg(long)]
30-
sleep: Option<jiff::SignedDuration>,
31-
}
32-
33-
#[derive(Args, Debug)]
34-
struct BuiltInParsers {
35-
/// Support for discrete numbers
36-
#[arg(
37-
long,
38-
default_value_t = 22,
39-
value_parser = clap::builder::PossibleValuesParser::new(["22", "80"])
40-
.map(|s| s.parse::<usize>().unwrap()),
41-
)]
42-
port: usize,
43-
44-
/// Support enums from a foreign crate that don't implement `ValueEnum`
45-
#[arg(
46-
long,
47-
default_value_t = foreign_crate::LogLevel::Info,
48-
value_parser = clap::builder::PossibleValuesParser::new(["trace", "debug", "info", "warn", "error"])
49-
.map(|s| s.parse::<foreign_crate::LogLevel>().unwrap()),
50-
)]
51-
log_level: foreign_crate::LogLevel,
52-
}
53-
54-
#[derive(Args, Debug)]
55-
struct FnParser {
56-
/// Hand-written parser for tuples
57-
#[arg(short = 'D', value_parser = parse_key_val::<String, i32>)]
58-
defines: Vec<(String, i32)>,
59-
}
60-
61-
/// Parse a single key-value pair
62-
fn parse_key_val<T, U>(s: &str) -> Result<(T, U), Box<dyn Error + Send + Sync + 'static>>
63-
where
64-
T: std::str::FromStr,
65-
T::Err: Error + Send + Sync + 'static,
66-
U: std::str::FromStr,
67-
U::Err: Error + Send + Sync + 'static,
68-
{
69-
let pos = s
70-
.find('=')
71-
.ok_or_else(|| format!("invalid KEY=value: no `=` found in `{s}`"))?;
72-
Ok((s[..pos].parse()?, s[pos + 1..].parse()?))
73-
}
74-
75-
mod foreign_crate {
76-
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
77-
pub(crate) enum LogLevel {
78-
Trace,
79-
Debug,
80-
Info,
81-
Warn,
82-
Error,
83-
}
84-
85-
impl std::fmt::Display for LogLevel {
86-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87-
let s = match self {
88-
Self::Trace => "trace",
89-
Self::Debug => "debug",
90-
Self::Info => "info",
91-
Self::Warn => "warn",
92-
Self::Error => "error",
93-
};
94-
s.fmt(f)
95-
}
96-
}
97-
impl std::str::FromStr for LogLevel {
98-
type Err = String;
99-
100-
fn from_str(s: &str) -> Result<Self, Self::Err> {
101-
match s {
102-
"trace" => Ok(Self::Trace),
103-
"debug" => Ok(Self::Debug),
104-
"info" => Ok(Self::Info),
105-
"warn" => Ok(Self::Warn),
106-
"error" => Ok(Self::Error),
107-
_ => Err(format!("Unknown log level: {s}")),
108-
}
109-
}
110-
}
11+
Implicit(implicit::ImplicitParsers),
12+
Builtin(builtin::BuiltInParsers),
13+
FnParser(fn_parser::FnParser),
11114
}
11215

11316
fn main() {

0 commit comments

Comments
 (0)