diff --git a/documentation/_documentation/_0_intro/index.md b/documentation/_documentation/_0_intro/index.md index 4318bc42..a6b2bbb2 100644 --- a/documentation/_documentation/_0_intro/index.md +++ b/documentation/_documentation/_0_intro/index.md @@ -18,7 +18,7 @@ and match both in a single parser ## Parse, don't validate `bpaf` tries hard to let you to move as much invariants about the user input you are -trying to parse into rust type: for mutually exclusive options you can get `enum` with +trying to parse into rust types: for mutually exclusive options you can get `enum` with exclusive items going into separate branches, you can collect results into types like [`BTreeSet`](std::collections::BTreeSet), or whatever custom type you might have with custom parsing. Ideas for @@ -26,14 +26,14 @@ custom parsing. Ideas for and [using parsing over validation](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) are not new. -That said you can also validate your inputs if this fits your problem better. If you want to +That said you can also validate your inputs if this fits your situation better. If you want to ensure that sum of every numeric fields must be divisible by both 3 and 5, but only when it's Thursday - you can do that too. ## Flexibility While aiming to be a general purpose command line parser `bpaf` offers a few backdoors that -allow to parse pretty much anything you want: chained commands, custom blocks of options, DOS +allow you to parse pretty much anything you want: chained commands, custom blocks of options, DOS style options (`/ofile.pas`), `dd` style options (`if=file of=out`), etc. Similar idea applies for what the parser can produce - your app operates with boxed string slices internally? `bpaf` will give you `Box` instead of `String` if you ask it to. @@ -62,7 +62,7 @@ Or to make it so parser runs multiple times and collects results into a `Vec`. ## Performance While performance is an explicit non goal - `bpaf` does nothing that would pessimize it either, -so performance is on par or better compared to fully featured parsers. +so performance is on par or better compared to other fully featured parsers. ## Correctness diff --git a/documentation/_documentation/_1_tutorials/_0_types_of_arguments/_0_switch/index.md b/documentation/_documentation/_1_tutorials/_0_types_of_arguments/_0_switch/index.md index f25d1d0c..d44f9786 100644 --- a/documentation/_documentation/_1_tutorials/_0_types_of_arguments/_0_switch/index.md +++ b/documentation/_documentation/_1_tutorials/_0_types_of_arguments/_0_switch/index.md @@ -1,7 +1,7 @@ #### Options, switches or flags Options or flags usually starts with a dash, single dash for short options and double dash for -long one. Several short options usually can be squashed together with a single dash between +long one. Several short options can usually be squashed together with a single dash in front of them to save on typing: `-vvv` can be parsed the same as `-v -v -v`. Options don't have any other information apart from being there or not. Relative position usually does not matter and `--alpha --beta` should parse the same as `--beta --alpha`. diff --git a/documentation/_documentation/_1_tutorials/_0_types_of_arguments/_3_command/index.md b/documentation/_documentation/_1_tutorials/_0_types_of_arguments/_3_command/index.md index d46be345..0091253b 100644 --- a/documentation/_documentation/_1_tutorials/_0_types_of_arguments/_3_command/index.md +++ b/documentation/_documentation/_1_tutorials/_0_types_of_arguments/_3_command/index.md @@ -1,7 +1,7 @@ #### Commands or subcommands -Commands are similar to positional items, but instead of representing an item they represent -a new parser, usually with its own help and other arguments. Commands allow a single +Commands are similar to positional items, but instead of representing an item they start +a whole new parser, usually with its own help and other arguments. Commands allow a single applications to perform multiple different functions. Command parser will be able to parse all the command line options to the right of the command name diff --git a/documentation/_documentation/_1_tutorials/_0_types_of_arguments/_4_exotic/index.md b/documentation/_documentation/_1_tutorials/_0_types_of_arguments/_4_exotic/index.md index 64798a4a..9c97d15e 100644 --- a/documentation/_documentation/_1_tutorials/_0_types_of_arguments/_4_exotic/index.md +++ b/documentation/_documentation/_1_tutorials/_0_types_of_arguments/_4_exotic/index.md @@ -2,7 +2,7 @@ While modern software tends to use just the options listed above you can still encounter programs created before those options became norm and they use something complitely different, -let me give a few examples, see [exotic howto](crate::_documentation::_2_howto) +let me give a few examples, see [the parsing cookbook](crate::_documentation::_2_howto) about actually parsing them `su` takes an option that consists of a single dash `-` diff --git a/documentation/_documentation/_1_tutorials/_0_types_of_arguments/index.md b/documentation/_documentation/_1_tutorials/_0_types_of_arguments/index.md index ae5f792c..df5fc491 100644 --- a/documentation/_documentation/_1_tutorials/_0_types_of_arguments/index.md +++ b/documentation/_documentation/_1_tutorials/_0_types_of_arguments/index.md @@ -15,8 +15,7 @@ $ cargo test -p my_project --verbose `cargo` here is an executable name, everything to the right of it separated by spaces are the -q! options. Nowdays programs share mostly similar conventions about what a command line argument is, it -wasn't the case before though. Let's cover the basic types +wasn't the case before though. Let's cover the basic types. diff --git a/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_1_argument/index.md b/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_1_argument/index.md index 22d280b3..aa7ba260 100644 --- a/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_1_argument/index.md +++ b/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_1_argument/index.md @@ -10,14 +10,18 @@ several ways to do it: # use bpaf::*; # use std::path::PathBuf; fn simple_argument_1() -> impl Parser { + // rustc figures out the type from returned value long("number").argument("NUM") } fn simple_argument_2() -> impl Parser { + // type is specified explicitly with turbofish long("name").argument::("NAME") } fn file_parser() -> OptionParser { + // OptionParser is a type for finalized parser, at this point you can + // start adding extra information to the `--help` message long("file").argument::("FILE").to_options() } ``` diff --git a/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_2_positional/index.md b/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_2_positional/index.md index 15f3e3b4..dce8f46e 100644 --- a/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_2_positional/index.md +++ b/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_0_simple_parser/_2_positional/index.md @@ -1,9 +1,9 @@ #### Positional item parser And the last simple option type is parser for positional items. Since there's no name you use -[`positional`] method directly which behaves similarly to [`NamedArg::argument`] - takes -metavariable name and a type parameter in some form. You can also attach help message directly -to it thanks to [`ParsePositional::help`] +[`positional`] method directly. Similar to [`NamedArg::argument`] this method takes +metavariable name and a type parameter in some form. You can also attach the help message +thanks to [`ParsePositional::help`] Full example: #![cfg_attr(not(doctest), doc = include_str!("docs2/compose_basic_positional.md"))] diff --git a/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_1_chaining/index.md b/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_1_chaining/index.md index 0e1d96d1..55ee8faf 100644 --- a/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_1_chaining/index.md +++ b/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_1_chaining/index.md @@ -80,7 +80,7 @@ specific example it makes code less readable. One of the important types of transformations you can apply is a set of failing transformations. Suppose your application operates with numbers and uses `newtype` pattern to keep track what numbers are odd or even. Parser that consumes an even number can use -[`Parser::parse`] and look like this: +[`Parser::parse`] and may look like this: ```rust # use bpaf::*; diff --git a/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_2_combining/index.md b/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_2_combining/index.md index d72bedaa..1f7a30f3 100644 --- a/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_2_combining/index.md +++ b/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_2_combining/index.md @@ -21,6 +21,8 @@ fn alpha() -> impl Parser { fn both() -> impl Parser { let beta = long("beta").argument("BETA"); + // call `alpha` function, and use result to make parser + // for field `alpha`, use parser `beta` for field `beta` construct!(Options { alpha(), beta }) } ``` @@ -32,8 +34,8 @@ If you are using positional parsers - they must go to the right most side and wi order you specify them. For named parsers order affects only the `--help` message. Second type of composition `construct!` offers is a parallel composition. You pass multiple -parsers that produce the same result type and `bpaf` runs one that fits best with the data user -gave. +parsers that produce the same result type in `[]` and `bpaf` selects one that fits best with +the data user gave. #![cfg_attr(not(doctest), doc = include_str!("docs2/compose_basic_choice.md"))] diff --git a/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_4_decorating/index.md b/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_4_decorating/index.md index d087d447..d1789107 100644 --- a/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_4_decorating/index.md +++ b/documentation/_documentation/_1_tutorials/_1_combinatoric_api/_4_decorating/index.md @@ -15,4 +15,4 @@ There's a few other things you can do: - add a test to make sure that bpaf internal invariants are satisfied with [`OptionParser::check_invariants`] - generate user documentation in manpage and markdown formats with - [`OptionParser::render_manpage] and [`OptionParser::render_markdown`] + [`OptionParser::render_manpage`] and [`OptionParser::render_markdown`] diff --git a/documentation/_documentation/_1_tutorials/_2_derive_api/_2_custom_consumers/index.md b/documentation/_documentation/_1_tutorials/_2_derive_api/_2_custom_consumers/index.md index 45a8f14c..ebc581bc 100644 --- a/documentation/_documentation/_1_tutorials/_2_derive_api/_2_custom_consumers/index.md +++ b/documentation/_documentation/_1_tutorials/_2_derive_api/_2_custom_consumers/index.md @@ -3,11 +3,11 @@ By default `bpaf` picks parsers depending on a field type according to those rules: 1. `bool` fields are converted into switches: [`NamedArg::switch`](crate::parsers::NamedArg::switch) -2. `()` (unit) fields, unit variants of enum or unit structs themselves are handled as req_flag +2. `()` (unit) fields, unit variants of enum or unit structs themselves are handled as [`NamedArg::req_flag`](crate::parsers::NamedArg::req_flag) and thus users must always specify them for parser to succeed 3. All other types with no `Vec`/`Option` are parsed using [`FromStr`](std::str::FromStr), but in a - smart way, so Non-utf8 `PathBuf`/`OsString` are working as expected. + smart way, so non-utf8 `PathBuf`/`OsString` are working as expected. 4. For values wrapped in `Option` or `Vec` bpaf derives inner parser and then applies applies logic from [`Parser::optional`] and [`Parser::many`] respectively. diff --git a/documentation/_documentation/_1_tutorials/_2_derive_api/_4_enums_and_structs/index.md b/documentation/_documentation/_1_tutorials/_2_derive_api/_4_enums_and_structs/index.md index 07425c37..543b70b5 100644 --- a/documentation/_documentation/_1_tutorials/_2_derive_api/_4_enums_and_structs/index.md +++ b/documentation/_documentation/_1_tutorials/_2_derive_api/_4_enums_and_structs/index.md @@ -1,7 +1,9 @@ #### Parsing structs and enums To produce a struct bpaf needs for all the field parsers to succeed. If you are planning to use -it for some other purpose as well and want to skip them during parsing you can use [`pure`]. +it for some other purpose as well and want to skip them during parsing you can use [`pure`] to +fill in values in member fields and `#[bpaf(skip)]` on enum variants you want to ignore, see +combinatoric example in [`Parser::last`]. If you use `#[derive(Bpaf)]` on enum parser will produce variant for which all the parsers succeed. diff --git a/documentation/_documentation/_1_tutorials/_2_derive_api/_6_nesting/index.md b/documentation/_documentation/_1_tutorials/_2_derive_api/_6_nesting/index.md index f1233adb..9cf5e5f0 100644 --- a/documentation/_documentation/_1_tutorials/_2_derive_api/_6_nesting/index.md +++ b/documentation/_documentation/_1_tutorials/_2_derive_api/_6_nesting/index.md @@ -5,3 +5,30 @@ parsers, possibly wrapped in `Option` or `Vec`, but it also possible to nest der too: #![cfg_attr(not(doctest), doc = include_str!("docs2/derive_basic_nesting.md"))] + + +`external` takes an optional function name and will call that function to make the parser for +the field. You can chain more transformations after the `external` and if name is absent - +`bpaf` would use field name instead, so you can also write the example above as + + +```rust +#[derive(Debug, Clone, Bpaf)] +pub enum Format { + /// Produce output in HTML format + Html, + /// Produce output in Markdown format + Markdown, + /// Produce output in manpage format + Manpage, +} + +#[derive(Debug, Clone, Bpaf)] +#[bpaf(options)] +pub struct Options { + /// File to process + input: String, + #[bpaf(external)] + format: Format, +} +``` diff --git a/documentation/_documentation/_1_tutorials/_2_derive_api/index.md b/documentation/_documentation/_1_tutorials/_2_derive_api/index.md index 701a2dcb..6955c48b 100644 --- a/documentation/_documentation/_1_tutorials/_2_derive_api/index.md +++ b/documentation/_documentation/_1_tutorials/_2_derive_api/index.md @@ -7,7 +7,7 @@ When making a parser using Derive API you should go though approximately followi 1. Design data type your application will receive 2. Design command line options user will have to pass 3. Add `#[derive(Bpaf, Debug, Clone)]` on top of your type or types -4. Add #[bpaf(xxx)] annotations on types and fields +4. Add `#[bpaf(xxx)]` annotations on types and fields 5. And `#[bpaf(options)]` to the top type 6. Run the resulting parser diff --git a/documentation/_documentation/_1_tutorials/_3_picking_type/index.md b/documentation/_documentation/_1_tutorials/_3_picking_type/index.md index df51a608..a7de0578 100644 --- a/documentation/_documentation/_1_tutorials/_3_picking_type/index.md +++ b/documentation/_documentation/_1_tutorials/_3_picking_type/index.md @@ -15,9 +15,9 @@ implement a newtype along with `FromStr` implementation to get validation for fr parsing. -```rust -use std::str::FromStr; - +```no_run +# use std::str::FromStr; +# use bpaf::*; #[derive(Debug, Clone, Copy)] pub struct Ratio(u8); @@ -31,6 +31,17 @@ impl FromStr for Ratio { } } } + +#[derive(Debug, Clone, Bpaf)] +#[bpaf(options)] +struct Options { + /// Fill ratio + ratio: Ratio +} + +fn main() { + println!("{:?}", options().run()); +} ``` @@ -38,6 +49,8 @@ Try using enums instead of structs for mutually exclusive options: ```no_check /// Good format selection +#[derive(Debug, Clone, Bpaf)] +#[bpaf(options)] enum OutputFormat { Intel, Att, @@ -45,7 +58,8 @@ enum OutputFormat { } fn main() { - ... + let format = output_format().run(); + // `rustc` ensures you handle each case, parser won't try to consume // combinations of flags it can't represent. For example it won't accept // both `--intel` and `--att` at once @@ -63,6 +77,8 @@ consuming inside your app is more fragile ```no_check /// Bad format selection +#[derive(Debug, Clone, Bpaf)] +#[bpaf(options)] struct OutputFormat { intel: bool, att: bool, @@ -70,7 +86,7 @@ struct OutputFormat { } fn main() { - ... + let format = output_format().run(); // what happens when none matches? Or all of them? // What happens when you add a new output format? if format.intel { @@ -91,6 +107,7 @@ idea to use enum as well: ```no_check /// Good input selection +#[derive(Debug, Clone, Bpaf)] enum Input { File { filepath: PathBuf, @@ -107,12 +124,12 @@ If your codebase uses newtype pattern - it's a good idea to use it starting from options: ```no_check +#[derive(Debug, Clone, Bpaf)] struct Options { // better than taking a String and parsing internally date: NaiveDate, // f64 might work too, but you can start from some basic sanity checks speed: Speed - ... } ``` diff --git a/src/_documentation.rs b/src/_documentation.rs index a8535082..3a8a9a16 100644 --- a/src/_documentation.rs +++ b/src/_documentation.rs @@ -45,7 +45,7 @@ //! ## Parse, don't validate //! //! `bpaf` tries hard to let you to move as much invariants about the user input you are - //! trying to parse into rust type: for mutually exclusive options you can get `enum` with + //! trying to parse into rust types: for mutually exclusive options you can get `enum` with //! exclusive items going into separate branches, you can collect results into types like //! [`BTreeSet`](std::collections::BTreeSet), or whatever custom type you might have with //! custom parsing. Ideas for @@ -53,14 +53,14 @@ //! and [using parsing over validation](https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/) //! are not new. //! - //! That said you can also validate your inputs if this fits your problem better. If you want to + //! That said you can also validate your inputs if this fits your situation better. If you want to //! ensure that sum of every numeric fields must be divisible by both 3 and 5, but only when it's //! Thursday - you can do that too. //! //! ## Flexibility //! //! While aiming to be a general purpose command line parser `bpaf` offers a few backdoors that - //! allow to parse pretty much anything you want: chained commands, custom blocks of options, DOS + //! allow you to parse pretty much anything you want: chained commands, custom blocks of options, DOS //! style options (`/ofile.pas`), `dd` style options (`if=file of=out`), etc. Similar idea applies //! for what the parser can produce - your app operates with boxed string slices internally? `bpaf` //! will give you `Box` instead of `String` if you ask it to. @@ -89,7 +89,7 @@ //! ## Performance //! //! While performance is an explicit non goal - `bpaf` does nothing that would pessimize it either, - //! so performance is on par or better compared to fully featured parsers. + //! so performance is on par or better compared to other fully featured parsers. //! //! ## Correctness //! @@ -208,11 +208,10 @@ //! //! //! `cargo` here is an executable name, everything to the right of it separated by spaces are the - //! q! //! options. //! //! Nowdays programs share mostly similar conventions about what a command line argument is, it - //! wasn't the case before though. Let's cover the basic types + //! wasn't the case before though. Let's cover the basic types. //! //! - [Options, switches or flags](_0_switch) //! - [Option arguments or arguments](_1_argument) @@ -258,7 +257,7 @@ //! #### Options, switches or flags //! //! Options or flags usually starts with a dash, single dash for short options and double dash for - //! long one. Several short options usually can be squashed together with a single dash between + //! long one. Several short options can usually be squashed together with a single dash in front of //! them to save on typing: `-vvv` can be parsed the same as `-v -v -v`. Options don't have any //! other information apart from being there or not. Relative position usually does not matter and //! `--alpha --beta` should parse the same as `--beta --alpha`. @@ -447,8 +446,8 @@ //! //! #### Commands or subcommands //! - //! Commands are similar to positional items, but instead of representing an item they represent - //! a new parser, usually with its own help and other arguments. Commands allow a single + //! Commands are similar to positional items, but instead of representing an item they start + //! a whole new parser, usually with its own help and other arguments. Commands allow a single //! applications to perform multiple different functions. Command parser will be able to parse all //! the command line options to the right of the command name //! @@ -509,7 +508,7 @@ //! //! While modern software tends to use just the options listed above you can still encounter //! programs created before those options became norm and they use something complitely different, - //! let me give a few examples, see [exotic howto](crate::_documentation::_2_howto) + //! let me give a few examples, see [the parsing cookbook](crate::_documentation::_2_howto) //! about actually parsing them //! //! `su` takes an option that consists of a single dash `-` @@ -774,14 +773,18 @@ //! # use bpaf::*; //! # use std::path::PathBuf; //! fn simple_argument_1() -> impl Parser { + //! // rustc figures out the type from returned value //! long("number").argument("NUM") //! } //! //! fn simple_argument_2() -> impl Parser { + //! // type is specified explicitly with turbofish //! long("name").argument::("NAME") //! } //! //! fn file_parser() -> OptionParser { + //! // OptionParser is a type for finalized parser, at this point you can + //! // start adding extra information to the `--help` message //! long("file").argument::("FILE").to_options() //! } //! ``` @@ -837,9 +840,9 @@ //! #### Positional item parser //! //! And the last simple option type is parser for positional items. Since there's no name you use - //! [`positional`] method directly which behaves similarly to [`NamedArg::argument`] - takes - //! metavariable name and a type parameter in some form. You can also attach help message directly - //! to it thanks to [`ParsePositional::help`] + //! [`positional`] method directly. Similar to [`NamedArg::argument`] this method takes + //! metavariable name and a type parameter in some form. You can also attach the help message + //! thanks to [`ParsePositional::help`] //! //! Full example: #![cfg_attr(not(doctest), doc = include_str!("docs2/compose_basic_positional.md"))] @@ -969,7 +972,7 @@ //! One of the important types of transformations you can apply is a set of failing //! transformations. Suppose your application operates with numbers and uses `newtype` pattern to //! keep track what numbers are odd or even. Parser that consumes an even number can use - //! [`Parser::parse`] and look like this: + //! [`Parser::parse`] and may look like this: //! //! ```rust //! # use bpaf::*; @@ -1057,6 +1060,8 @@ //! //! fn both() -> impl Parser { //! let beta = long("beta").argument("BETA"); + //! // call `alpha` function, and use result to make parser + //! // for field `alpha`, use parser `beta` for field `beta` //! construct!(Options { alpha(), beta }) //! } //! ``` @@ -1068,8 +1073,8 @@ //! order you specify them. For named parsers order affects only the `--help` message. //! //! Second type of composition `construct!` offers is a parallel composition. You pass multiple - //! parsers that produce the same result type and `bpaf` runs one that fits best with the data user - //! gave. + //! parsers that produce the same result type in `[]` and `bpaf` selects one that fits best with + //! the data user gave. //! //! #![cfg_attr(not(doctest), doc = include_str!("docs2/compose_basic_choice.md"))] @@ -1210,7 +1215,7 @@ //! - add a test to make sure that bpaf internal invariants are satisfied with //! [`OptionParser::check_invariants`] //! - generate user documentation in manpage and markdown formats with - //! [`OptionParser::render_manpage] and [`OptionParser::render_markdown`] + //! [`OptionParser::render_manpage`] and [`OptionParser::render_markdown`] //! //! //!   @@ -1264,7 +1269,7 @@ //! 1. Design data type your application will receive //! 2. Design command line options user will have to pass //! 3. Add `#[derive(Bpaf, Debug, Clone)]` on top of your type or types - //! 4. Add #[bpaf(xxx)] annotations on types and fields + //! 4. Add `#[bpaf(xxx)]` annotations on types and fields //! 5. And `#[bpaf(options)]` to the top type //! 6. Run the resulting parser //! @@ -1438,11 +1443,11 @@ //! By default `bpaf` picks parsers depending on a field type according to those rules: //! //! 1. `bool` fields are converted into switches: [`NamedArg::switch`](crate::parsers::NamedArg::switch) - //! 2. `()` (unit) fields, unit variants of enum or unit structs themselves are handled as req_flag + //! 2. `()` (unit) fields, unit variants of enum or unit structs themselves are handled as //! [`NamedArg::req_flag`](crate::parsers::NamedArg::req_flag) and thus users must always specify //! them for parser to succeed //! 3. All other types with no `Vec`/`Option` are parsed using [`FromStr`](std::str::FromStr), but in a - //! smart way, so Non-utf8 `PathBuf`/`OsString` are working as expected. + //! smart way, so non-utf8 `PathBuf`/`OsString` are working as expected. //! 4. For values wrapped in `Option` or `Vec` bpaf derives inner parser and then applies //! applies logic from [`Parser::optional`] and [`Parser::many`] respectively. //! @@ -1570,7 +1575,9 @@ //! #### Parsing structs and enums //! //! To produce a struct bpaf needs for all the field parsers to succeed. If you are planning to use - //! it for some other purpose as well and want to skip them during parsing you can use [`pure`]. + //! it for some other purpose as well and want to skip them during parsing you can use [`pure`] to + //! fill in values in member fields and `#[bpaf(skip)]` on enum variants you want to ignore, see + //! combinatoric example in [`Parser::last`]. //! //! If you use `#[derive(Bpaf)]` on enum parser will produce variant for which all the parsers //! succeed. @@ -1697,6 +1704,33 @@ //! too: //! #![cfg_attr(not(doctest), doc = include_str!("docs2/derive_basic_nesting.md"))] + //! + //! + //! `external` takes an optional function name and will call that function to make the parser for + //! the field. You can chain more transformations after the `external` and if name is absent - + //! `bpaf` would use field name instead, so you can also write the example above as + //! + //! + //! ```rust + //! #[derive(Debug, Clone, Bpaf)] + //! pub enum Format { + //! /// Produce output in HTML format + //! Html, + //! /// Produce output in Markdown format + //! Markdown, + //! /// Produce output in manpage format + //! Manpage, + //! } + //! + //! #[derive(Debug, Clone, Bpaf)] + //! #[bpaf(options)] + //! pub struct Options { + //! /// File to process + //! input: String, + //! #[bpaf(external)] + //! format: Format, + //! } + //! ``` //! //! //!   @@ -1870,9 +1904,9 @@ //! parsing. //! //! - //! ```rust - //! use std::str::FromStr; - //! + //! ```no_run + //! # use std::str::FromStr; + //! # use bpaf::*; //! #[derive(Debug, Clone, Copy)] //! pub struct Ratio(u8); //! @@ -1886,6 +1920,17 @@ //! } //! } //! } + //! + //! #[derive(Debug, Clone, Bpaf)] + //! #[bpaf(options)] + //! struct Options { + //! /// Fill ratio + //! ratio: Ratio + //! } + //! + //! fn main() { + //! println!("{:?}", options().run()); + //! } //! ``` //! //! @@ -1893,6 +1938,8 @@ //! //! ```no_check //! /// Good format selection + //! #[derive(Debug, Clone, Bpaf)] + //! #[bpaf(options)] //! enum OutputFormat { //! Intel, //! Att, @@ -1900,7 +1947,8 @@ //! } //! //! fn main() { - //! ... + //! let format = output_format().run(); + //! //! // `rustc` ensures you handle each case, parser won't try to consume //! // combinations of flags it can't represent. For example it won't accept //! // both `--intel` and `--att` at once @@ -1918,6 +1966,8 @@ //! //! ```no_check //! /// Bad format selection + //! #[derive(Debug, Clone, Bpaf)] + //! #[bpaf(options)] //! struct OutputFormat { //! intel: bool, //! att: bool, @@ -1925,7 +1975,7 @@ //! } //! //! fn main() { - //! ... + //! let format = output_format().run(); //! // what happens when none matches? Or all of them? //! // What happens when you add a new output format? //! if format.intel { @@ -1946,6 +1996,7 @@ //! //! ```no_check //! /// Good input selection + //! #[derive(Debug, Clone, Bpaf)] //! enum Input { //! File { //! filepath: PathBuf, @@ -1962,12 +2013,12 @@ //! options: //! //! ```no_check + //! #[derive(Debug, Clone, Bpaf)] //! struct Options { //! // better than taking a String and parsing internally //! date: NaiveDate, //! // f64 might work too, but you can start from some basic sanity checks //! speed: Speed - //! ... //! } //! ``` //! diff --git a/src/params.rs b/src/params.rs index a276c126..fd1682a6 100644 --- a/src/params.rs +++ b/src/params.rs @@ -406,6 +406,16 @@ impl

ParseCommand

{ /// allowing only "vertical" chaining of commands. `adjacent` modifier lets command parser to /// succeed if there are leftovers for as long as all comsumed items form a single adjacent /// block. This opens possibilities to chain commands sequentially. + /// + /// Let's consider two examples with consumed items marked in bold : + /// + /// - **cmd** **-a** -b **-c** -d + /// - **cmd** **-a** **-c** -b -d + /// + /// In the first example `-b` breaks the adjacency for all the consumed items so parsing will fail, + /// while here in the second one the name and all the consumed items are adjacent to each other so + /// parsing will succeed. + /// #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_command.md"))] #[must_use] pub fn adjacent(mut self) -> Self { diff --git a/src/structs.rs b/src/structs.rs index 9dbc08d9..f3e7755c 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -877,6 +877,16 @@ impl ParseCon { /// sequential subset of arguments - `adjacent` might be able to help you. Check the examples /// for better intuition. /// + /// Let's consider two examples with consumed items marked in bold and constructor containing + /// parsers for `-c` and `-d`. + /// + /// - **-a** -b **-c** -d + /// - **-a** **-c** -b -d + /// + /// In the first example `-b` breaks the adjacency for all the consumed items so parsing will fail, + /// while here in the second one all the consumed items are adjacent to each other so + /// parsing will succeed. + /// /// # Multi-value arguments /// /// Parsing things like `--point X Y Z`