docs(cookbook): Add position-sensitive example

This commit is contained in:
Ed Page 2022-08-15 10:40:20 -05:00
parent 7486a0b4b9
commit 9c9cc9fcff
5 changed files with 162 additions and 0 deletions

View file

@ -126,6 +126,10 @@ required-features = ["cargo"]
name = "escaped-positional-derive" name = "escaped-positional-derive"
required-features = ["derive"] required-features = ["derive"]
[[example]]
name = "find"
required-features = ["cargo"]
[[example]] [[example]]
name = "git-derive" name = "git-derive"
required-features = ["derive"] required-features = ["derive"]

47
examples/find.md Normal file
View file

@ -0,0 +1,47 @@
`find` is an example of position-sensitive flags
```console
$ find --help
clap 4.0.0-alpha.0
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
find[EXE] [OPTIONS] --name <NAME>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
TESTS:
--empty File is empty and is either a regular file or a directory
--name <NAME> Base of file name (the path with the leading directories removed) matches
shell pattern pattern
OPERATORS:
-o, --or expr2 is not evaluate if exp1 is true
-a, --and Same as `expr1 expr1`
$ find --empty -o --name .keep
[
(
"empty",
Bool(
true,
),
),
(
"or",
Bool(
true,
),
),
(
"name",
String(
".keep",
),
),
]
```

99
examples/find.rs Normal file
View file

@ -0,0 +1,99 @@
use std::collections::BTreeMap;
use clap::{arg, command, ArgGroup, ArgMatches, Command};
fn main() {
let matches = cli().get_matches();
let values = Value::from_matches(&matches);
println!("{:#?}", values);
}
fn cli() -> Command<'static> {
command!()
.group(ArgGroup::new("tests").multiple(true))
.next_help_heading("TESTS")
.args([
arg!(--empty "File is empty and is either a regular file or a directory").group("tests"),
arg!(--name <NAME> "Base of file name (the path with the leading directories removed) matches shell pattern pattern").group("tests"),
])
.group(ArgGroup::new("operators").multiple(true))
.next_help_heading("OPERATORS")
.args([
arg!(-o - -or "expr2 is not evaluate if exp1 is true").group("operators"),
arg!(-a - -and "Same as `expr1 expr1`").group("operators"),
])
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Value {
Bool(bool),
String(String),
}
impl Value {
pub fn from_matches(matches: &ArgMatches) -> Vec<(clap::Id, Self)> {
let mut values = BTreeMap::new();
for id in matches.ids() {
if matches.try_get_many::<clap::Id>(id.as_str()).is_ok() {
// ignore groups
continue;
}
let value_source = matches
.value_source(id.as_str())
.expect("id came from matches");
if value_source != clap::parser::ValueSource::CommandLine {
// Any other source just gets tacked on at the end (like default values)
continue;
}
if Self::extract::<String>(matches, id, &mut values) {
continue;
}
if Self::extract::<bool>(matches, id, &mut values) {
continue;
}
unimplemented!("unknown type for {}: {:?}", id, matches);
}
values.into_values().collect::<Vec<_>>()
}
fn extract<T: Clone + Into<Value> + Send + Sync + 'static>(
matches: &ArgMatches,
id: &clap::Id,
output: &mut BTreeMap<usize, (clap::Id, Self)>,
) -> bool {
match matches.try_get_many::<T>(id.as_str()) {
Ok(Some(values)) => {
for (value, index) in values.zip(
matches
.indices_of(id.as_str())
.expect("id came from matches"),
) {
output.insert(index, (id.clone(), value.clone().into()));
}
true
}
Ok(None) => {
unreachable!("`ids` only reports what is present")
}
Err(clap::parser::MatchesError::UnknownArgument { .. }) => {
unreachable!("id came from matches")
}
Err(clap::parser::MatchesError::Downcast { .. }) => false,
Err(_) => {
unreachable!("id came from matches")
}
}
}
}
impl From<String> for Value {
fn from(other: String) -> Self {
Self::String(other)
}
}
impl From<bool> for Value {
fn from(other: bool) -> Self {
Self::Bool(other)
}
}

7
src/_cookbook/find.rs Normal file
View file

@ -0,0 +1,7 @@
//! # Example: find-like CLI (Builder API)
//!
//! ```rust
#![doc = include_str!("../../examples/find.rs")]
//! ```
//!
#![doc = include_str!("../../examples/find.md")]

View file

@ -16,6 +16,10 @@
//! - Subcommands //! - Subcommands
//! - Cargo plugins //! - Cargo plugins
//! //!
//! find-like interface: [builder][find]
//! - Topics:
//! - Position-sensitive flags
//!
//! git-like interface: [builder][git], [derive][git_derive] //! git-like interface: [builder][git], [derive][git_derive]
//! - Topics: //! - Topics:
//! - Subcommands //! - Subcommands
@ -46,6 +50,7 @@ pub mod cargo_example;
pub mod cargo_example_derive; pub mod cargo_example_derive;
pub mod escaped_positional; pub mod escaped_positional;
pub mod escaped_positional_derive; pub mod escaped_positional_derive;
pub mod find;
pub mod git; pub mod git;
pub mod git_derive; pub mod git_derive;
pub mod multicall_busybox; pub mod multicall_busybox;