xref: /third_party/rust/crates/clap/src/_derive/mod.rs (revision 19625d8c)
1//! # Documentation: Derive Reference
2//!
3//! 1. [Overview](#overview)
4//! 2. [Attributes](#attributes)
5//!     1. [Terminology](#terminology)
6//!     2. [Command Attributes](#command-attributes)
7//!     2. [ArgGroup Attributes](#arggroup-attributes)
8//!     3. [Arg Attributes](#arg-attributes)
9//!     4. [ValueEnum Attributes](#valueenum-attributes)
10//!     5. [Possible Value Attributes](#possible-value-attributes)
11//! 3. [Arg Types](#arg-types)
12//! 4. [Doc Comments](#doc-comments)
13//! 5. [Mixing Builder and Derive APIs](#mixing-builder-and-derive-apis)
14//! 6. [Tips](#tips)
15//!
16//! ## Overview
17//!
18//! To derive `clap` types, you need to enable the [`derive` feature flag][crate::_features].
19//!
20//! Example:
21//! ```rust
22#![doc = include_str!("../../examples/demo.rs")]
23//! ```
24//!
25//! Let's start by breaking down the anatomy of the derive attributes:
26//! ```rust
27//! use clap::{Parser, Args, Subcommand, ValueEnum};
28//!
29//! /// Doc comment
30//! #[derive(Parser)]
31//! #[command(CMD ATTRIBUTE)]
32//! #[group(GROUP ATTRIBUTE)]
33//! struct Cli {
34//!     /// Doc comment
35//!     #[arg(ARG ATTRIBUTE)]
36//!     field: UserType,
37//!
38//!     #[arg(value_enum, ARG ATTRIBUTE...)]
39//!     field: EnumValues,
40//!
41//!     #[command(flatten)]
42//!     delegate: Struct,
43//!
44//!     #[command(subcommand)]
45//!     command: Command,
46//! }
47//!
48//! /// Doc comment
49//! #[derive(Args)]
50//! #[command(PARENT CMD ATTRIBUTE)]
51//! #[group(GROUP ATTRIBUTE)]
52//! struct Struct {
53//!     /// Doc comment
54//!     #[command(ARG ATTRIBUTE)]
55//!     field: UserType,
56//! }
57//!
58//! /// Doc comment
59//! #[derive(Subcommand)]
60//! #[command(PARENT CMD ATTRIBUTE)]
61//! enum Command {
62//!     /// Doc comment
63//!     #[command(CMD ATTRIBUTE)]
64//!     Variant1(Struct),
65//!
66//!     /// Doc comment
67//!     #[command(CMD ATTRIBUTE)]
68//!     Variant2 {
69//!         /// Doc comment
70//!         #[arg(ARG ATTRIBUTE)]
71//!         field: UserType,
72//!     }
73//! }
74//!
75//! /// Doc comment
76//! #[derive(ValueEnum)]
77//! #[value(VALUE ENUM ATTRIBUTE)]
78//! enum EnumValues {
79//!     /// Doc comment
80//!     #[value(POSSIBLE VALUE ATTRIBUTE)]
81//!     Variant1,
82//! }
83//!
84//! fn main() {
85//!     let cli = Cli::parse();
86//! }
87//! ```
88//!
89//! Traits:
90//! - [`Parser`][crate::Parser] parses arguments into a `struct` (arguments) or `enum` (subcommands).
91//!   - [`Args`][crate::Args] allows defining a set of re-usable arguments that get merged into their parent container.
92//!   - [`Subcommand`][crate::Subcommand] defines available subcommands.
93//!   - Subcommand arguments can be defined in a struct-variant or automatically flattened with a tuple-variant.
94//! - [`ValueEnum`][crate::ValueEnum] allows parsing a value directly into an `enum`, erroring on unsupported values.
95//!   - The derive doesn't work on enums that contain non-unit variants, unless they are skipped
96//!
97//! *See also the [derive tutorial][crate::_derive::_tutorial] and [cookbook][crate::_cookbook]*
98//!
99//! ## Attributes
100//!
101//! ### Terminology
102//!
103//! **Raw attributes** are forwarded directly to the underlying [`clap` builder][crate::builder].  Any
104//! [`Command`][crate::Command], [`Arg`][crate::Arg], or [`PossibleValue`][crate::builder::PossibleValue] method can be used as an attribute.
105//!
106//! Raw attributes come in two different syntaxes:
107//! ```rust,ignore
108//! #[arg(
109//!     global = true, // name = arg form, neat for one-arg methods
110//!     required_if_eq("out", "file") // name(arg1, arg2, ...) form.
111//! )]
112//! ```
113//!
114//! - `method = arg` can only be used for methods which take only one argument.
115//! - `method(arg1, arg2)` can be used with any method.
116//!
117//! As long as `method_name` is not one of the magical methods it will be
118//! translated into a mere method call.
119//!
120//! **Magic attributes** have post-processing done to them, whether that is
121//! - Providing of defaults
122//! - Special behavior is triggered off of it
123//!
124//! Magic attributes are more constrained in the syntax they support, usually just
125//! `<attr> = <value>` though some use `<attr>(<value>)` instead.  See the specific
126//! magic attributes documentation for details.  This allows users to access the
127//! raw behavior of an attribute via `<attr>(<value>)` syntax.
128//!
129//! **NOTE:** Some attributes are inferred from [Arg Types](#arg-types) and [Doc
130//! Comments](#doc-comments).  Explicit attributes take precedence over inferred
131//! attributes.
132//!
133//! ### Command Attributes
134//!
135//! These correspond to a [`Command`][crate::Command] which is used for both top-level parsers and
136//! when defining subcommands.
137//!
138//! **Raw attributes:**  Any [`Command` method][crate::Command] can also be used as an attribute,
139//! see [Terminology](#terminology) for syntax.
140//! - e.g. `#[command(arg_required_else_help(true))]` would translate to `cmd.arg_required_else_help(true)`
141//!
142//! **Magic attributes:**
143//! - `name  = <expr>`: [`Command::name`][crate::Command::name]
144//!   - When not present: [crate `name`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-name-field) (if on [`Parser`][crate::Parser] container), variant name (if on [`Subcommand`][crate::Subcommand] variant)
145//! - `version [= <expr>]`: [`Command::version`][crate::Command::version]
146//!   - When not present: no version set
147//!   - Without `<expr>`: defaults to [crate `version`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field)
148//! - `author [= <expr>]`: [`Command::author`][crate::Command::author]
149//!   - When not present: no author set
150//!   - Without `<expr>`: defaults to [crate `authors`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-authors-field)
151//! - `about [= <expr>]`: [`Command::about`][crate::Command::about]
152//!   - When not present: [Doc comment summary](#doc-comments)
153//!   - Without `<expr>`: [crate `description`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-description-field) ([`Parser`][crate::Parser] container)
154//!     - **TIP:** When a doc comment is also present, you most likely want to add
155//!       `#[arg(long_about = None)]` to clear the doc comment so only [`about`][crate::Command::about]
156//!       gets shown with both `-h` and `--help`.
157//! - `long_about[ = <expr>]`: [`Command::long_about`][crate::Command::long_about]
158//!   - When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing
159//!   - When present without a value: [Doc comment](#doc-comments)
160//! - `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to [`about`][crate::Command::about] / [`long_about`][crate::Command::long_about]
161//! - `next_display_order`: [`Command::next_display_order`][crate::Command::next_display_order]
162//! - `next_help_heading`: [`Command::next_help_heading`][crate::Command::next_help_heading]
163//!   - When `flatten`ing [`Args`][crate::Args], this is scoped to just the args in this struct and any struct `flatten`ed into it
164//! - `rename_all = <string_literal>`: Override default field / variant name case conversion for [`Command::name`][crate::Command::name] / [`Arg::id`][crate::Arg::id]
165//!   - When not present: `"kebab-case"`
166//!   - Available values: `"camelCase"`, `"kebab-case"`, `"PascalCase"`, `"SCREAMING_SNAKE_CASE"`, `"snake_case"`, `"lower"`, `"UPPER"`, `"verbatim"`
167//! - `rename_all_env = <string_literal>`: Override default field name case conversion for env variables for  [`Arg::env`][crate::Arg::env]
168//!   - When not present: `"SCREAMING_SNAKE_CASE"`
169//!   - Available values: `"camelCase"`, `"kebab-case"`, `"PascalCase"`, `"SCREAMING_SNAKE_CASE"`, `"snake_case"`, `"lower"`, `"UPPER"`, `"verbatim"`
170//!
171//! And for [`Subcommand`][crate::Subcommand] variants:
172//! - `skip`: Ignore this variant
173//! - `flatten`: Delegates to the variant for more subcommands (must implement
174//!   [`Subcommand`][crate::Subcommand])
175//! - `subcommand`: Nest subcommands under the current set of subcommands (must implement
176//!   [`Subcommand`][crate::Subcommand])
177//! - `external_subcommand`: [`Command::allow_external_subcommand(true)`][crate::Command::allow_external_subcommands]
178//!   - Variant must be either `Variant(Vec<String>)` or `Variant(Vec<OsString>)`
179//!
180//! And for [`Args`][crate::Args] fields:
181//! - `flatten`: Delegates to the field for more arguments (must implement [`Args`][crate::Args])
182//!   - Only [`next_help_heading`][crate::Command::next_help_heading] can be used with `flatten`.  See
183//!     [clap-rs/clap#3269](https://github.com/clap-rs/clap/issues/3269) for why
184//!     arg attributes are not generally supported.
185//!   - **Tip:** Though we do apply a flattened [`Args`][crate::Args]'s Parent Command Attributes, this
186//!     makes reuse harder. Generally prefer putting the cmd attributes on the
187//!     [`Parser`][crate::Parser] or on the flattened field.
188//! - `subcommand`: Delegates definition of subcommands to the field (must implement
189//!   [`Subcommand`][crate::Subcommand])
190//!   - When `Option<T>`, the subcommand becomes optional
191//!
192//! ### ArgGroup Attributes
193//!
194//! These correspond to the [`ArgGroup`][crate::ArgGroup] which is implicitly created for each
195//! `Args` derive.
196//!
197//! At the moment, only `#[group(skip)]` is supported
198//!
199//! ### Arg Attributes
200//!
201//! These correspond to a [`Arg`][crate::Arg].
202//!
203//! **Raw attributes:**  Any [`Arg` method][crate::Arg] can also be used as an attribute, see [Terminology](#terminology) for syntax.
204//! - e.g. `#[arg(max_values(3))]` would translate to `arg.max_values(3)`
205//!
206//! **Magic attributes**:
207//! - `id = <expr>`: [`Arg::id`][crate::Arg::id]
208//!   - When not present: case-converted field name is used
209//! - `value_parser [= <expr>]`: [`Arg::value_parser`][crate::Arg::value_parser]
210//!   - When not present: will auto-select an implementation based on the field type using
211//!     [`value_parser!`][crate::value_parser!]
212//! - `action [= <expr>]`: [`Arg::action`][crate::Arg::action]
213//!   - When not present: will auto-select an action based on the field type
214//! - `help = <expr>`: [`Arg::help`][crate::Arg::help]
215//!   - When not present: [Doc comment summary](#doc-comments)
216//! - `long_help[ = <expr>]`: [`Arg::long_help`][crate::Arg::long_help]
217//!   - When not present: [Doc comment](#doc-comments) if there is a blank line, else nothing
218//!   - When present without a value: [Doc comment](#doc-comments)
219//! - `verbatim_doc_comment`: Minimizes pre-processing when converting doc comments to [`help`][crate::Arg::help] / [`long_help`][crate::Arg::long_help]
220//! - `short [= <char>]`: [`Arg::short`][crate::Arg::short]
221//!   - When not present: no short set
222//!   - Without `<char>`: defaults to first character in the case-converted field name
223//! - `long [= <str>]`: [`Arg::long`][crate::Arg::long]
224//!   - When not present: no long set
225//!   - Without `<str>`: defaults to the case-converted field name
226//! - `env [= <str>]`: [`Arg::env`][crate::Arg::env] (needs [`env` feature][crate::_features] enabled)
227//!   - When not present: no env set
228//!   - Without `<str>`: defaults to the case-converted field name
229//! - `from_global`: Read a [`Arg::global`][crate::Arg::global] argument (raw attribute), regardless of what subcommand you are in
230//! - `value_enum`: Parse the value using the [`ValueEnum`][crate::ValueEnum]
231//! - `skip [= <expr>]`: Ignore this field, filling in with `<expr>`
232//!   - Without `<expr>`: fills the field with `Default::default()`
233//! - `default_value = <str>`: [`Arg::default_value`][crate::Arg::default_value] and [`Arg::required(false)`][crate::Arg::required]
234//! - `default_value_t [= <expr>]`: [`Arg::default_value`][crate::Arg::default_value] and [`Arg::required(false)`][crate::Arg::required]
235//!   - Requires `std::fmt::Display` that roundtrips correctly with the
236//!     [`Arg::value_parser`][crate::Arg::value_parser] or `#[arg(value_enum)]`
237//!   - Without `<expr>`, relies on `Default::default()`
238//! - `default_values_t = <expr>`: [`Arg::default_values`][crate::Arg::default_values] and [`Arg::required(false)`][crate::Arg::required]
239//!   - Requires field arg to be of type `Vec<T>` and `T` to implement `std::fmt::Display` or `#[arg(value_enum)]`
240//!   - `<expr>` must implement `IntoIterator<T>`
241//! - `default_value_os_t [= <expr>]`: [`Arg::default_value_os`][crate::Arg::default_value_os] and [`Arg::required(false)`][crate::Arg::required]
242//!   - Requires `std::convert::Into<OsString>` or `#[arg(value_enum)]`
243//!   - Without `<expr>`, relies on `Default::default()`
244//! - `default_values_os_t = <expr>`: [`Arg::default_values_os`][crate::Arg::default_values_os] and [`Arg::required(false)`][crate::Arg::required]
245//!   - Requires field arg to be of type `Vec<T>` and `T` to implement `std::convert::Into<OsString>` or `#[arg(value_enum)]`
246//!   - `<expr>` must implement `IntoIterator<T>`
247//!
248//! ### ValueEnum Attributes
249//!
250//! - `rename_all = <string_literal>`: Override default field / variant name case conversion for [`PossibleValue::new`][crate::builder::PossibleValue]
251//!   - When not present: `"kebab-case"`
252//!   - Available values: `"camelCase"`, `"kebab-case"`, `"PascalCase"`, `"SCREAMING_SNAKE_CASE"`, `"snake_case"`, `"lower"`, `"UPPER"`, `"verbatim"`
253//!
254//! ### Possible Value Attributes
255//!
256//! These correspond to a [`PossibleValue`][crate::builder::PossibleValue].
257//!
258//! **Raw attributes:**  Any [`PossibleValue` method][crate::builder::PossibleValue] can also be used as an attribute, see [Terminology](#terminology) for syntax.
259//! - e.g. `#[value(alias("foo"))]` would translate to `pv.alias("foo")`
260//!
261//! **Magic attributes**:
262//! - `name = <expr>`: [`PossibleValue::new`][crate::builder::PossibleValue::new]
263//!   - When not present: case-converted field name is used
264//! - `help = <expr>`: [`PossibleValue::help`][crate::builder::PossibleValue::help]
265//!   - When not present: [Doc comment summary](#doc-comments)
266//! - `skip`: Ignore this variant
267//!
268//! ## Arg Types
269//!
270//! `clap` assumes some intent based on the type used:
271//!
272//! | Type                | Effect                               | Implies                                                     |
273//! |---------------------|--------------------------------------|-------------------------------------------------------------|
274//! | `()`                | user-defined                         | `.action(ArgAction::Set).required(false)`                   |
275//! | `bool`              | flag                                 | `.action(ArgAction::SetTrue)`                               |
276//! | `Option<T>`         | optional argument                    | `.action(ArgAction::Set).required(false)`                   |
277//! | `Option<Option<T>>` | optional value for optional argument | `.action(ArgAction::Set).required(false).num_args(0..=1)`   |
278//! | `T`                 | required argument                    | `.action(ArgAction::Set).required(!has_default)`            |
279//! | `Vec<T>`            | `0..` occurrences of argument        | `.action(ArgAction::Append).required(false)`  |
280//! | `Option<Vec<T>>`    | `0..` occurrences of argument        | `.action(ArgAction::Append).required(false)`  |
281//!
282//! In addition, [`.value_parser(value_parser!(T))`][crate::value_parser!] is called for each
283//! field.
284//!
285//! Notes:
286//! - For custom type behavior, you can override the implied attributes/settings and/or set additional ones
287//! - `Option<Vec<T>>` will be `None` instead of `vec![]` if no arguments are provided.
288//!   - This gives the user some flexibility in designing their argument, like with `num_args(0..)`
289//!
290//! ## Doc Comments
291//!
292//! In clap, help messages for the whole binary can be specified
293//! via [`Command::about`][crate::Command::about] and [`Command::long_about`][crate::Command::long_about] while help messages
294//! for individual arguments can be specified via [`Arg::help`][crate::Arg::help] and [`Arg::long_help`][crate::Arg::long_help].
295//!
296//! `long_*` variants are used when user calls the program with
297//! `--help` and "short" variants are used with `-h` flag.
298//!
299//! ```rust
300//! # use clap::Parser;
301//!
302//! #[derive(Parser)]
303//! #[command(about = "I am a program and I work, just pass `-h`", long_about = None)]
304//! struct Foo {
305//!     #[arg(short, help = "Pass `-h` and you'll see me!")]
306//!     bar: String,
307//! }
308//! ```
309//!
310//! For convenience, doc comments can be used instead of raw methods
311//! (this example works exactly like the one above):
312//!
313//! ```rust
314//! # use clap::Parser;
315//!
316//! #[derive(Parser)]
317//! /// I am a program and I work, just pass `-h`
318//! struct Foo {
319//!     /// Pass `-h` and you'll see me!
320//!     bar: String,
321//! }
322//! ```
323//!
324//! **NOTE:** Attributes have priority over doc comments!
325//!
326//! **Top level doc comments always generate `Command::about/long_about` calls!**
327//! If you really want to use the `Command::about/long_about` methods (you likely don't),
328//! use the `about` / `long_about` attributes to override the calls generated from
329//! the doc comment.  To clear `long_about`, you can use
330//! `#[command(long_about = None)]`.
331//!
332//! ### Pre-processing
333//!
334//! ```rust
335//! # use clap::Parser;
336//! #[derive(Parser)]
337//! /// Hi there, I'm Robo!
338//! ///
339//! /// I like beeping, stumbling, eating your electricity,
340//! /// and making records of you singing in a shower.
341//! /// Pay up, or I'll upload it to youtube!
342//! struct Robo {
343//!     /// Call my brother SkyNet.
344//!     ///
345//!     /// I am artificial superintelligence. I won't rest
346//!     /// until I'll have destroyed humanity. Enjoy your
347//!     /// pathetic existence, you mere mortals.
348//!     #[arg(long, action)]
349//!     kill_all_humans: bool,
350//! }
351//! ```
352//!
353//! A doc comment consists of three parts:
354//! - Short summary
355//! - A blank line (whitespace only)
356//! - Detailed description, all the rest
357//!
358//! The summary corresponds with `Command::about` / `Arg::help`.  When a blank line is
359//! present, the whole doc comment will be passed to `Command::long_about` /
360//! `Arg::long_help`.  Or in other words, a doc may result in just a `Command::about` /
361//! `Arg::help` or `Command::about` / `Arg::help` and `Command::long_about` /
362//! `Arg::long_help`
363//!
364//! In addition, when `verbatim_doc_comment` is not present, `clap` applies some preprocessing, including:
365//!
366//! - Strip leading and trailing whitespace from every line, if present.
367//!
368//! - Strip leading and trailing blank lines, if present.
369//!
370//! - Interpret each group of non-empty lines as a word-wrapped paragraph.
371//!
372//!   We replace newlines within paragraphs with spaces to allow the output
373//!   to be re-wrapped to the terminal width.
374//!
375//! - Strip any excess blank lines so that there is exactly one per paragraph break.
376//!
377//! - If the first paragraph ends in exactly one period,
378//!   remove the trailing period (i.e. strip trailing periods but not trailing ellipses).
379//!
380//! Sometimes you don't want this preprocessing to apply, for example the comment contains
381//! some ASCII art or markdown tables, you would need to preserve LFs along with
382//! blank lines and the leading/trailing whitespace. When you pass use the
383//! `verbatim_doc_comment` magic attribute, you  preserve
384//! them.
385//!
386//! **Note:** Keep in mind that `verbatim_doc_comment` will *still*
387//! - Remove one leading space from each line, even if this attribute is present,
388//!   to allow for a space between `///` and the content.
389//! - Remove leading and trailing blank lines
390//!
391//! ## Mixing Builder and Derive APIs
392//!
393//! The builder and derive APIs do not live in isolation. They can work together, which is
394//! especially helpful if some arguments can be specified at compile-time while others must be
395//! specified at runtime.
396//!
397//! ### Using derived arguments in a builder application
398//!
399//! When using the derive API, you can `#[command(flatten)]` a struct deriving `Args` into a struct
400//! deriving `Args` or `Parser`. This example shows how you can augment a `Command` instance
401//! created using the builder API with `Args` created using the derive API.
402//!
403//! It uses the [`Args::augment_args`][crate::Args::augment_args] method to add the arguments to
404//! the `Command` instance.
405//!
406//! Crates such as [clap-verbosity-flag](https://github.com/rust-cli/clap-verbosity-flag) provide
407//! structs that implement `Args`. Without the technique shown in this example, it would not be
408//! possible to use such crates with the builder API.
409//!
410//! For example:
411//! ```rust
412#![doc = include_str!("../../examples/derive_ref/augment_args.rs")]
413//! ```
414//!
415//! ### Using derived subcommands in a builder application
416//!
417//! When using the derive API, you can use `#[command(subcommand)]` inside the struct to add
418//! subcommands. The type of the field is usually an enum that derived `Parser`. However, you can
419//! also add the subcommands in that enum to a `Command` instance created with the builder API.
420//!
421//! It uses the [`Subcommand::augment_subcommands`][crate::Subcommand::augment_subcommands] method
422//! to add the subcommands to the `Command` instance.
423//!
424//! For example:
425//! ```rust
426#![doc = include_str!("../../examples/derive_ref/augment_subcommands.rs")]
427//! ```
428//!
429//! ### Adding hand-implemented subcommands to a derived application
430//!
431//! When using the derive API, you can use `#[command(subcommand)]` inside the struct to add
432//! subcommands. The type of the field is usually an enum that derived `Parser`. However, you can
433//! also implement the `Subcommand` trait manually on this enum (or any other type) and it can
434//! still be used inside the struct created with the derive API. The implementation of the
435//! `Subcommand` trait will use the builder API to add the subcommands to the `Command` instance
436//! created behind the scenes for you by the derive API.
437//!
438//! Notice how in the previous example we used
439//! [`augment_subcommands`][crate::Subcommand::augment_subcommands] on an enum that derived
440//! `Parser`, whereas now we implement
441//! [`augment_subcommands`][crate::Subcommand::augment_subcommands] ourselves, but the derive API
442//! calls it automatically since we used the `#[command(subcommand)]` attribute.
443//!
444//! For example:
445//! ```rust
446#![doc = include_str!("../../examples/derive_ref/hand_subcommand.rs")]
447//! ```
448//!
449//! ### Flattening hand-implemented args into a derived application
450//!
451//! When using the derive API, you can use `#[command(flatten)]` inside the struct to add arguments as
452//! if they were added directly to the containing struct. The type of the field is usually an
453//! struct that derived `Args`. However, you can also implement the `Args` trait manually on this
454//! struct (or any other type) and it can still be used inside the struct created with the derive
455//! API. The implementation of the `Args` trait will use the builder API to add the arguments to
456//! the `Command` instance created behind the scenes for you by the derive API.
457//!
458//! Notice how in the previous example we used [`augment_args`][crate::Args::augment_args] on the
459//! struct that derived `Parser`, whereas now we implement
460//! [`augment_args`][crate::Args::augment_args] ourselves, but the derive API calls it
461//! automatically since we used the `#[command(flatten)]` attribute.
462//!
463//! For example:
464//! ```rust
465#![doc = include_str!("../../examples/derive_ref/flatten_hand_args.rs")]
466//! ```
467//!
468//! ## Tips
469//!
470//! - To get access to a [`Command`][crate::Command] call
471//!   [`CommandFactory::command`][crate::CommandFactory::command] (implemented when deriving
472//!   [`Parser`][crate::Parser])
473//! - Proactively check for bad [`Command`][crate::Command] configurations by calling
474//!   [`Command::debug_assert`][crate::Command::debug_assert] in a test
475//!   ([example](../tutorial_derive/05_01_assert.rs))
476//! - Always remember to [document](#doc-comments) args and commands with `#![deny(missing_docs)]`
477
478pub mod _tutorial;
479#[doc(inline)]
480pub use crate::_cookbook;
481