Skip to content

Commit

Permalink
Pre release tweaks and changelog
Browse files Browse the repository at this point in the history
  • Loading branch information
CreepySkeleton authored and TeXitoi committed Dec 22, 2019
1 parent 3534cb3 commit 920e84f
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 16 deletions.
12 changes: 7 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
language: rust
matrix:
include:
- rust: 1.36.0
- rust: stable
- rust: beta
- rust: nightly

- rust: stable
name: check if `cargo fmt --all` is applied
before_script: rustup component add rustfmt-preview
Expand All @@ -17,6 +12,13 @@ matrix:
install: npm install -g markdown-link-check
script:
- markdown-link-check -c link-check-headers.json README.md
- markdown-link-check -c link-check-headers.json CHANGELOG.md
- markdown-link-check -c link-check-headers.json examples/README.md

- rust: 1.36.0
- rust: stable
- rust: beta
- rust: nightly

script:
- cargo test $FEATURES
70 changes: 67 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,74 @@
# [Upcoming]

* **Bugfix**: `structopt` used to treat `::path::to::type::Vec<T>` as `Vec<T>`
This is unusually big patch release. It contains a number of bugfixes and
new features, some of them may theoretically be considered breaking. We did our best
to avoid any problems on user's side but, if it wasn't good enough, please
[file an issue ASAP](https://github.com/TeXitoi/structopt/issues).

### Bugfixes

* `structopt` used to treat `::path::to::type::Vec<T>` as `Vec<T>`
special type. [This was considered erroneous](https://github.com/TeXitoi/structopt/pull/287).
(same for `Option<T>` and `bool`). Now only exact `Vec<T>` match is a special type.
* Top level `#structopt[...]` raw methods on inner atructs/enums now work as expected
([#151](https://github.com/TeXitoi/structopt/issues/151)) ([#289](https://github.com/TeXitoi/structopt/issues/289)).

* `#[structopt(version = expr)]` where `expr` is not a string literal used to get
overridden by auto generated `.version()` call,
[incorrectly](https://github.com/TeXitoi/structopt/issues/283). Now it doesn't.

* Fixed bug with top-level `App::*` calls on multiple `struct`s, see
[#289](https://github.com/TeXitoi/structopt/issues/265).

* Positional `bool` args with no explicit `#[structopt(parse(...))]` annotation are
now prohibited. This couldn't work well anyway, see
[this example](https://github.com/TeXitoi/structopt/blob/master/examples/true_or_false.rs)
for details.

* Now we've instituted strict priority between doc comments, about, help, and the like.
See [the documentation](https://docs.rs/structopt/0.3/structopt/#help-messages).

**HUGE THANKS to [`@ssokolow`](https://github.com/ssokolow)** for tidying up our documentation,
teaching me English and explaining why our doc used to suck. I promise I'll make the rest
of the doc up to your standards... sometime later!

### New features

* Implement `StructOpt` for `Box<impl StructOpt>` so from now on you can use `Box<T>`
with `flatten` and `subcommand` ([#304](https://github.com/TeXitoi/structopt/issues/304)).

```rust
enum Command {
#[structopt(name = "version")]
PrintVersion,

#[structopt(name = "second")]
DoSomething {
#[structopt(flatten)]
config: Box<DoSomethingConfig>,
},

#[structopt(name = "first")]
DoSomethingElse {
#[structopt(flatten)]
config: Box<DoSomethingElseConfig>,
}
}
```

* Introduced `#[structopt(verbatim_doc_comment)]` attribute that keeps line breaks in
doc comments, see
[the documentation](https://docs.rs/structopt/0.3/structopt/#doc-comment-preprocessing-and-structoptverbatim_doc_comment).

* Introduced `#[structopt(rename_all_env)]` and `#[structopt(env)]` magical methods
so you can derive env var's name from field's name. See
[the documentation](https://docs.rs/structopt/0.3/structopt/#auto-deriving-environment-variables).

### Improvements

* Now we have nice README for our examples,
[check it out](https://github.com/TeXitoi/structopt/tree/master/examples)!

* Some error messages were improved and clarified, thanks for all people involved!


# v0.3.5 (2019-11-22)

Expand Down
17 changes: 15 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,13 +261,13 @@
//!
//! - [`rename_all`](#specifying-argument-types): [`rename_all = "kebab"/"snake"/"screaming-snake"/"camel"/"pascal"/"verbatim"]`
//!
//! Usable only on top level
//! Usable both on top level and field level.
//!
//! - [`parse`](#custom-string-parsers): `parse(type [= path::to::parser::fn])`
//!
//! Usable only on field-level.
//!
//! - [`skip`](#skipping-fields): `skip = [expr]`
//! - [`skip`](#skipping-fields): `skip [= expr]`
//!
//! Usable only on field-level.
//!
Expand All @@ -279,6 +279,19 @@
//!
//! Usable only on field-level.
//!
//! - [`env`](#environment-variable-fallback): `env [= str_literal]`
//!
//! Usable only on field-level.
//!
//! - [`rename_all_env`](##auto-deriving-environment-variables): [`rename_all_env = "kebab"/"snake"/"screaming-snake"/"camel"/"pascal"/"verbatim"]`
//!
//! Usable both on top level and field level.
//!
//! - [`verbatim_doc_comment`](#doc-comment-preprocessing-and-structoptverbatim_doc_comment):
//! `verbatim_doc_comment`
//!
//! Usable both on top level and field level.
//!
//! ## Type magic
//!
//! One of major things that makes `structopt` so awesome is it's type magic.
Expand Down
40 changes: 35 additions & 5 deletions structopt-derive/src/parse.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::iter::FromIterator;

use proc_macro2::TokenStream;
use proc_macro_error::{abort, ResultExt};
use quote::ToTokens;
use syn::{
self, parenthesized,
parse::{Parse, ParseBuffer, ParseStream},
Expand Down Expand Up @@ -229,19 +229,49 @@ impl Parse for ParserSpec {
}
}

struct CommaSeparated<T>(Punctuated<T, Token![,]>);

impl<T: Parse> Parse for CommaSeparated<T> {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
let res = Punctuated::parse_separated_nonempty(input)?;
Ok(CommaSeparated(res))
}
}

fn raw_method_suggestion(ts: ParseBuffer) -> String {
let do_parse = move || -> Result<(Ident, TokenStream), syn::Error> {
let do_parse = move || -> Result<(Ident, CommaSeparated<Expr>), syn::Error> {
let name = ts.parse()?;
let _eq: Token![=] = ts.parse()?;
let val: LitStr = ts.parse()?;
Ok((name, syn::parse_str(&val.value())?))
};

fn to_string<T: ToTokens>(val: &T) -> String {
val.to_token_stream()
.to_string()
.replace(" ", "")
.replace(",", ", ")
}

if let Ok((name, val)) = do_parse() {
let val = val.to_string().replace(" ", "").replace(",", ", ");
let exprs = val.0;
let suggestion = if exprs.len() == 1 {
let val = to_string(&exprs[0]);
format!(" = {}", val)
} else {
let val = exprs
.into_iter()
.map(|expr| to_string(&expr))
.collect::<Vec<_>>()
.join(", ");

format!("({})", val)
};

format!(
"if you need to call `clap::Arg/App::{}` method you \
can do it like this: #[structopt({}({}))]",
name, name, val
can do it like this: #[structopt({}{})]",
name, name, suggestion
)
} else {
"if you need to call some method from `clap::Arg/App` \
Expand Down
3 changes: 3 additions & 0 deletions tests/issues.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ fn issue_151() {
assert!(Cli::clap()
.get_matches_from_safe(&["test", "--zebra"])
.is_err());
assert!(Cli::clap()
.get_matches_from_safe(&["test", "--foo", "--bar"])
.is_ok());
}

#[test]
Expand Down
5 changes: 5 additions & 0 deletions tests/ui/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ struct Opt {
s: String,
}

#[derive(StructOpt, Debug)]
struct Opt2 {
#[structopt(raw(requires_if = r#""one", "two""#))]
s: String,
}
fn main() {
let opt = Opt::from_args();
println!("{:?}", opt);
Expand Down
12 changes: 11 additions & 1 deletion tests/ui/raw.stderr
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
error: `#[structopt(raw(...))` attributes are removed in structopt 0.3, they are replaced with raw methods

= help: if you meant to call `clap::Arg::raw()` method you should use bool literal, like `raw(true)` or `raw(false)`
= note: if you need to call `clap::Arg/App::case_insensitive` method you can do it like this: #[structopt(case_insensitive(true))]
= note: if you need to call `clap::Arg/App::case_insensitive` method you can do it like this: #[structopt(case_insensitive = true)]

--> $DIR/raw.rs:13:17
|
13 | #[structopt(raw(case_insensitive = "true"))]
| ^^^

error: `#[structopt(raw(...))` attributes are removed in structopt 0.3, they are replaced with raw methods

= help: if you meant to call `clap::Arg::raw()` method you should use bool literal, like `raw(true)` or `raw(false)`
= note: if you need to call `clap::Arg/App::requires_if` method you can do it like this: #[structopt(requires_if("one", "two"))]

--> $DIR/raw.rs:19:17
|
19 | #[structopt(raw(requires_if = r#""one", "two""#))]
| ^^^

0 comments on commit 920e84f

Please sign in to comment.