Merge pull request #21 from epage/trycmd

test: More thoroughly test examples
This commit is contained in:
Ed Page 2021-11-23 13:24:22 -06:00 committed by GitHub
commit 0fccd07001
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 886 additions and 197 deletions

View file

@ -125,6 +125,8 @@ regex = "1.0"
lazy_static = "1"
version-sync = "0.9"
criterion = "0.3.2"
# Cutting out `filesystem` feature
trycmd = { version = "0.8.0", default-features = false, features = ["color-auto", "diff", "examples"] }
[[example]]
name = "busybox"

View file

@ -0,0 +1,40 @@
This example shows how to create an application with several arguments using usage strings
Let's first check out the help:
```bash
$ 01a_quick_example --help
MyApp 1.0
Kevin K. <kbknapp@gmail.com>
Does awesome things
USAGE:
01a_quick_example[EXE] [OPTIONS] [output] [SUBCOMMAND]
ARGS:
<output> Sets an optional output file
OPTIONS:
-c, --config <FILE> Sets a custom config file
-d, --debug Turn debugging information on
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
test does testing things
```
By default, the program does nothing:
```bash
$ 01a_quick_example
Debug mode is off
```
But you can mix and match the various features
```bash
$ 01a_quick_example -dd test
Debug mode is on
Not printing testing lists...
```

View file

@ -0,0 +1,40 @@
This method shows the traditional, and slightly more configurable way to set up arguments.
Let's first check out the help:
```bash
$ 01b_quick_example --help
MyApp 1.0
Kevin K. <kbknapp@gmail.com>
Does awesome things
USAGE:
01b_quick_example[EXE] [OPTIONS] [output] [SUBCOMMAND]
ARGS:
<output> Sets an optional output file
OPTIONS:
-c, --config <FILE> Sets a custom config file
-d, --debug Turn debugging information on
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
test does testing things
```
By default, the program does nothing:
```bash
$ 01b_quick_example
Debug mode is off
```
But you can mix and match the various features
```bash
$ 01b_quick_example -dd test
Debug mode is on
Not printing testing lists...
```

24
examples/02_apps.md Normal file
View file

@ -0,0 +1,24 @@
Apps describe the top level application
You can see this in the help:
```bash
$ 02_apps --help
MyApp 1.0
Kevin K. <kbknapp@gmail.com>
Does awesome things
USAGE:
02_apps[EXE]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
```
And among the version
```bash
$ 02_apps --version
MyApp 1.0
```

View file

@ -1,8 +1,6 @@
use clap::App;
fn main() {
// Apps describe the top level application
//
// You create an App and set various options on that App using the "builder pattern"
//
// The options (version(), author(), about()) aren't mandatory, but recommended. There is

29
examples/03_args.md Normal file
View file

@ -0,0 +1,29 @@
Args describe a possible valid argument which may be supplied by the user at runtime. There
are three different types of arguments (flags, options, and positional) as well as a fourth
special type of argument, called Subcommands (which will be discussed separately).
# Help and Version
`clap` automatically generates a help and version flag for you, unless you specify your
own. By default help uses "-h" and "--help", and version uses "-V" and "--version". You can
safely override "-V" and "-h" to your own arguments, and "--help" and "--version" will still
be automatically generated for you.
```bash
$ 03_args --help
MyApp
USAGE:
03_args[EXE] [OPTIONS] <input> [output]
ARGS:
<input> the input file to use
<output> Supply an output file to use
OPTIONS:
-c, --config <config> sets the config file to use
-d turn on debugging information
-h, --help Print help information
-i, --int <IFACE> Set an interface to use
--license display the license file
```

View file

@ -1,10 +1,6 @@
use clap::{arg, App, Arg};
fn main() {
// Args describe a possible valid argument which may be supplied by the user at runtime. There
// are three different types of arguments (flags, options, and positional) as well as a fourth
// special type of argument, called Subcommands (which will be discussed separately).
//
// Args are described in the same manner as Apps using the "builder pattern" with multiple
// methods describing various settings for the individual arguments. Or by supplying a "usage"
// string. Both methods have their pros and cons.
@ -16,12 +12,6 @@ fn main() {
// three types of arguments, some only apply one or two of the types. *NOTE* if you set
// incompatible options on a single argument, clap will panic! at runtime. This is by design,
// so that you know right away an error was made by the developer, not the end user.
//
// # Help and Version
// clap automatically generates a help and version flag for you, unless you specify your
// own. By default help uses "-h" and "--help", and version uses "-V" and "--version". You can
// safely override "-V" and "-h" to your own arguments, and "--help" and "--version" will still
// be automatically generated for you.
let matches = App::new("MyApp")
// All application settings go here...
// A simple "Flag" argument example (i.e. "-d") using the builder pattern

View file

@ -0,0 +1,15 @@
Once all App settings (including all arguments) have been set, you call get_matches() which
parses the string provided by the user, and returns all the valid matches to the ones you
specified.
For example:
```bash
$ 04_using_matches input
Doing real work with file: input
$ 04_using_matches input --debug
Debugging is turned on
Doing real work with file: input
$ 04_using_matches input --config path
Using config file: path
Doing real work with file: input
```

62
examples/05_flag_args.md Normal file
View file

@ -0,0 +1,62 @@
Of the three argument types, flags are the most simple. Flags are simple switches which can
be either "on" or "off"
`clap` also supports multiple occurrences of flags, the common example is "verbosity" where a
user could want a little information with "-v" or tons of information with "-v -v" or "-vv"
Let's look at their help:
```bash
$ 05_flag_args --help
MyApp
USAGE:
05_flag_args[EXE] [OPTIONS] [output]
ARGS:
<output> sets an output file
OPTIONS:
-a, --awesome turns up the awesome
-c, --config <FILE> sets a custom config file
-h, --help Print help information
```
By default, nothing happens:
```bash
$ 05_flag_args
Nothing is awesome
```
Note that `--awesome` places requirements on how other flags are used:
```bash
$ 05_flag_args --awesome
? failed
error: The following required arguments were not provided:
--config <FILE>
USAGE:
05_flag_args[EXE] --config <FILE> --awesome
For more information try --help
$ 05_flag_args output.txt --config file.toml --awesome
? failed
error: The argument '--awesome' cannot be used with '<output>'
USAGE:
05_flag_args[EXE] --config <FILE> <output>
For more information try --help
```
You can then add `--awesome` as many times as you like:
```bash
$ 05_flag_args --config file.toml --awesome
Awesomeness is turned on
Some things are awesome
$ 05_flag_args --config file.toml --awesome --awesome
Awesomeness is turned on
Lots of things are awesome
$ 05_flag_args --config file.toml -aaaaaaaaaaaaaaaaaa
Awesomeness is turned on
EVERYTHING is awesome!
```

View file

@ -1,11 +1,6 @@
use clap::{arg, App, Arg};
fn main() {
// Of the three argument types, flags are the most simple. Flags are simple switches which can
// be either "on" or "off"
//
// clap also supports multiple occurrences of flags, the common example is "verbosity" where a
// user could want a little information with "-v" or tons of information with "-v -v" or "-vv"
let matches = App::new("MyApp")
// Regular App configuration goes here...
// We'll add a flag that represents an awesome meter...

View file

@ -0,0 +1,53 @@
Positional arguments are those values after the program name which are not preceded by any
identifier (such as "myapp some_file"). Positionals support many of the same options as
flags, as well as a few additional ones.
Let's look at their help:
```bash
$ 06_positional_args --help
MyApp
USAGE:
06_positional_args[EXE] <input> [config]
ARGS:
<input> the input file to use
<config> the config file to use
OPTIONS:
-h, --help Print help information
```
First, we see that the first argument is required:
```
$ 06_positional_args
? failed
error: The following required arguments were not provided:
<input>
<config>
USAGE:
06_positional_args[EXE] <input> [config]
For more information try --help
```
That first argument causes the second to be required:
```
$ 06_positional_args input.txt
? failed
error: The following required arguments were not provided:
<config>
USAGE:
06_positional_args[EXE] <input> <config> [config]
For more information try --help
```
Everything works now that we specify both:
```
$ 06_positional_args input.txt config.toml
An input file was specified
Doing work with input.txt and config.toml
```

View file

@ -1,9 +1,6 @@
use clap::{App, Arg};
fn main() {
// Positional arguments are those values after the program name which are not preceded by any
// identifier (such as "myapp some_file"). Positionals support many of the same options as
// flags, as well as a few additional ones.
let matches = App::new("MyApp")
// Regular App configuration goes here...
// We'll add two positional arguments, an input file, and a config file.

View file

@ -0,0 +1,77 @@
Option arguments are those that take an additional value, such as "-c value". In clap they
support three types of specification, those with short() as "-o some", or those with long()
as "--option value" or "--option=value"
Options also support a multiple setting, which is discussed in the example below.
Let's look at their help:
```bash
$ 07_option_args --help
MyApp
USAGE:
07_option_args[EXE] [OPTIONS] --input <input> [output]
ARGS:
<output> the output file to use
OPTIONS:
-c, --config <FILE> the config file to use
-h, --help Print help information
-i, --input <input> the input file to use
```
First, we see that `--input` is required:
```bash
$ 07_option_args
? failed
error: The following required arguments were not provided:
--config <FILE>
--input <input>
USAGE:
07_option_args[EXE] [OPTIONS] --input <input> [output]
For more information try --help
```
But `--input` also requires `--config`:
```bash
$ 07_option_args --input input.txt --input another.txt
? failed
error: The following required arguments were not provided:
--config <FILE>
USAGE:
07_option_args[EXE] [OPTIONS] --input <input> --config <FILE> [output]
For more information try --help
```
Everything works now that we specify both:
```bash
$ 07_option_args --input input.txt --input another.txt --config config.toml
An input file was specified
An input file: input.txt
An input file: input.txt
An input file: another.txt
The "input" argument was used 2 times
```
But we can't mix this with output:
```bash
$ 07_option_args --input input.txt --input another.txt --config config.toml output.txt
? failed
error: The argument '<output>' cannot be used with '--input <input>'
USAGE:
07_option_args[EXE] --input <input> --input <input> --config <FILE>
For more information try --help
```
That requires passing it in by itself:
```bash
$ 07_option_args output.txt
The "input" argument was used 0 times
```

View file

@ -1,11 +1,6 @@
use clap::{arg, App, Arg};
fn main() {
// Option arguments are those that take an additional value, such as "-c value". In clap they
// support three types of specification, those with short() as "-o some", or those with long()
// as "--option value" or "--option=value"
//
// Options also support a multiple setting, which is discussed in the example below.
let matches = App::new("MyApp")
// Regular App configuration goes here...
// Assume we have an application that accepts an input file via the "-i file"

View file

@ -0,0 +1,61 @@
Subcommands function exactly like sub-Apps, because that's exactly what they are. Each
instance of a Subcommand can have its own version, author(s), Args, and even its own
subcommands.
Just like Apps, each subcommand will get its own "help" and "version" flags automatically
generated. Also, like Apps, you can override "-V" or "-h" safely and still get "--help" and
"--version" auto generated.
**NOTE:** If you specify a subcommand for your App, clap will also autogenerate a "help"
subcommand along with "-h" and "--help" (applies to sub-subcommands as well).
```bash
$ 08_subcommands help
MyApp 1.0
USAGE:
08_subcommands[EXE] [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
add Adds files to myapp
help Print this message or the help of the given subcommand(s)
$ 08_subcommands help add
08_subcommands[EXE]-add 0.1
Kevin K.
Adds files to myapp
USAGE:
08_subcommands[EXE] add <input>
ARGS:
<input> the file to add
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 08_subcommands add help
'myapp add' was used, input is: help
```
```bash
$ 08_subcommands --version
MyApp 1.0
```
Without any subcommand:
```bash
$ 08_subcommands
No subcommand was used
```
And with:
```bash
$ 08_subcommands add input.txt
'myapp add' was used, input is: input.txt
```

View file

@ -1,21 +1,10 @@
use clap::{App, Arg};
fn main() {
// Subcommands function exactly like sub-Apps, because that's exactly what they are. Each
// instance of a Subcommand can have its own version, author(s), Args, and even its own
// subcommands.
//
// # Help and Version
// Just like Apps, each subcommand will get its own "help" and "version" flags automatically
// generated. Also, like Apps, you can override "-V" or "-h" safely and still get "--help" and
// "--version" auto generated.
//
// NOTE: If you specify a subcommand for your App, clap will also autogenerate a "help"
// subcommand along with "-h" and "--help" (applies to sub-subcommands as well).
//
// Just like arg() and args(), subcommands can be specified one at a time via subcommand() or
// multiple ones at once with a Vec<App> provided to subcommands().
let matches = App::new("MyApp")
.version("1.0")
// Normal App and Arg configuration goes here...
// In the following example assume we wanted an application which
// supported an "add" subcommand, this "add" subcommand also took

View file

@ -0,0 +1,21 @@
You can have clap pull the application metadata directly from your Cargo.toml using the
`app_from_crate!()` macro.
```bash
$ 09_cargo_metadata --help
clap 3.0.0-beta.5
Kevin K. <kbknapp@gmail.com>:Clap Maintainers
A simple to use, efficient, and full-featured Command Line Argument Parser
USAGE:
09_cargo_metadata[EXE]
OPTIONS:
-h, --help Print help information
-V, --version Print version information
$ 09_cargo_metadata --version
...
```
*(censored to keep the release process easy)*

View file

@ -0,0 +1,30 @@
Using `Arg::default_value`, rather than `Option::unwrap_or`, gives clap more information it can use with our argument.
For example, let's look at the help:
```bash
$ 10_default_values --help
myapp
does awesome things
USAGE:
10_default_values[EXE] [OPTIONS] [INPUT]
ARGS:
<INPUT> The input file to use [default: input.txt]
OPTIONS:
-c <CONFIG> The config file to use
-h, --help Print help information
```
`<INPUT>`'s description says what the default is while `-c`'s does not.
Otherwise, they'll work the same:
```bash
$ 10_default_values
The input file is: input.txt
The config file is: config.json
$ 10_default_values other.txt -c other.toml
The input file is: other.txt
The config file is: other.toml
```

View file

@ -1,12 +1,6 @@
use clap::{App, Arg};
fn main() {
// There are two ways in which to get a default value, one is to use clap's Arg::default_value
// method, and the other is to use Rust's built in Option::unwrap_or method.
//
// I'll demo both here.
//
// First, we'll use clap's Arg::default_value with an "INPUT" file.
let matches = App::new("myapp")
.about("does awesome things")
.arg(

View file

@ -0,0 +1,48 @@
If you have arguments of specific values you want to test for, you can use the
.possible_values() method of Arg
This allows you specify the valid values for that argument. If the user does not use one of
those specific values, they will receive a graceful exit with error message informing them
of the mistake, and what the possible valid values are
For this example, assume you want one positional argument of either "fast" or "slow"
i.e. the only possible ways to run the program are "myprog fast" or "myprog slow"
```bash
$ 11_only_specific_values fast
Hare
$ 11_only_specific_values slow
Tortoise
```
Anything else will error, guiding the user to a valid value:
```bash
$ 11_only_specific_values medium
? failed
error: "medium" isn't a valid value for '<MODE>'
[possible values: fast, slow]
USAGE:
11_only_specific_values[EXE] <MODE>
For more information try --help
```
Valid values also get shown in the help:
```bash
$ 11_only_specific_values --help
myapp
does awesome things
USAGE:
11_only_specific_values[EXE] <MODE>
ARGS:
<MODE> What mode to run the program in [possible values: fast, slow]
OPTIONS:
-h, --help Print help information
```
For integrating this with enums, see [13_enum_values](13_enum_values.md)

View file

@ -1,15 +1,6 @@
use clap::{App, Arg};
fn main() {
// If you have arguments of specific values you want to test for, you can use the
// .possible_values() method of Arg
//
// This allows you specify the valid values for that argument. If the user does not use one of
// those specific values, they will receive a graceful exit with error message informing them
// of the mistake, and what the possible valid values are
//
// For this example, assume you want one positional argument of either "fast" or "slow"
// i.e. the only possible ways to run the program are "myprog fast" or "myprog slow"
let matches = App::new("myapp")
.about("does awesome things")
.arg(

View file

@ -0,0 +1,32 @@
You can use some convenience methods provided by clap to get typed values, so long as the
type you're converting into implements std::str::FromStr
This works for both single, and multiple values (multiple values returns a Vec<T>)
When getting a typed value, a Result is returned which allows you decide what to do upon a failure, whether exit, provide a
default value, etc. You have control. But it also means you have to write the code or boiler plate
to handle those instances.
For example, you could exit:
```bash
$ 12_typed_values 1 2 3
Sequence part 1 + 2: 3
Sequence part 2 + 2: 4
Sequence part 3 + 2: 5
len (10) + 2 = 12
$ 12_typed_values 1 2 3 four
? failed
error: Invalid value for 'seq': The argument 'four' isn't a valid value: invalid digit found in string
```
Or provide a fallback:
```bash
$ 12_typed_values 1 -l 3
Sequence part 1 + 2: 3
len (3) + 2 = 5
$ 12_typed_values 1 -l four
Sequence part 1 + 2: 3
len (10) + 2 = 12
```
Or you can have clap do the error reporting for you, see [15_custom_validator](15_custom_validator.md)

View file

@ -1,24 +1,6 @@
use clap::{arg, App};
fn main() {
// You can use some convenience methods provided by clap to get typed values, so long as the
// type you're converting into implements std::str::FromStr
//
// This works for both single, and multiple values (multiple values returns a Vec<T>)
//
// There are also two ways in which to get types, those where failures cause the program to exit
// with an error and usage string, and those which return a Result<T,String> or Result<Vec<T>,String>
// respectively. Both methods support single and multiple values.
//
// The method which returns a Result allows you decide what to do upon a failure, exit, provide a
// default value, etc. You have control. But it also means you have to write the code or boiler plate
// to handle those instances.
//
// That is why the second method exists, so you can simply get a T or Vec<T> back, or be sure the
// program will exit gracefully. The catch is, the second method should *only* be used on required
// arguments, because if the argument isn't found, it exits. Just FYI ;)
//
// The following example shows both methods.
let matches = App::new("myapp")
// Create two arguments, a required positional which accepts multiple values
// and an optional '-l value'

View file

@ -0,0 +1,37 @@
Building on [11_only_specific_values](11_only_specific_values.md), we will create an enum with 4 values, assign a positional argument
that accepts only one of those values, and use clap to parse the argument.
```bash
$ 13_enum_values Foo
Found a Foo
$ 13_enum_values Bar
Found a Bar
```
Anything else will error, guiding the user to a valid value:
```bash
$ 13_enum_values Alice
? failed
error: "Alice" isn't a valid value for '<type>'
[possible values: Bar, Baz, Foo, Qux]
USAGE:
13_enum_values[EXE] <type>
For more information try --help
```
Valid values also get shown in the help:
```bash
$ 13_enum_values --help
myapp
USAGE:
13_enum_values[EXE] <type>
ARGS:
<type> The type to use [possible values: Foo, Bar, Baz, Qux]
OPTIONS:
-h, --help Print help information
```

View file

@ -1,6 +1,3 @@
// In the following example we will create an enum with 4 values, assign a positional argument
// that accepts only one of those values, and use clap to parse the argument.
//
// Start with bringing the trait into scope.
use std::str::FromStr;

53
examples/14_groups.md Normal file
View file

@ -0,0 +1,53 @@
`ArgGroup`s are a family of related arguments and way for you to say, "Any of these arguments".
By placing arguments in a logical group, you can make easier requirement and exclusion rules
instead of having to list each individually, or when you want a rule to apply "any but not all"
arguments.
Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
present out of a given set. Imagine that you had multiple arguments, and you want one of them to
be required, but making all of them required isn't feasible because perhaps they conflict with
each other. For example, lets say that you were building an application where one could set a
given version number by supplying a string with an option argument, i.e. `--set-ver v1.2.3`, you
also wanted to support automatically using a previous version number and simply incrementing one
of the three numbers. So you create three flags `--major`, `--minor`, and `--patch`. All of
these arguments shouldn't be used at one time but you want to specify that *at least one* of
them is used. For this, you can create a group.
```bash
$ 14_groups
? failed
error: The following required arguments were not provided:
<--set-ver <ver>|--major|--minor|--patch>
USAGE:
14_groups[EXE] [OPTIONS] <--set-ver <ver>|--major|--minor|--patch> [INPUT_FILE]
For more information try --help
$ 14_groups --major
Version: 2.2.3
$ 14_groups --major --minor
? failed
error: The argument '--major' cannot be used with '--minor'
USAGE:
14_groups[EXE] [OPTIONS] <--set-ver <ver>|--major|--minor|--patch> [INPUT_FILE]
For more information try --help
```
You can also do things such as name an ArgGroup as a confliction or requirement, meaning any
of the arguments that belong to that group will cause a failure if present, or must present
respectively.
```bash
$ 14_groups --major -c config.toml
? failed
error: The following required arguments were not provided:
<INPUT_FILE|--spec-in <SPEC_IN>>
USAGE:
14_groups[EXE] -c <config> <--set-ver <ver>|--major|--minor|--patch> <INPUT_FILE|--spec-in <SPEC_IN>>
For more information try --help
$ 14_groups --major -c config.toml --spec-in input.txt
Version: 2.2.3
Doing work using input input.txt and config config.toml
```

View file

@ -1,25 +1,3 @@
/// `ArgGroup`s are a family of related arguments and way for you to say, "Any of these arguments".
/// By placing arguments in a logical group, you can make easier requirement and exclusion rules
/// instead of having to list each individually, or when you want a rule to apply "any but not all"
/// arguments.
///
/// For instance, you can make an entire ArgGroup required, this means that one (and *only* one)
/// argument. from that group must be present. Using more than one argument from an ArgGroup causes
/// a failure (graceful exit).
///
/// You can also do things such as name an ArgGroup as a confliction or requirement, meaning any
/// of the arguments that belong to that group will cause a failure if present, or must present
/// respectively.
///
/// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
/// present out of a given set. Imagine that you had multiple arguments, and you want one of them to
/// be required, but making all of them required isn't feasible because perhaps they conflict with
/// each other. For example, lets say that you were building an application where one could set a
/// given version number by supplying a string with an option argument, i.e. `--set-ver v1.2.3`, you
/// also wanted to support automatically using a previous version number and simply incrementing one
/// of the three numbers. So you create three flags `--major`, `--minor`, and `--patch`. All of
/// these arguments shouldn't be used at one time but you want to specify that *at least one* of
/// them is used. For this, you can create a group.
use clap::{arg, App, Arg, ArgGroup};
fn main() {

View file

@ -0,0 +1,15 @@
You can define a function (or a closure) to use as a validator to argument values. The
function must accept a `&str` and return `Result<(), String>` where `Err(String)` is the
message displayed to the user.
```bash
$ 15_custom_validator input.png
The .PNG file is: input.png
$ 15_custom_validator input.txt
? failed
error: Invalid value for '<input>': the file format must be png.
For more information try --help
```
This is especially useful when using [custom types](12_types_values.md).

View file

@ -1,10 +1,6 @@
use clap::{App, Arg};
fn main() {
// You can define a function (or a closure) to use as a validator to argument values. The
// function must accept a `&str` and return `Result<(), String>` where `Err(String)` is the
// message displayed to the user.
let matches = App::new("myapp")
// Application logic goes here...
.arg(

View file

@ -0,0 +1,52 @@
You can use `AppSettings` to change the application level behavior of clap. `app.setting()` function
takes `AppSettings` enum as argument. You can learn more about AppSettings in the
documentation, which also has examples on each setting.
This example will only show usage of one AppSettings setting. See documentation for more
information.
Something is required:
```bash
$ 16_app_settings
? failed
error: The following required arguments were not provided:
<input>
USAGE:
16_app_settings[EXE] <input>
16_app_settings[EXE] <SUBCOMMAND>
For more information try --help
```
It can either be an argument:
```bash
$ 16_app_settings input.txt
The input file is: input.txt
```
Or the `test` subcommand:
```bash
$ 16_app_settings test
The 'test' subcommand was used
```
And see what this looks like in the help:
```bash
$ 16_app_settings --help
myapp
USAGE:
16_app_settings[EXE] <input>
16_app_settings[EXE] <SUBCOMMAND>
ARGS:
<input> input file to use
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
test does some testing
```

View file

@ -1,13 +1,6 @@
use clap::{arg, App, AppSettings};
fn main() {
// You can use AppSettings to change the application level behavior of clap. .setting() function
// of App struct takes AppSettings enum as argument. You can learn more about AppSettings in the
// documentation, which also has examples on each setting.
//
// This example will only show usage of one AppSettings setting. See documentation for more
// information.
let matches = App::new("myapp")
.setting(AppSettings::SubcommandsNegateReqs)
// Negates requirement of parent command.

20
examples/21_aliases.md Normal file
View file

@ -0,0 +1,20 @@
Subcommands can also have aliases
```
$ 21_aliases --help
MyApp
USAGE:
21_aliases[EXE] [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
help Print this message or the help of the given subcommand(s)
ls Adds files to myapp
$ 21_aliases ls .
'myapp add' was used, input is: .
$ 21_aliases dir .
'myapp add' was used, input is: .
```

View file

@ -0,0 +1,54 @@
You can use `--` to escape further arguments.
Let's see what this looks like in the help:
```bash
$ 22_stop_parsing_with_-- --help
myprog
USAGE:
22_stop_parsing_with_--[EXE] [OPTIONS] [-- <slop>...]
ARGS:
<slop>...
OPTIONS:
-f
-h, --help Print help information
-p <pea>
```
Here is a baseline without any arguments:
```bash
$ 22_stop_parsing_with_--
-f used: false
-p's value: None
'slops' values: None
```
Notice that we can't pass positional arguments before `--`:
```bash
$ 22_stop_parsing_with_-- foo bar
? failed
error: Found argument 'foo' which wasn't expected, or isn't valid in this context
USAGE:
22_stop_parsing_with_--[EXE] [OPTIONS] [-- <slop>...]
For more information try --help
```
But you can after:
```bash
$ 22_stop_parsing_with_-- -f -p=bob -- sloppy slop slop
-f used: true
-p's value: Some("bob")
'slops' values: Some(["sloppy", "slop", "slop"])
```
As mentioned, the parser will directly pass everything through:
```bash
$ 22_stop_parsing_with_-- -- -f -p=bob sloppy slop slop
-f used: false
-p's value: None
'slops' values: Some(["-f", "-p=bob", "sloppy", "slop", "slop"])
```

View file

@ -0,0 +1,33 @@
This feature allows users of the app to pass subcommands in the fashion of short or long flags.
You may be familiar with it if you ever used [`pacman`](https://wiki.archlinux.org/index.php/pacman).
Some made up examples of what flag subcommands are:
Here, `-S` is a short flag subcommand:
```bash
$ 23_flag_subcommands_pacman -S package
Installing package...
```
Here `--sync` is a long flag subcommand:
```bash
$ 23_flag_subcommands_pacman --sync package
Installing package...
```
Now the short flag subcommand (`-S`) with a long flag:
```bash
$ 23_flag_subcommands_pacman -S --search name
Searching for name...
```
And the various forms of short flags that work:
```
$ 23_flag_subcommands_pacman -S -s name
Searching for name...
$ 23_flag_subcommands_pacman -Ss name
Searching for name...
```
*(users can "stack" short subcommands with short flags or with other short flag subcommands)*
**NOTE:** Keep in mind that subcommands, flags, and long flags are *case sensitive*: `-Q` and `-q` are different flags/subcommands. For example, you can have both `-Q` subcommand and `-q` flag, and they will be properly disambiguated.
Let's make a quick program to illustrate.

View file

@ -1,23 +1,3 @@
// This feature allows users of the app to pass subcommands in the fashion of short or long flags.
// You may be familiar with it if you ever used [`pacman`](https://wiki.archlinux.org/index.php/pacman).
// Some made up examples of what flag subcommands are:
//
// ```shell
// $ pacman -S
// ^--- short flag subcommand.
// $ pacman --sync
// ^--- long flag subcommand.
// $ pacman -Ss
// ^--- short flag subcommand followed by a short flag
// (users can "stack" short subcommands with short flags or with other short flag subcommands)
// $ pacman -S -s
// ^--- same as above
// $ pacman -S --sync
// ^--- short flag subcommand followed by a long flag
// ```
// NOTE: Keep in mind that subcommands, flags, and long flags are *case sensitive*: `-Q` and `-q` are different flags/subcommands. For example, you can have both `-Q` subcommand and `-q` flag, and they will be properly disambiguated.
// Let's make a quick program to illustrate.
use clap::{App, AppSettings, Arg};
fn main() {

View file

@ -0,0 +1,40 @@
Example of a busybox-style multicall program
See the documentation for clap::AppSettings::Multicall for rationale.
This example omits every command except true and false,
which are the most trivial to implement,
```bash
$ busybox true
? 0
$ busybox false
? 1
```
*Note: without the links setup, we can't demonostrate the multicall behavior*
But includes the `--install` option as an example of why it can be useful
for the main program to take arguments that aren't applet subcommands.
```bash
$ busybox --install
? failed
...
```
Though users must pass something:
```bash
$ busybox
? failed
busybox
USAGE:
busybox[EXE] [OPTIONS] [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
--install <install> Install hardlinks for all subcommands in path
SUBCOMMANDS:
false does nothing unsuccessfully
help Print this message or the help of the given subcommand(s)
true does nothing successfully
```

View file

@ -1,12 +1,3 @@
//! Example of a `busybox-style` multicall program
//!
//! See the documentation for clap::AppSettings::Multicall for rationale.
//!
//! This example omits every command except true and false,
//! which are the most trivial to implement,
//! but includes the `--install` option as an example of why it can be useful
//! for the main program to take arguments that aren't applet subcommands.
use std::process::exit;
use clap::{App, AppSettings, Arg};

View file

@ -0,0 +1,31 @@
Example of a `hostname-style` multicall program
See the documentation for clap::AppSettings::Multicall for rationale.
This example omits the implementation of displaying address config
```bash
$ hostname hostname
www
$ hostname dnsdomainname
example.com
```
*Note: without the links setup, we can't demonostrate the multicall behavior*
Though users must pass something:
```bash
$ hostname
? failed
hostname
USAGE:
hostname[EXE] [SUBCOMMAND]
OPTIONS:
-h, --help Print help information
SUBCOMMANDS:
dnsdomainname show domain name part of FQDN
help Print this message or the help of the given subcommand(s)
hostname show hostname part of FQDN
```

View file

@ -1,9 +1,3 @@
//! Example of a `hostname-style` multicall program
//!
//! See the documentation for clap::AppSettings::Multicall for rationale.
//!
//! This example omits the implementation of displaying address config
use clap::{App, AppSettings};
fn main() {

8
examples/README.md Normal file
View file

@ -0,0 +1,8 @@
# `clap` Examples
Each example is accompanying by a markdown file demonstrating its features.
## Contributing
Each example must have a markdown file. They are verified using
[trycmd](https://docs.rs/trycmd).

View file

@ -1,61 +1,13 @@
#![cfg(not(tarpaulin))]
use std::ffi::OsStr;
use std::fs;
use std::process::{Command, Output};
fn run_example<S: AsRef<str>>(name: S, args: &[&str]) -> Output {
let mut all_args = vec!["run", "--example", name.as_ref(), "--"];
all_args.extend_from_slice(args);
Command::new(env!("CARGO"))
.args(all_args)
.output()
.expect("failed to run example")
}
#[test]
fn examples_are_functional() {
let example_paths = fs::read_dir("examples")
.expect("couldn't read examples directory")
.map(|result| result.expect("couldn't get directory entry").path())
.filter(|path| path.is_file() && path.extension().and_then(OsStr::to_str) == Some("rs"));
let mut example_count = 0;
for path in example_paths {
example_count += 1;
let example_name = match path.file_name().and_then(OsStr::to_str) {
Some("24a_multicall_busybox.rs") => {
#[cfg(not(feature = "unstable-multicall"))]
continue;
#[allow(unreachable_code)]
"busybox"
}
Some("24b_multicall_hostname.rs") => {
#[cfg(not(feature = "unstable-multicall"))]
continue;
#[allow(unreachable_code)]
"hostname"
}
_ => path
.file_stem()
.and_then(OsStr::to_str)
.expect("unable to determine example name"),
};
let help_output = run_example(example_name, &["--help"]);
assert!(
help_output.status.success(),
"{} --help exited with nonzero: {}",
example_name,
String::from_utf8_lossy(&help_output.stderr),
);
assert!(
!help_output.stdout.is_empty(),
"{} --help had no output",
example_name,
);
fn example_tests() {
let t = trycmd::TestCases::new();
t.register_bins(trycmd::cargo::compile_examples([]).unwrap());
t.case("examples/*.md");
#[cfg(not(feature = "unstable-multicall"))]
{
t.skip("examples/24a_multicall_busybox.md");
t.skip("examples/24b_multicall_hostname.md");
}
assert!(example_count > 0);
}