diff --git a/.travis.yml b/.travis.yml index 982b0bb6..f115e505 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,9 @@ matrix: include: - rust: nightly env: FEATURES="--features nightly" - + - rust: stable + env: RUN=FMT + before_script: rustup component add rustfmt-preview + script: cargo fmt --all -- --write-mode diff script: - cargo test $FEATURES diff --git a/examples/enum_tuple.rs b/examples/enum_tuple.rs index 7edd91e8..596c060d 100644 --- a/examples/enum_tuple.rs +++ b/examples/enum_tuple.rs @@ -1,4 +1,5 @@ -#[macro_use] extern crate structopt; +#[macro_use] +extern crate structopt; use structopt::StructOpt; @@ -10,7 +11,7 @@ pub struct Foo { #[derive(Debug, StructOpt)] pub enum Command { #[structopt(name = "foo")] - Foo(Foo) + Foo(Foo), } #[derive(Debug, StructOpt)] diff --git a/examples/git.rs b/examples/git.rs index 982652fe..d4f185af 100644 --- a/examples/git.rs +++ b/examples/git.rs @@ -3,7 +3,8 @@ //! Documentation can be added either through doc comments or the //! `about` attribute. -#[macro_use] extern crate structopt; +#[macro_use] +extern crate structopt; use structopt::StructOpt; @@ -19,7 +20,7 @@ enum Opt { #[structopt(long = "all")] all: bool, #[structopt(default_value = "origin")] - repository: String + repository: String, }, #[structopt(name = "add")] /// add files to the staging area @@ -28,8 +29,8 @@ enum Opt { interactive: bool, #[structopt(short = "a")] all: bool, - files: Vec - } + files: Vec, + }, } fn main() { diff --git a/examples/group.rs b/examples/group.rs index 9b92691a..40898ff5 100644 --- a/examples/group.rs +++ b/examples/group.rs @@ -14,8 +14,7 @@ fn vers_arg_group() -> ArgGroup<'static> { // As the attributes of the struct are executed before the struct // fields, we can't use .args(...), but we can use the group // attribute on the fields. - ArgGroup::with_name("vers") - .required(true) + ArgGroup::with_name("vers").required(true) } #[derive(StructOpt, Debug)] diff --git a/examples/keyvalue.rs b/examples/keyvalue.rs index 89bc653a..85a6270e 100644 --- a/examples/keyvalue.rs +++ b/examples/keyvalue.rs @@ -1,8 +1,8 @@ #[macro_use] extern crate structopt; -use structopt::StructOpt; use std::error::Error; +use structopt::StructOpt; fn parse_key_val(s: &str) -> Result<(T, U), Box> where @@ -11,7 +11,8 @@ where U: std::str::FromStr, U::Err: Error + 'static, { - let pos = s.find('=').ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?; + let pos = s.find('=') + .ok_or_else(|| format!("invalid KEY=value: no `=` found in `{}`", s))?; Ok((s[..pos].parse()?, s[pos + 1..].parse()?)) } diff --git a/examples/no_version.rs b/examples/no_version.rs index 97ef5c4f..3f8eb126 100644 --- a/examples/no_version.rs +++ b/examples/no_version.rs @@ -7,8 +7,7 @@ use structopt::clap::AppSettings; #[derive(StructOpt, Debug)] #[structopt(name = "no_version", about = "", version = "", author = "", raw(global_settings = "&[AppSettings::DisableVersion]"))] -struct Opt { -} +struct Opt {} fn main() { let opt = Opt::from_args(); diff --git a/src/lib.rs b/src/lib.rs index ef2f3de7..3d153a82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -411,7 +411,10 @@ pub trait StructOpt { /// Gets the struct from the command line arguments. Print the /// error message and quit the program in case of failure. - fn from_args() -> Self where Self: Sized { + fn from_args() -> Self + where + Self: Sized, + { Self::from_clap(&Self::clap().get_matches()) } @@ -421,7 +424,7 @@ pub trait StructOpt { where Self: Sized, I: IntoIterator, - I::Item: Into + Clone + I::Item: Into + Clone, { Self::from_clap(&Self::clap().get_matches_from(iter)) } @@ -435,7 +438,7 @@ pub trait StructOpt { where Self: Sized, I: IntoIterator, - I::Item: Into + Clone + I::Item: Into + Clone, { Ok(Self::from_clap(&Self::clap().get_matches_from_safe(iter)?)) } diff --git a/structopt-derive/Cargo.toml b/structopt-derive/Cargo.toml index 33add54f..36681eeb 100644 --- a/structopt-derive/Cargo.toml +++ b/structopt-derive/Cargo.toml @@ -13,9 +13,9 @@ license = "Apache-2.0/MIT" travis-ci = { repository = "TeXitoi/structopt" } [dependencies] -syn = "0.13" -quote = "0.5" -proc-macro2 = "0.3" +syn = "0.14" +quote = "0.6" +proc-macro2 = "0.4" [features] nightly = ["proc-macro2/nightly"] diff --git a/structopt-derive/src/attrs.rs b/structopt-derive/src/attrs.rs index 50944268..4089b44d 100644 --- a/structopt-derive/src/attrs.rs +++ b/structopt-derive/src/attrs.rs @@ -6,10 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use proc_macro2::{Span, TokenStream}; use std::{env, mem}; -use quote::Tokens; -use syn::{self, Attribute, MetaNameValue, MetaList, LitStr, TypePath}; use syn::Type::Path; +use syn::{self, Attribute, Ident, LitStr, MetaList, MetaNameValue, TypePath}; #[derive(Copy, Clone, PartialEq, Debug)] pub enum Kind { @@ -28,14 +28,14 @@ pub enum Ty { pub struct Attrs { name: String, methods: Vec, - parser: (Parser, Tokens), + parser: (Parser, TokenStream), has_custom_parser: bool, kind: Kind, } #[derive(Debug)] struct Method { name: String, - args: Tokens, + args: TokenStream, } #[derive(Debug, PartialEq)] pub enum Parser { @@ -54,7 +54,7 @@ impl ::std::str::FromStr for Parser { "from_os_str" => Ok(Parser::FromOsStr), "try_from_os_str" => Ok(Parser::TryFromOsStr), "from_occurrences" => Ok(Parser::FromOccurrences), - _ => Err(format!("unsupported parser {}", s)) + _ => Err(format!("unsupported parser {}", s)), } } } @@ -73,10 +73,7 @@ impl Attrs { match (name, arg) { ("about", "") | ("version", "") | ("author", "") => { let methods = mem::replace(&mut self.methods, vec![]); - self.methods = methods - .into_iter() - .filter(|m| m.name != name) - .collect(); + self.methods = methods.into_iter().filter(|m| m.name != name).collect(); } ("name", new_name) => self.name = new_name.into(), (name, arg) => self.methods.push(Method { @@ -86,22 +83,23 @@ impl Attrs { } } fn push_attrs(&mut self, attrs: &[Attribute]) { + use Lit::*; use Meta::*; use NestedMeta::*; - use Lit::*; - let iter = attrs.iter() + let iter = attrs + .iter() .filter_map(|attr| { let path = &attr.path; - match quote!(#path) == quote!(structopt) { + match quote!(#path).to_string() == "structopt" { true => Some( attr.interpret_meta() - .expect(&format!("invalid structopt syntax: {}", quote!(attr))) + .expect(&format!("invalid structopt syntax: {}", quote!(attr))), ), false => None, } - }). - flat_map(|m| match m { + }) + .flat_map(|m| match m { List(l) => l.nested, tokens => panic!("unsupported syntax: {}", quote!(#tokens).to_string()), }) @@ -110,46 +108,55 @@ impl Attrs { ref tokens => panic!("unsupported syntax: {}", quote!(#tokens).to_string()), }); for attr in iter { - match attr { - NameValue(MetaNameValue { ident, lit: Str(ref value), .. }) => - self.push_str_method(ident.as_ref(), &value.value()), - NameValue(MetaNameValue { ident, lit, .. }) => { - self.methods.push(Method { - name: ident.to_string(), - args: quote!(#lit), - }) - } - List(MetaList { ident, ref nested, .. }) if ident == "parse" => { + match &attr { + NameValue(MetaNameValue { + ident, + lit: Str(value), + .. + }) => self.push_str_method(&ident.to_string(), &value.value()), + NameValue(MetaNameValue { ident, lit, .. }) => self.methods.push(Method { + name: ident.to_string(), + args: quote!(#lit), + }), + List(MetaList { ident, nested, .. }) if ident == "parse" => { if nested.len() != 1 { panic!("parse must have exactly one argument"); } self.has_custom_parser = true; - self.parser = match nested[0] { - Meta(NameValue(MetaNameValue { ident, lit: Str(ref v), .. })) => { + self.parser = match &nested[0] { + Meta(NameValue(MetaNameValue { + ident, lit: Str(v), .. + })) => { let function: syn::Path = v.parse().expect("parser function path"); - let parser = ident.as_ref().parse().unwrap(); + let parser = ident.to_string().parse().unwrap(); (parser, quote!(#function)) } Meta(Word(ref i)) => { use Parser::*; - let parser = i.as_ref().parse().unwrap(); + let parser = i.to_string().parse().unwrap(); let function = match parser { FromStr => quote!(::std::convert::From::from), TryFromStr => quote!(::std::str::FromStr::from_str), FromOsStr => quote!(::std::convert::From::from), - TryFromOsStr => panic!("cannot omit parser function name with `try_from_os_str`"), - FromOccurrences => quote!({|v| v as _}), + TryFromOsStr => panic!( + "cannot omit parser function name with `try_from_os_str`" + ), + FromOccurrences => quote!({ |v| v as _ }), }; (parser, function) } ref l @ _ => panic!("unknown value parser specification: {}", quote!(#l)), }; } - List(MetaList { ident, ref nested, .. }) if ident == "raw" => { + List(MetaList { + ident, ref nested, .. + }) if ident == "raw" => + { for method in nested { - match *method { - Meta(NameValue(MetaNameValue { ident, lit: Str(ref v), .. })) => - self.push_raw_method(ident.as_ref(), v), + match method { + Meta(NameValue(MetaNameValue { + ident, lit: Str(v), .. + })) => self.push_raw_method(&ident.to_string(), v), ref mi @ _ => panic!("unsupported raw entry: {}", quote!(#mi)), } } @@ -160,33 +167,41 @@ impl Attrs { Word(ref w) if w == "flatten" => { self.set_kind(Kind::FlattenStruct); } - ref i @ List(..) | ref i @ Word(..) => - panic!("unsupported option: {}", quote!(#i)), + ref i @ List(..) | ref i @ Word(..) => panic!("unsupported option: {}", quote!(#i)), } } } fn push_raw_method(&mut self, name: &str, args: &LitStr) { - let ts: ::proc_macro2::TokenStream = args.value().parse() - .expect(&format!("bad parameter {} = {}: the parameter must be valid rust code", name, quote!(#args))); + let ts: TokenStream = args.value().parse().expect(&format!( + "bad parameter {} = {}: the parameter must be valid rust code", + name, + quote!(#args) + )); self.methods.push(Method { name: name.to_string(), args: quote!(#(#ts)*), }) } fn push_doc_comment(&mut self, attrs: &[Attribute], name: &str) { - let doc_comments: Vec<_> = attrs.iter() + let doc_comments: Vec<_> = attrs + .iter() .filter_map(|attr| { let path = &attr.path; - match quote!(#path) == quote!(doc) { + match quote!(#path).to_string() == "doc" { true => attr.interpret_meta(), false => None, } }) .filter_map(|attr| { - use Meta::*; use Lit::*; - if let NameValue(MetaNameValue { ident, lit: Str(s), .. }) = attr { - if ident != "doc" { return None; } + use Meta::*; + if let NameValue(MetaNameValue { + ident, lit: Str(s), .. + }) = attr + { + if ident != "doc" { + return None; + } let value = s.value(); let text = value .trim_left_matches("//!") @@ -197,7 +212,7 @@ impl Attrs { .trim(); if text.is_empty() { Some("\n\n".to_string()) - } else{ + } else { Some(text.to_string()) } } else { @@ -205,7 +220,9 @@ impl Attrs { } }) .collect(); - if doc_comments.is_empty() { return; } + if doc_comments.is_empty() { + return; + } let arg = doc_comments .join(" ") .split('\n') @@ -224,7 +241,8 @@ impl Attrs { ("about", "CARGO_PKG_DESCRIPTION"), ("author", "CARGO_PKG_AUTHORS"), ]; - attrs_with_env.iter() + attrs_with_env + .iter() .filter_map(|&(m, v)| env::var(v).ok().and_then(|arg| Some((m, arg)))) .filter(|&(_, ref arg)| !arg.is_empty()) .for_each(|(name, arg)| { @@ -247,8 +265,12 @@ impl Attrs { } } fn ty_from_field(ty: &syn::Type) -> Ty { - if let Path(TypePath { path: syn::Path { ref segments, .. }, .. }) = *ty { - match segments.iter().last().unwrap().ident.as_ref() { + if let Path(TypePath { + path: syn::Path { ref segments, .. }, + .. + }) = *ty + { + match segments.iter().last().unwrap().ident.to_string().as_str() { "bool" => Ty::Bool, "Option" => Ty::Option, "Vec" => Ty::Vec, @@ -259,7 +281,7 @@ impl Attrs { } } pub fn from_field(field: &syn::Field) -> Attrs { - let name = field.ident.as_ref().unwrap().as_ref().to_string(); + let name = field.ident.as_ref().unwrap().to_string(); let mut res = Self::new(name); res.push_doc_comment(&field.attrs, "help"); res.push_attrs(&field.attrs); @@ -298,7 +320,7 @@ impl Attrs { if res.has_method("required") { panic!("required is meaningless for bool") } - }, + } Ty::Option => { if res.has_method("default_value") { panic!("default_value is meaningless for Option") @@ -306,7 +328,7 @@ impl Attrs { if res.has_method("required") { panic!("required is meaningless for Option") } - }, + } _ => (), } res.kind = Kind::Arg(ty); @@ -325,9 +347,9 @@ impl Attrs { pub fn has_method(&self, method: &str) -> bool { self.methods.iter().find(|m| m.name == method).is_some() } - pub fn methods(&self) -> Tokens { + pub fn methods(&self) -> TokenStream { let methods = self.methods.iter().map(|&Method { ref name, ref args }| { - let name: ::syn::Ident = name.as_str().into(); + let name = Ident::new(&name, Span::call_site()); quote!( .#name(#args) ) }); quote!( #(#methods)* ) @@ -335,7 +357,7 @@ impl Attrs { pub fn name(&self) -> &str { &self.name } - pub fn parser(&self) -> &(Parser, Tokens) { + pub fn parser(&self) -> &(Parser, TokenStream) { &self.parser } pub fn kind(&self) -> Kind { diff --git a/structopt-derive/src/lib.rs b/structopt-derive/src/lib.rs index 0db52cb2..025fe92f 100644 --- a/structopt-derive/src/lib.rs +++ b/structopt-derive/src/lib.rs @@ -18,15 +18,15 @@ extern crate proc_macro2; mod attrs; -use proc_macro::TokenStream; -use syn::*; +use attrs::{Attrs, Kind, Parser, Ty}; +use proc_macro2::{Span, TokenStream}; use syn::punctuated::Punctuated; -use syn::token::{Comma}; -use attrs::{Attrs, Parser, Kind, Ty}; +use syn::token::Comma; +use syn::*; /// Generates the `StructOpt` impl. #[proc_macro_derive(StructOpt, attributes(structopt))] -pub fn structopt(input: TokenStream) -> TokenStream { +pub fn structopt(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input: DeriveInput = syn::parse(input).unwrap(); let gen = impl_structopt(&input); gen.into() @@ -34,16 +34,19 @@ pub fn structopt(input: TokenStream) -> TokenStream { fn sub_type(t: &syn::Type) -> Option<&syn::Type> { let segs = match *t { - syn::Type::Path(TypePath { path: syn::Path { ref segments, .. }, .. }) => segments, + syn::Type::Path(TypePath { + path: syn::Path { ref segments, .. }, + .. + }) => segments, _ => return None, }; match *segs.iter().last().unwrap() { PathSegment { - arguments: PathArguments::AngleBracketed( - AngleBracketedGenericArguments { ref args, .. } - ), + arguments: + PathArguments::AngleBracketed(AngleBracketedGenericArguments { ref args, .. }), .. - } if args.len() == 1 => { + } if args.len() == 1 => + { if let GenericArgument::Type(ref ty) = args[0] { Some(ty) } else { @@ -56,19 +59,24 @@ fn sub_type(t: &syn::Type) -> Option<&syn::Type> { /// Generate a block of code to add arguments/subcommands corresponding to /// the `fields` to an app. -fn gen_augmentation(fields: &Punctuated, app_var: &Ident) -> quote::Tokens { - let subcmds: Vec = fields.iter() +fn gen_augmentation(fields: &Punctuated, app_var: &Ident) -> TokenStream { + let subcmds: Vec<_> = fields + .iter() .filter_map(|field| { let attrs = Attrs::from_field(&field); if let Kind::Subcommand(ty) = attrs.kind() { let subcmd_type = match (ty, sub_type(&field.ty)) { (Ty::Option, Some(sub_type)) => sub_type, - _ => &field.ty + _ => &field.ty, }; let required = if ty == Ty::Option { quote!() } else { - quote!( let #app_var = #app_var.setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp); ) + quote! { + let #app_var = #app_var.setting( + ::structopt::clap::AppSettings::SubcommandRequiredElseHelp + ); + } }; Some(quote!{ @@ -81,64 +89,70 @@ fn gen_augmentation(fields: &Punctuated, app_var: &Ident) -> quote }) .collect(); - assert!(subcmds.len() <= 1, "cannot have more than one nested subcommand"); + assert!( + subcmds.len() <= 1, + "cannot have more than one nested subcommand" + ); - let args = fields.iter() - .filter_map(|field| { - let attrs = Attrs::from_field(field); - match attrs.kind() { - Kind::Subcommand(_) => None, - Kind::FlattenStruct => { - let ty = &field.ty; - Some(quote! { - let #app_var = <#ty>::augment_clap(#app_var); - let #app_var = if <#ty>::is_subcommand() { - #app_var.setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp) - } else { - #app_var - }; - }) - } - Kind::Arg(ty) => { - let convert_type = match ty { - Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty), - _ => &field.ty, + let args = fields.iter().filter_map(|field| { + let attrs = Attrs::from_field(field); + match attrs.kind() { + Kind::Subcommand(_) => None, + Kind::FlattenStruct => { + let ty = &field.ty; + Some(quote! { + let #app_var = <#ty>::augment_clap(#app_var); + let #app_var = if <#ty>::is_subcommand() { + #app_var.setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp) + } else { + #app_var }; - - let occurences = attrs.parser().0 == Parser::FromOccurrences; - - let validator = match *attrs.parser() { - (Parser::TryFromStr, ref f) => quote! { - .validator(|s| { - #f(&s) - .map(|_: #convert_type| ()) - .map_err(|e| e.to_string()) - }) - }, - (Parser::TryFromOsStr, ref f) => quote! { - .validator_os(|s| #f(&s).map(|_: #convert_type| ())) - }, - _ => quote!(), - }; - - let modifier = match ty { - Ty::Bool => quote!( .takes_value(false).multiple(false) ), - Ty::Option => quote!( .takes_value(true).multiple(false) #validator ), - Ty::Vec => quote!( .takes_value(true).multiple(true) #validator ), - Ty::Other if occurences => quote!( .takes_value(false).multiple(true) ), - Ty::Other => { - let required = !attrs.has_method("default_value"); - quote!( .takes_value(true).multiple(false).required(#required) #validator ) - }, - }; - let methods = attrs.methods(); - let name = attrs.name(); - Some(quote!{ - let #app_var = #app_var.arg(::structopt::clap::Arg::with_name(#name)#modifier#methods); - }) - } + }) } - }); + Kind::Arg(ty) => { + let convert_type = match ty { + Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty), + _ => &field.ty, + }; + + let occurences = attrs.parser().0 == Parser::FromOccurrences; + + let validator = match *attrs.parser() { + (Parser::TryFromStr, ref f) => quote! { + .validator(|s| { + #f(&s) + .map(|_: #convert_type| ()) + .map_err(|e| e.to_string()) + }) + }, + (Parser::TryFromOsStr, ref f) => quote! { + .validator_os(|s| #f(&s).map(|_: #convert_type| ())) + }, + _ => quote!(), + }; + + let modifier = match ty { + Ty::Bool => quote!( .takes_value(false).multiple(false) ), + Ty::Option => quote!( .takes_value(true).multiple(false) #validator ), + Ty::Vec => quote!( .takes_value(true).multiple(true) #validator ), + Ty::Other if occurences => quote!( .takes_value(false).multiple(true) ), + Ty::Other => { + let required = !attrs.has_method("default_value"); + quote!( .takes_value(true).multiple(false).required(#required) #validator ) + } + }; + let methods = attrs.methods(); + let name = attrs.name(); + Some(quote!{ + let #app_var = #app_var.arg( + ::structopt::clap::Arg::with_name(#name) + #modifier + #methods + ); + }) + } + } + }); quote! {{ #( #args )* @@ -147,7 +161,7 @@ fn gen_augmentation(fields: &Punctuated, app_var: &Ident) -> quote }} } -fn gen_constructor(fields: &Punctuated) -> quote::Tokens { +fn gen_constructor(fields: &Punctuated) -> TokenStream { let fields = fields.iter().map(|field| { let attrs = Attrs::from_field(field); let field_name = field.ident.as_ref().unwrap(); @@ -155,27 +169,30 @@ fn gen_constructor(fields: &Punctuated) -> quote::Tokens { Kind::Subcommand(ty) => { let subcmd_type = match (ty, sub_type(&field.ty)) { (Ty::Option, Some(sub_type)) => sub_type, - _ => &field.ty + _ => &field.ty, }; let unwrapper = match ty { Ty::Option => quote!(), - _ => quote!( .unwrap() ) + _ => quote!( .unwrap() ), }; quote!(#field_name: <#subcmd_type>::from_subcommand(matches.subcommand())#unwrapper) } - Kind::FlattenStruct => { - quote!(#field_name: StructOpt::from_clap(matches)) - } + Kind::FlattenStruct => quote!(#field_name: StructOpt::from_clap(matches)), Kind::Arg(ty) => { use Parser::*; let (value_of, values_of, parse) = match *attrs.parser() { (FromStr, ref f) => (quote!(value_of), quote!(values_of), f.clone()), - (TryFromStr, ref f) => - (quote!(value_of), quote!(values_of), quote!(|s| #f(s).unwrap())), - (FromOsStr, ref f) => - (quote!(value_of_os), quote!(values_of_os), f.clone()), - (TryFromOsStr, ref f) => - (quote!(value_of_os), quote!(values_of_os), quote!(|s| #f(s).unwrap())), + (TryFromStr, ref f) => ( + quote!(value_of), + quote!(values_of), + quote!(|s| #f(s).unwrap()), + ), + (FromOsStr, ref f) => (quote!(value_of_os), quote!(values_of_os), f.clone()), + (TryFromOsStr, ref f) => ( + quote!(value_of_os), + quote!(values_of_os), + quote!(|s| #f(s).unwrap()), + ), (FromOccurrences, ref f) => (quote!(occurrences_of), quote!(), f.clone()), }; @@ -213,7 +230,7 @@ fn gen_constructor(fields: &Punctuated) -> quote::Tokens { }} } -fn gen_from_clap(struct_name: &Ident, fields: &Punctuated) -> quote::Tokens { +fn gen_from_clap(struct_name: &Ident, fields: &Punctuated) -> TokenStream { let field_block = gen_constructor(fields); quote! { @@ -223,15 +240,17 @@ fn gen_from_clap(struct_name: &Ident, fields: &Punctuated) -> quot } } -fn gen_clap(attrs: &[Attribute]) -> quote::Tokens { - let name = std::env::var("CARGO_PKG_NAME").ok().unwrap_or_else(String::default); +fn gen_clap(attrs: &[Attribute]) -> TokenStream { + let name = std::env::var("CARGO_PKG_NAME") + .ok() + .unwrap_or_else(String::default); let attrs = Attrs::from_struct(attrs, name); let name = attrs.name(); let methods = attrs.methods(); quote!(::structopt::clap::App::new(#name)#methods) } -fn gen_clap_struct(struct_attrs: &[Attribute]) -> quote::Tokens { +fn gen_clap_struct(struct_attrs: &[Attribute]) -> TokenStream { let gen = gen_clap(struct_attrs); quote! { fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> { @@ -241,17 +260,19 @@ fn gen_clap_struct(struct_attrs: &[Attribute]) -> quote::Tokens { } } -fn gen_augment_clap(fields: &Punctuated) -> quote::Tokens { - let app_var: Ident = "app".into(); +fn gen_augment_clap(fields: &Punctuated) -> TokenStream { + let app_var = Ident::new("app", Span::call_site()); let augmentation = gen_augmentation(fields, &app_var); quote! { - pub fn augment_clap<'a, 'b>(#app_var: ::structopt::clap::App<'a, 'b>) -> ::structopt::clap::App<'a, 'b> { + pub fn augment_clap<'a, 'b>( + #app_var: ::structopt::clap::App<'a, 'b> + ) -> ::structopt::clap::App<'a, 'b> { #augmentation } } } -fn gen_clap_enum(enum_attrs: &[Attribute]) -> quote::Tokens { +fn gen_clap_enum(enum_attrs: &[Attribute]) -> TokenStream { let gen = gen_clap(enum_attrs); quote! { fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> { @@ -262,13 +283,13 @@ fn gen_clap_enum(enum_attrs: &[Attribute]) -> quote::Tokens { } } -fn gen_augment_clap_enum(variants: &Punctuated) -> quote::Tokens { +fn gen_augment_clap_enum(variants: &Punctuated) -> TokenStream { use syn::Fields::*; let subcommands = variants.iter().map(|variant| { - let name = variant.ident.as_ref().to_string(); + let name = variant.ident.to_string(); let attrs = Attrs::from_struct(&variant.attrs, name); - let app_var: Ident = "subcommand".into(); + let app_var = Ident::new("subcommand", Span::call_site()); let arg_block = match variant.fields { Named(ref fields) => gen_augmentation(&fields.named, &app_var), Unit => quote!( #app_var ), @@ -278,7 +299,9 @@ fn gen_augment_clap_enum(variants: &Punctuated) -> quote::Tokens { let #app_var = <#ty>::augment_clap(#app_var); if <#ty>::is_subcommand() { - #app_var.setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp) + #app_var.setting( + ::structopt::clap::AppSettings::SubcommandRequiredElseHelp + ) } else { #app_var } @@ -300,13 +323,15 @@ fn gen_augment_clap_enum(variants: &Punctuated) -> quote::Tokens }); quote! { - pub fn augment_clap<'a, 'b>(app: ::structopt::clap::App<'a, 'b>) -> ::structopt::clap::App<'a, 'b> { + pub fn augment_clap<'a, 'b>( + app: ::structopt::clap::App<'a, 'b> + ) -> ::structopt::clap::App<'a, 'b> { app #( #subcommands )* } } } -fn gen_from_clap_enum(name: &Ident) -> quote::Tokens { +fn gen_from_clap_enum(name: &Ident) -> TokenStream { quote! { fn from_clap(matches: &::structopt::clap::ArgMatches) -> Self { <#name>::from_subcommand(matches.subcommand()) @@ -315,11 +340,11 @@ fn gen_from_clap_enum(name: &Ident) -> quote::Tokens { } } -fn gen_from_subcommand(name: &Ident, variants: &Punctuated) -> quote::Tokens { +fn gen_from_subcommand(name: &Ident, variants: &Punctuated) -> TokenStream { use syn::Fields::*; let match_arms = variants.iter().map(|variant| { - let attrs = Attrs::from_struct(&variant.attrs, variant.ident.as_ref().to_string()); + let attrs = Attrs::from_struct(&variant.attrs, variant.ident.to_string()); let sub_name = attrs.name(); let variant_name = &variant.ident; let constructor_block = match variant.fields { @@ -329,8 +354,7 @@ fn gen_from_subcommand(name: &Ident, variants: &Punctuated) -> q let ty = &fields.unnamed[0]; quote!( ( <#ty as ::structopt::StructOpt>::from_clap(matches) ) ) } - Unnamed(..) => - panic!("{}: tuple enum are not supported", variant.ident), + Unnamed(..) => panic!("{}: tuple enum are not supported", variant.ident), }; quote! { @@ -340,7 +364,9 @@ fn gen_from_subcommand(name: &Ident, variants: &Punctuated) -> q }); quote! { - pub fn from_subcommand<'a, 'b>(sub: (&'b str, Option<&'b ::structopt::clap::ArgMatches<'a>>)) -> Option { + pub fn from_subcommand<'a, 'b>( + sub: (&'b str, Option<&'b ::structopt::clap::ArgMatches<'a>>) + ) -> Option { match sub { #( #match_arms ),*, _ => None @@ -352,8 +378,8 @@ fn gen_from_subcommand(name: &Ident, variants: &Punctuated) -> q fn impl_structopt_for_struct( name: &Ident, fields: &Punctuated, - attrs: &[Attribute] -) -> quote::Tokens { + attrs: &[Attribute], +) -> TokenStream { let clap = gen_clap_struct(attrs); let augment_clap = gen_augment_clap(fields); let from_clap = gen_from_clap(name, fields); @@ -377,8 +403,8 @@ fn impl_structopt_for_struct( fn impl_structopt_for_enum( name: &Ident, variants: &Punctuated, - attrs: &[Attribute] -) -> quote::Tokens { + attrs: &[Attribute], +) -> TokenStream { let clap = gen_clap_enum(attrs); let augment_clap = gen_augment_clap_enum(variants); let from_clap = gen_from_clap_enum(name); @@ -400,16 +426,17 @@ fn impl_structopt_for_enum( } } -fn impl_structopt(input: &DeriveInput) -> quote::Tokens { +fn impl_structopt(input: &DeriveInput) -> TokenStream { use syn::Data::*; let struct_name = &input.ident; let inner_impl = match input.data { - Struct(DataStruct { fields: syn::Fields::Named(ref fields), .. }) => - impl_structopt_for_struct(struct_name, &fields.named, &input.attrs), - Enum(ref e) => - impl_structopt_for_enum(struct_name, &e.variants, &input.attrs), - _ => panic!("structopt only supports non-tuple structs and enums") + Struct(DataStruct { + fields: syn::Fields::Named(ref fields), + .. + }) => impl_structopt_for_struct(struct_name, &fields.named, &input.attrs), + Enum(ref e) => impl_structopt_for_enum(struct_name, &e.variants, &input.attrs), + _ => panic!("structopt only supports non-tuple structs and enums"), }; quote!(#inner_impl) diff --git a/tests/arguments.rs b/tests/arguments.rs index 5845b010..0eab6819 100644 --- a/tests/arguments.rs +++ b/tests/arguments.rs @@ -20,7 +20,11 @@ fn required_argument() { } assert_eq!(Opt { arg: 42 }, Opt::from_iter(&["test", "42"])); assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err()); - assert!(Opt::clap().get_matches_from_safe(&["test", "42", "24"]).is_err()); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "42", "24"]) + .is_err() + ); } #[test] @@ -31,7 +35,11 @@ fn optional_argument() { } assert_eq!(Opt { arg: Some(42) }, Opt::from_iter(&["test", "42"])); assert_eq!(Opt { arg: None }, Opt::from_iter(&["test"])); - assert!(Opt::clap().get_matches_from_safe(&["test", "42", "24"]).is_err()); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "42", "24"]) + .is_err() + ); } #[test] @@ -43,7 +51,11 @@ fn argument_with_default() { } assert_eq!(Opt { arg: 24 }, Opt::from_iter(&["test", "24"])); assert_eq!(Opt { arg: 42 }, Opt::from_iter(&["test"])); - assert!(Opt::clap().get_matches_from_safe(&["test", "42", "24"]).is_err()); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "42", "24"]) + .is_err() + ); } #[test] @@ -55,7 +67,11 @@ fn argument_with_raw_default() { } assert_eq!(Opt { arg: 24 }, Opt::from_iter(&["test", "24"])); assert_eq!(Opt { arg: 42 }, Opt::from_iter(&["test"])); - assert!(Opt::clap().get_matches_from_safe(&["test", "42", "24"]).is_err()); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "42", "24"]) + .is_err() + ); } #[test] @@ -66,19 +82,27 @@ fn arguments() { } assert_eq!(Opt { arg: vec![24] }, Opt::from_iter(&["test", "24"])); assert_eq!(Opt { arg: vec![] }, Opt::from_iter(&["test"])); - assert_eq!(Opt { arg: vec![24, 42] }, Opt::from_iter(&["test", "24", "42"])); + assert_eq!( + Opt { arg: vec![24, 42] }, + Opt::from_iter(&["test", "24", "42"]) + ); } - #[test] fn arguments_safe() { #[derive(StructOpt, PartialEq, Debug)] struct Opt { arg: Vec, } - assert_eq!(Opt { arg: vec![24] }, Opt::from_iter_safe(&["test", "24"]).unwrap()); + assert_eq!( + Opt { arg: vec![24] }, + Opt::from_iter_safe(&["test", "24"]).unwrap() + ); assert_eq!(Opt { arg: vec![] }, Opt::from_iter_safe(&["test"]).unwrap()); - assert_eq!(Opt { arg: vec![24, 42] }, Opt::from_iter_safe(&["test", "24", "42"]).unwrap()); + assert_eq!( + Opt { arg: vec![24, 42] }, + Opt::from_iter_safe(&["test", "24", "42"]).unwrap() + ); assert_eq!( clap::ErrorKind::ValueValidation, diff --git a/tests/author_version_about.rs b/tests/author_version_about.rs index 902c200f..89dad08b 100644 --- a/tests/author_version_about.rs +++ b/tests/author_version_about.rs @@ -6,7 +6,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[macro_use] extern crate structopt; +#[macro_use] +extern crate structopt; use structopt::StructOpt; diff --git a/tests/custom-string-parsers.rs b/tests/custom-string-parsers.rs index 138547f6..d8b832c4 100644 --- a/tests/custom-string-parsers.rs +++ b/tests/custom-string-parsers.rs @@ -11,9 +11,9 @@ extern crate structopt; use structopt::StructOpt; -use std::path::PathBuf; -use std::num::ParseIntError; use std::ffi::{OsStr, OsString}; +use std::num::ParseIntError; +use std::path::PathBuf; #[derive(StructOpt, PartialEq, Debug)] struct PathOpt { @@ -48,19 +48,11 @@ fn test_path_opt_simple() { option_path_2: Some(PathBuf::from("j.zip")), }, PathOpt::from_clap(&PathOpt::clap().get_matches_from(&[ - "test", - "-p", "/usr/bin", - "-v", "/a/b/c", - "-v", "/d/e/f", - "-v", "/g/h/i", - "-q", "j.zip", + "test", "-p", "/usr/bin", "-v", "/a/b/c", "-v", "/d/e/f", "-v", "/g/h/i", "-q", "j.zip" ])) ); } - - - fn parse_hex(input: &str) -> Result { u64::from_str_radix(input, 16) } @@ -82,13 +74,12 @@ fn test_parse_hex() { HexOpt::from_clap(&HexOpt::clap().get_matches_from(&["test", "-n", "abcdef"])) ); - let err = HexOpt::clap().get_matches_from_safe(&["test", "-n", "gg"]).unwrap_err(); + let err = HexOpt::clap() + .get_matches_from_safe(&["test", "-n", "gg"]) + .unwrap_err(); assert!(err.message.contains("invalid digit found in string"), err); } - - - fn custom_parser_1(_: &str) -> &'static str { "A" } @@ -117,14 +108,16 @@ struct NoOpOpt { #[test] fn test_every_custom_parser() { assert_eq!( - NoOpOpt { a: "A", b: "B", c: "C", d: "D" }, - NoOpOpt::from_clap(&NoOpOpt::clap().get_matches_from(&[ - "test", "-a=?", "-b=?", "-c=?", "-d=?", - ])) + NoOpOpt { + a: "A", + b: "B", + c: "C", + d: "D" + }, + NoOpOpt::from_clap(&NoOpOpt::clap().get_matches_from(&["test", "-a=?", "-b=?", "-c=?", "-d=?",])) ); } - // Note: can't use `Vec` directly, as structopt would instead look for // conversion function from `&str` to `u8`. type Bytes = Vec; @@ -151,14 +144,16 @@ fn test_parser_with_default_value() { }, DefaultedOpt::from_clap(&DefaultedOpt::clap().get_matches_from(&[ "test", - "-b", "E²=p²c²+m²c⁴", - "-i", "9000", - "-p", "src/lib.rs", + "-b", + "E²=p²c²+m²c⁴", + "-i", + "9000", + "-p", + "src/lib.rs", ])) ); } - #[derive(PartialEq, Debug)] struct Foo(u8); @@ -223,33 +218,72 @@ fn test_custom_bool() { assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err()); assert!(Opt::clap().get_matches_from_safe(&["test", "-d"]).is_err()); - assert!(Opt::clap().get_matches_from_safe(&["test", "-dfoo"]).is_err()); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "-dfoo"]) + .is_err() + ); assert_eq!( - Opt { debug: false, verbose: false, tribool: None, bitset: vec![] }, + Opt { + debug: false, + verbose: false, + tribool: None, + bitset: vec![], + }, Opt::from_iter(&["test", "-dfalse"]), ); assert_eq!( - Opt { debug: true, verbose: false, tribool: None, bitset: vec![] }, + Opt { + debug: true, + verbose: false, + tribool: None, + bitset: vec![], + }, Opt::from_iter(&["test", "-dtrue"]), ); assert_eq!( - Opt { debug: true, verbose: false, tribool: None, bitset: vec![] }, + Opt { + debug: true, + verbose: false, + tribool: None, + bitset: vec![], + }, Opt::from_iter(&["test", "-dtrue", "-vfalse"]), ); assert_eq!( - Opt { debug: true, verbose: true, tribool: None, bitset: vec![] }, + Opt { + debug: true, + verbose: true, + tribool: None, + bitset: vec![], + }, Opt::from_iter(&["test", "-dtrue", "-vtrue"]), ); assert_eq!( - Opt { debug: true, verbose: false, tribool: Some(false), bitset: vec![] }, + Opt { + debug: true, + verbose: false, + tribool: Some(false), + bitset: vec![], + }, Opt::from_iter(&["test", "-dtrue", "-tfalse"]), ); assert_eq!( - Opt { debug: true, verbose: false, tribool: Some(true), bitset: vec![] }, + Opt { + debug: true, + verbose: false, + tribool: Some(true), + bitset: vec![], + }, Opt::from_iter(&["test", "-dtrue", "-ttrue"]), ); assert_eq!( - Opt { debug: true, verbose: false, tribool: None, bitset: vec![false, true, false, false] }, - Opt::from_iter(&["test", "-dtrue", "-bfalse", "-btrue", "-bfalse","-bfalse"]), + Opt { + debug: true, + verbose: false, + tribool: None, + bitset: vec![false, true, false, false], + }, + Opt::from_iter(&["test", "-dtrue", "-bfalse", "-btrue", "-bfalse", "-bfalse"]), ); } diff --git a/tests/deny-warnings.rs b/tests/deny-warnings.rs index 1e0e6a2b..b73d1711 100644 --- a/tests/deny-warnings.rs +++ b/tests/deny-warnings.rs @@ -7,7 +7,7 @@ // except according to those terms. #![deny(warnings)] -#![cfg(feature = "nightly")]// TODO: remove that when never is stable +#![cfg(feature = "nightly")] // TODO: remove that when never is stable #![feature(never_type)] #[macro_use] @@ -26,9 +26,12 @@ fn warning_never_struct() { #[structopt(parse(try_from_str = "try_str"))] s: String, } - assert_eq!(Opt { s: "foo".to_string() }, - Opt::from_iter(&["test", "foo"])); - + assert_eq!( + Opt { + s: "foo".to_string() + }, + Opt::from_iter(&["test", "foo"]) + ); } #[test] @@ -38,10 +41,12 @@ fn warning_never_enum() { Foo { #[structopt(parse(try_from_str = "try_str"))] s: String, - } + }, } - assert_eq!(Opt::Foo { s: "foo".to_string() }, - Opt::from_iter(&["test", "Foo", "foo"])); - + assert_eq!( + Opt::Foo { + s: "foo".to_string() + }, + Opt::from_iter(&["test", "Foo", "foo"]) + ); } - diff --git a/tests/flags.rs b/tests/flags.rs index 830ad024..9e8aaf47 100644 --- a/tests/flags.rs +++ b/tests/flags.rs @@ -19,16 +19,34 @@ fn unique_flag() { alice: bool, } - assert_eq!(Opt { alice: false }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))); - assert_eq!(Opt { alice: true }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))); - assert_eq!(Opt { alice: true }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--alice"]))); + assert_eq!( + Opt { alice: false }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert_eq!( + Opt { alice: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"])) + ); + assert_eq!( + Opt { alice: true }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--alice"])) + ); assert!(Opt::clap().get_matches_from_safe(&["test", "-i"]).is_err()); - assert!(Opt::clap().get_matches_from_safe(&["test", "-a", "foo"]).is_err()); - assert!(Opt::clap().get_matches_from_safe(&["test", "-a", "-a"]).is_err()); - assert!(Opt::clap().get_matches_from_safe(&["test", "-a", "--alice"]).is_err()); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "-a", "foo"]) + .is_err() + ); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "-a", "-a"]) + .is_err() + ); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "-a", "--alice"]) + .is_err() + ); } #[test] @@ -41,18 +59,32 @@ fn multiple_flag() { bob: u8, } - assert_eq!(Opt { alice: 0, bob: 0 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))); - assert_eq!(Opt { alice: 1, bob: 0 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))); - assert_eq!(Opt { alice: 2, bob: 0 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "-a"]))); - assert_eq!(Opt { alice: 2, bob: 2 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "--alice", "-bb"]))); - assert_eq!(Opt { alice: 3, bob: 1 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-aaa", "--bob"]))); + assert_eq!( + Opt { alice: 0, bob: 0 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert_eq!( + Opt { alice: 1, bob: 0 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"])) + ); + assert_eq!( + Opt { alice: 2, bob: 0 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "-a"])) + ); + assert_eq!( + Opt { alice: 2, bob: 2 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "--alice", "-bb"])) + ); + assert_eq!( + Opt { alice: 3, bob: 1 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-aaa", "--bob"])) + ); assert!(Opt::clap().get_matches_from_safe(&["test", "-i"]).is_err()); - assert!(Opt::clap().get_matches_from_safe(&["test", "-a", "foo"]).is_err()); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "-a", "foo"]) + .is_err() + ); } #[test] @@ -65,16 +97,46 @@ fn combined_flags() { bob: u64, } - assert_eq!(Opt { alice: false, bob: 0 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))); - assert_eq!(Opt { alice: true, bob: 0 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))); - assert_eq!(Opt { alice: true, bob: 0 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"]))); - assert_eq!(Opt { alice: false, bob: 1 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-b"]))); - assert_eq!(Opt { alice: true, bob: 1 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--alice", "--bob"]))); - assert_eq!(Opt { alice: true, bob: 4 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-bb", "-a", "-bb"]))); + assert_eq!( + Opt { + alice: false, + bob: 0 + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert_eq!( + Opt { + alice: true, + bob: 0 + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"])) + ); + assert_eq!( + Opt { + alice: true, + bob: 0 + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a"])) + ); + assert_eq!( + Opt { + alice: false, + bob: 1 + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-b"])) + ); + assert_eq!( + Opt { + alice: true, + bob: 1 + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--alice", "--bob"])) + ); + assert_eq!( + Opt { + alice: true, + bob: 4 + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-bb", "-a", "-bb"])) + ); } diff --git a/tests/flatten.rs b/tests/flatten.rs index 4e8a0cfa..b1e802be 100644 --- a/tests/flatten.rs +++ b/tests/flatten.rs @@ -23,9 +23,18 @@ fn flatten() { #[structopt(flatten)] common: Common, } - assert_eq!(Opt { common: Common { arg: 42 } }, Opt::from_iter(&["test", "42"])); + assert_eq!( + Opt { + common: Common { arg: 42 } + }, + Opt::from_iter(&["test", "42"]) + ); assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err()); - assert!(Opt::clap().get_matches_from_safe(&["test", "42", "24"]).is_err()); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "42", "24"]) + .is_err() + ); } #[test] @@ -76,8 +85,18 @@ fn flatten_in_subcommand() { Add(Add), } - assert_eq!(Opt::Fetch { all: false, common: Common { arg: 42 } }, - Opt::from_iter(&["test", "fetch", "42"])); - assert_eq!(Opt::Add(Add { interactive: true, common: Common { arg: 43 } }), - Opt::from_iter(&["test", "add", "-i", "43"])); + assert_eq!( + Opt::Fetch { + all: false, + common: Common { arg: 42 } + }, + Opt::from_iter(&["test", "fetch", "42"]) + ); + assert_eq!( + Opt::Add(Add { + interactive: true, + common: Common { arg: 43 } + }), + Opt::from_iter(&["test", "add", "-i", "43"]) + ); } diff --git a/tests/nested-subcommands.rs b/tests/nested-subcommands.rs index 10ccacc6..8557e13e 100644 --- a/tests/nested-subcommands.rs +++ b/tests/nested-subcommands.rs @@ -6,7 +6,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[macro_use] extern crate structopt; +#[macro_use] +extern crate structopt; use structopt::StructOpt; @@ -17,7 +18,7 @@ struct Opt { #[structopt(short = "v", long = "verbose", parse(from_occurrences))] verbose: u64, #[structopt(subcommand)] - cmd: Sub + cmd: Sub, } #[derive(StructOpt, PartialEq, Debug)] @@ -25,7 +26,7 @@ enum Sub { #[structopt(name = "fetch")] Fetch {}, #[structopt(name = "add")] - Add {} + Add {}, } #[derive(StructOpt, PartialEq, Debug)] @@ -35,7 +36,7 @@ struct Opt2 { #[structopt(short = "v", long = "verbose", parse(from_occurrences))] verbose: u64, #[structopt(subcommand)] - cmd: Option + cmd: Option, } #[test] @@ -43,24 +44,54 @@ fn test_no_cmd() { let result = Opt::clap().get_matches_from_safe(&["test"]); assert!(result.is_err()); - assert_eq!(Opt2 { force: false, verbose: 0, cmd: None }, - Opt2::from_clap(&Opt2::clap().get_matches_from(&["test"]))); + assert_eq!( + Opt2 { + force: false, + verbose: 0, + cmd: None + }, + Opt2::from_clap(&Opt2::clap().get_matches_from(&["test"])) + ); } #[test] fn test_fetch() { - assert_eq!(Opt { force: false, verbose: 3, cmd: Sub::Fetch {} }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vvv", "fetch"]))); - assert_eq!(Opt { force: true, verbose: 0, cmd: Sub::Fetch {} }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--force", "fetch"]))); + assert_eq!( + Opt { + force: false, + verbose: 3, + cmd: Sub::Fetch {} + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vvv", "fetch"])) + ); + assert_eq!( + Opt { + force: true, + verbose: 0, + cmd: Sub::Fetch {} + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--force", "fetch"])) + ); } #[test] fn test_add() { - assert_eq!(Opt { force: false, verbose: 0, cmd: Sub::Add {} }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"]))); - assert_eq!(Opt { force: false, verbose: 2, cmd: Sub::Add {} }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vv", "add"]))); + assert_eq!( + Opt { + force: false, + verbose: 0, + cmd: Sub::Add {} + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"])) + ); + assert_eq!( + Opt { + force: false, + verbose: 2, + cmd: Sub::Add {} + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-vv", "add"])) + ); } #[test] @@ -80,7 +111,7 @@ struct Opt3 { #[structopt(short = "a", long = "all")] all: bool, #[structopt(subcommand)] - cmd: Sub2 + cmd: Sub2, } #[derive(StructOpt, PartialEq, Debug)] @@ -89,11 +120,10 @@ enum Sub2 { Foo { file: String, #[structopt(subcommand)] - cmd: Sub3 + cmd: Sub3, }, #[structopt(name = "bar")] - Bar { - } + Bar {}, } #[derive(StructOpt, PartialEq, Debug)] @@ -101,7 +131,7 @@ enum Sub3 { #[structopt(name = "baz")] Baz {}, #[structopt(name = "quux")] - Quux {} + Quux {}, } #[test] @@ -109,7 +139,10 @@ fn test_subsubcommand() { assert_eq!( Opt3 { all: true, - cmd: Sub2::Foo { file: "lib.rs".to_string(), cmd: Sub3::Quux {} } + cmd: Sub2::Foo { + file: "lib.rs".to_string(), + cmd: Sub3::Quux {} + } }, Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "--all", "foo", "lib.rs", "quux"])) ); @@ -117,43 +150,57 @@ fn test_subsubcommand() { #[derive(StructOpt, PartialEq, Debug)] enum SubSubCmdWithOption { - #[structopt(name = "remote")] + #[structopt(name = "remote")] Remote { #[structopt(subcommand)] - cmd: Option + cmd: Option, }, #[structopt(name = "stash")] Stash { #[structopt(subcommand)] - cmd: Stash + cmd: Stash, }, } #[derive(StructOpt, PartialEq, Debug)] enum Remote { - #[structopt(name = "add")] + #[structopt(name = "add")] Add { name: String, url: String }, - #[structopt(name = "remove")] + #[structopt(name = "remove")] Remove { name: String }, } #[derive(StructOpt, PartialEq, Debug)] enum Stash { - #[structopt(name = "save")] + #[structopt(name = "save")] Save, - #[structopt(name = "pop")] + #[structopt(name = "pop")] Pop, } #[test] fn sub_sub_cmd_with_option() { fn make(args: &[&str]) -> Option { - SubSubCmdWithOption::clap().get_matches_from_safe(args).ok().map(|m| SubSubCmdWithOption::from_clap(&m)) + SubSubCmdWithOption::clap() + .get_matches_from_safe(args) + .ok() + .map(|m| SubSubCmdWithOption::from_clap(&m)) } - assert_eq!(Some(SubSubCmdWithOption::Remote { cmd: None }), make(&["", "remote"])); assert_eq!( - Some(SubSubCmdWithOption::Remote { cmd: Some(Remote::Add { name: "origin".into(), url: "http".into() }) }), + Some(SubSubCmdWithOption::Remote { cmd: None }), + make(&["", "remote"]) + ); + assert_eq!( + Some(SubSubCmdWithOption::Remote { + cmd: Some(Remote::Add { + name: "origin".into(), + url: "http".into() + }) + }), make(&["", "remote", "add", "origin", "http"]) ); - assert_eq!(Some(SubSubCmdWithOption::Stash { cmd: Stash::Save }), make(&["", "stash", "save"])); + assert_eq!( + Some(SubSubCmdWithOption::Stash { cmd: Stash::Save }), + make(&["", "stash", "save"]) + ); assert_eq!(None, make(&["", "stash"])); } diff --git a/tests/options.rs b/tests/options.rs index 2ea68bda..686113e2 100644 --- a/tests/options.rs +++ b/tests/options.rs @@ -18,14 +18,24 @@ fn required_option() { #[structopt(short = "a", long = "arg")] arg: i32, } - assert_eq!(Opt { arg: 42 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"]))); - assert_eq!(Opt { arg: 42 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "42"]))); - assert_eq!(Opt { arg: 42 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--arg", "42"]))); + assert_eq!( + Opt { arg: 42 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"])) + ); + assert_eq!( + Opt { arg: 42 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a", "42"])) + ); + assert_eq!( + Opt { arg: 42 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--arg", "42"])) + ); assert!(Opt::clap().get_matches_from_safe(&["test"]).is_err()); - assert!(Opt::clap().get_matches_from_safe(&["test", "-a42", "-a24"]).is_err()); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "-a42", "-a24"]) + .is_err() + ); } #[test] @@ -35,11 +45,19 @@ fn optional_option() { #[structopt(short = "a")] arg: Option, } - assert_eq!(Opt { arg: Some(42) }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"]))); - assert_eq!(Opt { arg: None }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))); - assert!(Opt::clap().get_matches_from_safe(&["test", "-a42", "-a24"]).is_err()); + assert_eq!( + Opt { arg: Some(42) }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a42"])) + ); + assert_eq!( + Opt { arg: None }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "-a42", "-a24"]) + .is_err() + ); } #[test] @@ -49,11 +67,19 @@ fn option_with_default() { #[structopt(short = "a", default_value = "42")] arg: i32, } - assert_eq!(Opt { arg: 24 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"]))); - assert_eq!(Opt { arg: 42 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))); - assert!(Opt::clap().get_matches_from_safe(&["test", "-a42", "-a24"]).is_err()); + assert_eq!( + Opt { arg: 24 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"])) + ); + assert_eq!( + Opt { arg: 42 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "-a42", "-a24"]) + .is_err() + ); } #[test] @@ -63,11 +89,19 @@ fn option_with_raw_default() { #[structopt(short = "a", raw(default_value = r#""42""#))] arg: i32, } - assert_eq!(Opt { arg: 24 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"]))); - assert_eq!(Opt { arg: 42 }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))); - assert!(Opt::clap().get_matches_from_safe(&["test", "-a42", "-a24"]).is_err()); + assert_eq!( + Opt { arg: 24 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"])) + ); + assert_eq!( + Opt { arg: 42 }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert!( + Opt::clap() + .get_matches_from_safe(&["test", "-a42", "-a24"]) + .is_err() + ); } #[test] @@ -77,12 +111,18 @@ fn options() { #[structopt(short = "a", long = "arg")] arg: Vec, } - assert_eq!(Opt { arg: vec![24] }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"]))); - assert_eq!(Opt { arg: vec![] }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test"]))); - assert_eq!(Opt { arg: vec![24, 42] }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24", "--arg", "42"]))); + assert_eq!( + Opt { arg: vec![24] }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24"])) + ); + assert_eq!( + Opt { arg: vec![] }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test"])) + ); + assert_eq!( + Opt { arg: vec![24, 42] }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-a24", "--arg", "42"])) + ); } #[test] @@ -93,5 +133,8 @@ fn empy_default_value() { arg: String, } assert_eq!(Opt { arg: "".into() }, Opt::from_iter(&["test"])); - assert_eq!(Opt { arg: "foo".into() }, Opt::from_iter(&["test", "-afoo"])); + assert_eq!( + Opt { arg: "foo".into() }, + Opt::from_iter(&["test", "-afoo"]) + ); } diff --git a/tests/privacy.rs b/tests/privacy.rs index 8ea4d2d7..67e53a38 100644 --- a/tests/privacy.rs +++ b/tests/privacy.rs @@ -12,18 +12,18 @@ extern crate structopt; mod options { #[derive(Debug, StructOpt)] pub struct Options { - #[structopt(subcommand)] - pub subcommand: ::subcommands::SubCommand, + #[structopt(subcommand)] + pub subcommand: ::subcommands::SubCommand, } } mod subcommands { #[derive(Debug, StructOpt)] pub enum SubCommand { - #[structopt(name = "foo", about = "foo")] - Foo { - #[structopt(help = "foo")] - bars: Vec, - }, + #[structopt(name = "foo", about = "foo")] + Foo { + #[structopt(help = "foo")] + bars: Vec, + }, } } diff --git a/tests/raw_attributes.rs b/tests/raw_attributes.rs index 012c71f8..35ad45ba 100644 --- a/tests/raw_attributes.rs +++ b/tests/raw_attributes.rs @@ -17,8 +17,8 @@ use structopt::clap::AppSettings; #[structopt(raw(global_settings = "&[AppSettings::ColoredHelp]"))] struct Opt { #[structopt(long = "x", - raw(display_order = "2", next_line_help = "true", - default_value = r#""0""#, require_equals = "true"))] + raw(display_order = "2", next_line_help = "true", default_value = r#""0""#, + require_equals = "true"))] x: i32, #[structopt(short = "l", long = "level", raw(aliases = r#"&["set-level", "lvl"]"#))] @@ -33,22 +33,64 @@ struct Opt { #[test] fn test_raw_slice() { - assert_eq!(Opt { x: 0, level: "1".to_string(), files: Vec::new(), values: vec![] }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1"]))); - assert_eq!(Opt { x: 0, level: "1".to_string(), files: Vec::new(), values: vec![] }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--level", "1"]))); - assert_eq!(Opt { x: 0, level: "1".to_string(), files: Vec::new(), values: vec![] }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--set-level", "1"]))); - assert_eq!(Opt { x: 0, level: "1".to_string(), files: Vec::new(), values: vec![] }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--lvl", "1"]))); + assert_eq!( + Opt { + x: 0, + level: "1".to_string(), + files: Vec::new(), + values: vec![], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1"])) + ); + assert_eq!( + Opt { + x: 0, + level: "1".to_string(), + files: Vec::new(), + values: vec![], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--level", "1"])) + ); + assert_eq!( + Opt { + x: 0, + level: "1".to_string(), + files: Vec::new(), + values: vec![], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--set-level", "1"])) + ); + assert_eq!( + Opt { + x: 0, + level: "1".to_string(), + files: Vec::new(), + values: vec![], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "--lvl", "1"])) + ); } #[test] fn test_raw_multi_args() { - assert_eq!(Opt { x: 0, level: "1".to_string(), files: vec!["file".to_string()], values: vec![] }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1", "file"]))); - assert_eq!(Opt { x: 0, level: "1".to_string(), files: vec!["FILE".to_string()], values: vec![1] }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1", "--values", "1", "--", "FILE"]))); + assert_eq!( + Opt { + x: 0, + level: "1".to_string(), + files: vec!["file".to_string()], + values: vec![], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1", "file"])) + ); + assert_eq!( + Opt { + x: 0, + level: "1".to_string(), + files: vec!["FILE".to_string()], + values: vec![1], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1", "--values", "1", "--", "FILE"])) + ); } #[test] @@ -59,8 +101,15 @@ fn test_raw_multi_args_fail() { #[test] fn test_raw_bool() { - assert_eq!(Opt { x: 1, level: "1".to_string(), files: vec![], values: vec![] }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1", "--x=1"]))); + assert_eq!( + Opt { + x: 1, + level: "1".to_string(), + files: vec![], + values: vec![], + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "-l", "1", "--x=1"])) + ); let result = Opt::clap().get_matches_from_safe(&["test", "-l", "1", "--x", "1"]); assert!(result.is_err()); } diff --git a/tests/subcommands.rs b/tests/subcommands.rs index c3f18d6a..6ae9b3b2 100644 --- a/tests/subcommands.rs +++ b/tests/subcommands.rs @@ -6,7 +6,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[macro_use] extern crate structopt; +#[macro_use] +extern crate structopt; use structopt::StructOpt; @@ -19,32 +20,54 @@ enum Opt { #[structopt(short = "f", long = "force")] /// Overwrite local branches. force: bool, - repo: String + repo: String, }, - + #[structopt(name = "add")] Add { #[structopt(short = "i", long = "interactive")] interactive: bool, #[structopt(short = "v", long = "verbose")] - verbose: bool - } + verbose: bool, + }, } #[test] fn test_fetch() { - assert_eq!(Opt::Fetch { all: true, force: false, repo: "origin".to_string() }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "--all", "origin"]))); - assert_eq!(Opt::Fetch { all: false, force: true, repo: "origin".to_string() }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "-f", "origin"]))); + assert_eq!( + Opt::Fetch { + all: true, + force: false, + repo: "origin".to_string() + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "--all", "origin"])) + ); + assert_eq!( + Opt::Fetch { + all: false, + force: true, + repo: "origin".to_string() + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "fetch", "-f", "origin"])) + ); } #[test] fn test_add() { - assert_eq!(Opt::Add { interactive: false, verbose: false }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"]))); - assert_eq!(Opt::Add { interactive: true, verbose: true }, - Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add", "-i", "-v"]))); + assert_eq!( + Opt::Add { + interactive: false, + verbose: false + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add"])) + ); + assert_eq!( + Opt::Add { + interactive: true, + verbose: true + }, + Opt::from_clap(&Opt::clap().get_matches_from(&["test", "add", "-i", "-v"])) + ); } #[test] @@ -62,17 +85,19 @@ fn test_no_parse() { #[derive(StructOpt, PartialEq, Debug)] enum Opt2 { #[structopt(name = "do-something")] - DoSomething { - arg: String - } + DoSomething { arg: String }, } #[test] /// This test is specifically to make sure that hyphenated subcommands get /// processed correctly. fn test_hyphenated_subcommands() { - assert_eq!(Opt2::DoSomething { arg: "blah".to_string() }, - Opt2::from_clap(&Opt2::clap().get_matches_from(&["test", "do-something", "blah"]))); + assert_eq!( + Opt2::DoSomething { + arg: "blah".to_string() + }, + Opt2::from_clap(&Opt2::clap().get_matches_from(&["test", "do-something", "blah"])) + ); } #[derive(StructOpt, PartialEq, Debug)] @@ -82,14 +107,23 @@ enum Opt3 { #[structopt(name = "init")] Init, #[structopt(name = "fetch")] - Fetch + Fetch, } #[test] fn test_null_commands() { - assert_eq!(Opt3::Add, Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "add"]))); - assert_eq!(Opt3::Init, Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "init"]))); - assert_eq!(Opt3::Fetch, Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "fetch"]))); + assert_eq!( + Opt3::Add, + Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "add"])) + ); + assert_eq!( + Opt3::Init, + Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "init"])) + ); + assert_eq!( + Opt3::Fetch, + Opt3::from_clap(&Opt3::clap().get_matches_from(&["test", "fetch"])) + ); } #[derive(StructOpt, PartialEq, Debug)] @@ -117,12 +151,19 @@ enum Opt4 { #[test] fn test_tuple_commands() { assert_eq!( - Opt4::Add(Add { file: "f".to_string() }), + Opt4::Add(Add { + file: "f".to_string() + }), Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "add", "f"])) ); - assert_eq!(Opt4::Init, Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "init"]))); assert_eq!( - Opt4::Fetch(Fetch { remote: "origin".to_string() }), + Opt4::Init, + Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "init"])) + ); + assert_eq!( + Opt4::Fetch(Fetch { + remote: "origin".to_string() + }), Opt4::from_clap(&Opt4::clap().get_matches_from(&["test", "fetch", "origin"])) ); @@ -140,7 +181,7 @@ fn enum_in_enum_subsubcommand() { #[derive(StructOpt, Debug, PartialEq)] pub enum Opt { #[structopt(name = "daemon")] - Daemon(DaemonCommand) + Daemon(DaemonCommand), } #[derive(StructOpt, Debug, PartialEq)] @@ -175,5 +216,10 @@ fn flatten_enum() { } assert!(Opt::from_iter_safe(&["test"]).is_err()); - assert_eq!(Opt::from_iter(&["test", "Foo"]), Opt { sub_cmd: SubCmd::Foo }); + assert_eq!( + Opt::from_iter(&["test", "Foo"]), + Opt { + sub_cmd: SubCmd::Foo + } + ); }