From 5a7ab79e2607fe5c9510df553a1def83100daf36 Mon Sep 17 00:00:00 2001 From: CreepySkeleton Date: Wed, 28 Aug 2019 19:52:09 +0300 Subject: [PATCH] Update documentation and changelog --- CHANGELOG.md | 172 ++++++++++++++++++++++++++++++++++++-------- examples/skip.rs | 36 ++++++++++ src/lib.rs | 182 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 309 insertions(+), 81 deletions(-) create mode 100644 examples/skip.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 446a15af..db9fd35a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,45 +2,159 @@ ## Breaking changes -* Bump minimum rust version to 1.34 by [@TeXitoi](https://github.com/TeXitoi) +### Bump minimum rustc version to 1.34 by [@TeXitoi](https://github.com/TeXitoi) +Now `rustc` 1.34 is the minimum compiler version supported by `structopt`, +it likely won't work with older compilers. -* Support optional vectors of arguments for distinguishing between `-o 1 2`, `-o` and no option provided at all - by [@sphynx](https://github.com/sphynx) - ([#180](https://github.com/TeXitoi/structopt/issues/188)). This is a breaking change - as `Option>` is handled differently. If you need to have a `Option>` - handled the old was, you can `type Something = Vec;` and then use `Option` - as your structopt field. +### Remove "nightly" feature +Once upon a time this feature had been used to enable some of improvements +in `proc-macro2` crate that were available only on nightly. Nowadays this feature doesn't +mean anything so it's now removed. -* Change default case from 'Verbatim' into 'Kebab' by [@0ndorio](https://github.com/0ndorio) - ([#202](https://github.com/TeXitoi/structopt/issues/202)). This is a breaking change. - If you rely on the old behavior you need to add `#[structopt(rename_all = "verbatim")]` - as an attribute to each data structure deriving the `StructOpt` trait. +### Support optional vectors of arguments for distinguishing between `-o 1 2`, `-o` and no option provided at all by [@sphynx](https://github.com/sphynx) ([#180](https://github.com/TeXitoi/structopt/issues/188)). -* Change `version`, `author` and `about` attributes behavior. `version/author/about = ""` is no longer a - valid syntax. `author` and `about` are no longer derived from `Cargo.toml` by default, i.e when no - attributes mentioned. `version` is still to be derived from `Cargo.toml` by default. - Introduced explicit `author` and `about` attributes (with no arguments, i.e `#[structopt(author)]`) - for explicit requests to deduce author/about fields from `Cargo.toml`. - `version/author/about = "version/author/about"` is still valid syntax. - Introduced `no_version` attribute (no args) which prevents version auto deducing by default. - Proposed by [@TeXitoi](https://github.com/TeXitoi) [(#217)](https://github.com/TeXitoi/structopt/issues/217), implemented by [@CreepySkeleton](https://github.com/CreepySkeleton) [(#229)](https://github.com/TeXitoi/structopt/pull/229). +```rust +#[derive(StructOpt)] +struct Opt { + #[structopt(long)] + fruit: Option>, +} + +fn main() { + assert_eq!(Opt::from_args(&["test"]), None); + assert_eq!(Opt::from_args(&["test", "--fruit"]), Some(vec![])); + assert_eq!(Opt::from_args(&["test", "--fruit=apple orange"]), Some(vec!["apple", "orange"])); +} +``` + +If you need to fall back to the old behavior you can use a type alias: +```rust +type Something = Vec; + +#[derive(StructOpt)] +struct Opt { + #[structopt(long)] + fruit: Option>, +} +``` + +### Change default case from 'Verbatim' into 'Kebab' by [@0ndorio](https://github.com/0ndorio) ([#202](https://github.com/TeXitoi/structopt/issues/202)). +`structopt` 0.3 uses field renaming to deduce a name for long options and subcommands. + +```rust +#[derive(StructOpt)] +struct Opt { + #[structopt(long)] + http_addr: String, // will be renamed to `--http-addr` + + #[structopt(subcommand)] + addr_type: AddrType // this adds `addr-type` subcommand +} +``` + +`structopt` 0.2 used to leave things "as is", not renaming anything. If you want to keep old +behavior add `#[structopt(rename_all = "verbatim")]` on top of a `struct`/`enum`. + +### Change `version`, `author` and `about` attributes behavior. +Proposed by [@TeXitoi](https://github.com/TeXitoi) [(#217)](https://github.com/TeXitoi/structopt/issues/217), implemented by [@CreepySkeleton](https://github.com/CreepySkeleton) [(#229)](https://github.com/TeXitoi/structopt/pull/229). + +`structopt` have been deducing `version`, `author`, and `about` properties from `Cargo.toml` +for a long time (more accurately, from `CARGO_PKG_...` environment variables). +But many users found this behavior somewhat confusing, and a hack was added to cancel out +this behavior: `#[structopt(author = "")]`. + +In `structopt` 0.3 this has changed. +* `author` and `about` are no longer deduced by default. You should use `#[structopt(author, about)]` + to explicitly request `structopt` to deduce them. +* Contrary, `version` **is still deduced by default**. You can use `#[structopt(no_version)]` to + cancel it out. +* `#[structopt(author = "", about = "", version = "")]` is no longer a valid syntax + and will trigger an error. +* `#[structopt(version = "version", author = "author", about = "about")]` syntax + stays unaffected by this changes. + +### Raw attributes are removed ([#198](https://github.com/TeXitoi/structopt/pull/198)) by [@sphynx](https://github.com/sphynx) +In `structopt` 0.2 you were able to use any method from `clap::App` and `clap::Arg` via +raw attribute: `#[structopt(raw(method_name = "arg"))]`. This syntax was kind of awkward. + +```rust +#[derive(StructOpt, Debug)] +#[structopt(raw( + global_settings = "&[AppSettings::ColoredHelp, AppSettings::VersionlessSubcommands]" +))] +struct Opt { + #[structopt(short = "l", long = "level", raw(aliases = r#"&["set-level", "lvl"]"#))] + level: Vec, +} +``` + +Raw attributes were removed in 0.3. Now you can use any method from `App` and `Arg` *directly*: +```rust +#[derive(StructOpt)] +#[structopt(global_settings(&[AppSettings::ColoredHelp, AppSettings::VersionlessSubcommands]))] +struct Opt { + #[structopt(short = "l", long = "level", aliases(&["set-level", "lvl"]))] + level: Vec, +} +``` + +## Improvements + +### Support skipping struct fields +Proposed by [@Morganamilo](https://github.com/Morganamilo) in ([#174](https://github.com/TeXitoi/structopt/issues/174)) +implemented by [@sphynx](https://github.com/sphynx) in ([#213](https://github.com/TeXitoi/structopt/issues/213)). + +Sometimes you want to include some fields in your `StructOpt` `struct` that are not options +and `clap` should know nothing about them. In `structopt` 0.3 it's possible via the +`#[structopt(skip)]` attribute. The field in question will be assigned with `Default::default()` +value. -## improvements +```rust +#[derive(StructOpt)] +struct Opt { + #[structopt(short, long)] + speed: f32, + + car: String, + + // this field should not generate any arguments + #[structopt(skip)] + meta: Vec +} +``` -* Support skipping struct fields by [@sphynx](https://github.com/sphynx) - ([#174](https://github.com/TeXitoi/structopt/issues/174)) +### Add optional feature to support `paw` by [@gameldar](https://github.com/gameldar) ([#187](https://github.com/TeXitoi/structopt/issues/187)) -* Add optional feature to support `paw` by [@gameldar](https://github.com/gameldar) - ([#187](https://github.com/TeXitoi/structopt/issues/187)) +### Significantly improve error reporting by [@CreepySkeleton](https://github.com/CreepySkeleton) ([#225](https://github.com/TeXitoi/structopt/pull/225/)) +Now (almost) every error message points to the location it originates from: -* Significantly improve error reporting by [@CreepySkeleton](https://github.com/CreepySkeleton) - ([#225](https://github.com/TeXitoi/structopt/pull/225/)) +```text +error: default_value is meaningless for bool + --> $DIR/bool_default_value.rs:14:24 + | +14 | #[structopt(short, default_value = true)] + | ^^^^^^^^^^^^^ +``` # v0.2.16 (2019-05-29) -* Support optional options with optional argument, allowing `cmd [--opt[=value]]` - by [@sphynx](https://github.com/sphynx) - ([#188](https://github.com/TeXitoi/structopt/issues/188)) +### Support optional options with optional argument, allowing `cmd [--opt[=value]]` by [@sphynx](https://github.com/sphynx) ([#188](https://github.com/TeXitoi/structopt/issues/188)) +Sometimes you want to represent an optional option that optionally takes an argument, +i.e `[--opt[=value]]`. This is represented by `Option>` + +```rust +#[derive(StructOpt)] +struct Opt { + #[structopt(long)] + fruit: Option>, +} + +fn main() { + assert_eq!(Opt::from_args(&["test"]), None); + assert_eq!(Opt::from_args(&["test", "--fruit"]), Some(None)); + assert_eq!(Opt::from_args(&["test", "--fruit=apple"]), Some("apple")); +} +``` # v0.2.15 (2019-03-08) diff --git a/examples/skip.rs b/examples/skip.rs new file mode 100644 index 00000000..40404df7 --- /dev/null +++ b/examples/skip.rs @@ -0,0 +1,36 @@ +use structopt::StructOpt; + +#[derive(StructOpt, Debug, PartialEq)] +#[structopt(name = "a")] +pub struct Opt { + #[structopt(long, short)] + number: u32, + #[structopt(skip)] + k: Kind, + #[structopt(skip)] + v: Vec, +} + +#[derive(Debug, PartialEq)] +#[allow(unused)] +enum Kind { + A, + B, +} + +impl Default for Kind { + fn default() -> Self { + return Kind::B; + } +} + +fn main() { + assert_eq!( + Opt::from_iter(&["test", "-n", "10"]), + Opt { + number: 10, + k: Kind::B, + v: vec![], + } + ); +} diff --git a/src/lib.rs b/src/lib.rs index a94bad81..af9279ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,6 @@ //! structopt = { version = "0.2", default-features = false } //! ``` //! -//! //! Support for [`paw`](https://github.com/rust-cli/paw) (the //! `Command line argument paw-rser abstraction for main`) is disabled //! by default, but can be enabled in the `structopt` dependency @@ -35,7 +34,7 @@ //! //! ## How to `derive(StructOpt)` //! -//! First, let's look at an example: +//! First, let's look at the example: //! //! ```should_panic //! use std::path::PathBuf; @@ -45,17 +44,29 @@ //! #[structopt(name = "example", about = "An example of StructOpt usage.")] //! struct Opt { //! /// Activate debug mode -//! #[structopt(short = "d", long = "debug")] +//! // short and long flags (-d, --debug) will be deduced from the field name +//! #[structopt(short, long)] //! debug: bool, +//! //! /// Set speed //! #[structopt(short = "s", long = "speed", default_value = "42")] //! speed: f64, +//! //! /// Input file //! #[structopt(parse(from_os_str))] //! input: PathBuf, +//! //! /// Output file, stdout if not present //! #[structopt(parse(from_os_str))] //! output: Option, +//! +//! /// Where to write the output: to `stdout` or `file` +//! #[structopt(short)] +//! out_type: String, +//! +//! /// File name: only required when `out` is set to `file` +//! #[structopt(name = "FILE", required_if("out_type", "file"))] +//! file_name: String, //! } //! //! fn main() { @@ -68,54 +79,127 @@ //! and the various `structopt` attributes are simply //! used for additional parameters. //! -//! First, define a struct, whatever its name. This structure will -//! correspond to a `clap::App`. Every method of `clap::App` in the -//! form of `fn function_name(self, &str)` can be used through attributes -//! placed on the struct. In our example above, the `about` attribute -//! will become an `.about("An example of StructOpt usage.")` call on the -//! generated `clap::App`. There are a few attributes that will default -//! if not specified: -//! -//! - `name`: The binary name displayed in help messages. Defaults -//! to the crate name given by Cargo. -//! - `version`: Defaults to the crate version given by Cargo. -//! - `author`: Defaults to the crate author name given by Cargo. -//! - `about`: Defaults to the crate description given by Cargo. -//! -//! This approach also works for other literals or expressions which -//! can be used as values of the attributes for corresponding -//! `clap::App` methods (e.g. for `fn function(self, bool)` and so -//! on). -//! -//! Then, each field of the struct not marked as a subcommand -//! corresponds to a `clap::Arg`. As with the struct attributes, every -//! method of `clap::Arg` with one argument can be used through -//! specifying it as an attribute with a value which is either a -//! literal or an expression. The `name` attribute can be used to -//! customize the `Arg::with_name()` call (defaults to the field name -//! in kebab-case). - -//! Some of the rare functions that take more than one argument can be -//! specified as function calls directly, e.g. `required_if("out", -//! "file")`. A full example: -//! +//! First, define a struct, whatever its name. This structure +//! corresponds to a `clap::App`, its fields correspond to `clap::Arg` +//! (unless they're [subcommands](#subcommands)), +//! and you can adjust these apps and args by `#[structopt(...)]` attributes. +//! +//! `#[structopt(...)]` attributes fall into two categories: +//! - `structopt`'s own [magical methods](#magical-methods), they are used by `structopt` itself. +//! They come mostly in `attr = ""` form, but some `attr(args...)` also exist. +//! - [`raw` attributes](#raw-methods) (explicit `#[structopt(raw(...))]` attrs in +//! pre-0.3 `structopt`). They represent explicit `clap::Arg/App` method calls. +//! +//! Every `structopt attribute` looks like comma-separated sequence of methods: +//! ```rust,ignore +//! #[structopt( +//! short, // method with no arguments - always magical +//! long = "--long-option", // method with one argument +//! required_if("out", "file"), // method with one or more args +//! parse(from_os_str = path::to::parser) // some magical methods have their own syntax +//! )] //! ``` -//! use structopt::StructOpt; //! -//! #[derive(StructOpt, Debug)] -//! struct Opt { -//! /// Where to write the output: to `stdout` or `file` -//! #[structopt(short = "o")] -//! out_type: String, +//! `#[structopt(...)]` attributes can be placed on top of `struct`, `enum`, `struct` field +//! or `enum` variant. Attributes on top of `struct` or `enum` represent `clap::App` method calls, +//! field or variant attributes correspond to `clap::Arg` method calls. //! -//! /// File name: only required when `out` is set to `file` -//! #[structopt(name = "FILE", required_if("out_type", "file"))] -//! file_name: String, -//! } -//! # fn main() {} +//! In other words, the `Opt` struct from the example above +//! will be turned into this (*details omitted*): +//! +//! ``` +//! # use structopt::clap::{Arg, App}; +//! App::new("example") +//! .version("0.2.0") +//! .about("An example of StructOpt usage.") +//! .arg(Arg::with_name("debug") +//! .help("Activate debug mode") +//! .short("debug") +//! .long("debug")) +//! .arg(Arg::with_name("speed") +//! .help("Set speed") +//! .short("s") +//! .long("speed") +//! .default_value("42")) +//! // and so on +//! # ; //! ``` //! -//! The type of the field gives the kind of argument: +//! ## Raw methods +//! +//! They are the reason why `structopt` is so flexible. +//! +//! Each and every method from `clap::App` and `clap::Arg` can be used directly - +//! just `#[structopt(method_name = single_arg)]` or `#[structopt(method_name(arg1, arg2))]` +//! and it just works. As long as `method_name` is not one of magical methods - +//! it's just a method call. +//! +//! **Note:** the `Arg::raw` method is allowed only with `true` or `false` literals. +//! +//! ## Magical methods +//! +//! They are the reason why `structopt` is so easy to use and convenient in most cases. +//! Many of them have defaults, some of them are used even if not mentioned. +//! +//! - `name`: `[name = "name"]` +//! - On top of a `struct`: `App::new("name")`. +//! +//! The binary name displayed in help messages. Defaults to the crate name given by Cargo. +//! +//! - On top of a field: `Arg::with_name("name")`. +//! +//! The name for the argument the field stands for, this name appears in help messages. +//! Defaults to a name, deduced from a field, see also [`rename_all`](#specifying-argument-types). +//! +//! - `version`: `[version = "version"]` +//! +//! Usable only on top of a `struct`: `App::version("version" or env!(CARGO_PKG_VERSION))`. +//! +//! The version displayed in help messages. +//! Defaults to the crate version given by Cargo. +//! +//! - `no_version`: `no_version` +//! +//! Usable only on top of a `struct`. Prevents default `App::version` call, i.e +//! when no `version = "version"` mentioned. +//! +//! - `author`: `author [= "author"]` +//! +//! Usable only on top of a `struct`: `App::author("author" or env!(CARGO_PKG_AUTHOR))`. +//! +//! Author/maintainer of the binary, this name appears in help messages. +//! Defaults to the crate author given by cargo, but only when `author` explicitly mentioned. +//! +//! - `about`: `about [= "about"]` +//! +//! Usable only on top of a `struct`: `App::about("about" or env!(CARGO_PKG_DESCRIPTION))`. +//! Short description of the binary, appears in help messages. +//! Defaults to the crate description given by cargo, +//! but only when `about` explicitly mentioned. +//! +//! - [`short`](#specifying-argument-types): `short [= "short-opt-name"]` +//! +//! Usable only on top of a field. +//! +//! - [`long`](#specifying-argument-types): `long [= "long-opt-name"]` +//! +//! Usable only on top of a field. +//! +//! - [`rename_all`](#specifying-argument-types): [`rename_all = "kebab"/"snake"/"screaming-snake"/"camel"/"pascal"/"verbatim"]` +//! +//! Usable only on top of a `struct` +//! +//! - [`parse`](#custom-string-parsers): `parse(type [= path::to::parser::fn])` +//! +//! Usable only on top of a field. +//! +//! ## Type magic +//! +//! One of major things that makes `structopt` so awesome is it's type magic. +//! Do you want optional positional argument? Use `Option`! Or perhaps optional argument +//! that optionally takes value (`[--opt=[val]]`)? Use `Option>`! +//! +//! Here is the table of types and `clap` methods they correspond to: //! //! Type | Effect | Added method call to `clap::Arg` //! -----------------------------|---------------------------------------------------|-------------------------------------- @@ -126,12 +210,6 @@ //! `Option` | optional list of options | `.takes_values(true).multiple(true).min_values(0)` //! `T: FromStr` | required option or positional argument | `.takes_value(true).multiple(false).required(!has_default)` //! -//! Note that `Option>` allows to express options like -//! `[--opt=[val]]` which can have three values: `None` if `--opt` was -//! not mentioned, `Some(None)` if it was mentioned, but didn't have -//! value (`--opt`) and `Some(Some(val))` for `--opt=val` case. -//! Similar reasoning also applies to `Option>`. -//! //! The `FromStr` trait is used to convert the argument to the given //! type, and the `Arg::validator` method is set to a method using //! `to_string()` (`FromStr::Err` must implement `std::fmt::Display`).