diff --git a/clap_derive/src/attrs.rs b/clap_derive/src/attrs.rs index 971795ec2997..1a2486fd1a2c 100644 --- a/clap_derive/src/attrs.rs +++ b/clap_derive/src/attrs.rs @@ -340,34 +340,41 @@ impl Attrs { VerbatimDocComment(ident) => self.verbatim_doc_comment = Some(ident), DefaultValue(ident, lit) => { - let val = if let Some(lit) = lit { - quote!(#lit) + let val = quote!(#lit); + self.methods.push(Method::new(ident, val)); + } + + DefaultValueT(ident, expr) => { + let val = if let Some(expr) = expr { + quote!(#expr) } else { let ty = if let Some(ty) = self.ty.as_ref() { ty } else { abort!( ident, - "#[clap(default_value)] (without an argument) can be used \ + "#[clap(default_value_t)] (without an argument) can be used \ only on field level"; note = "see \ https://docs.rs/structopt/0.3.5/structopt/#magical-methods") }; - - quote_spanned!(ident.span()=> { - clap::lazy_static::lazy_static! { - static ref DEFAULT_VALUE: &'static str = { - let val = <#ty as ::std::default::Default>::default(); - let s = ::std::string::ToString::to_string(&val); - ::std::boxed::Box::leak(s.into_boxed_str()) - }; - } - *DEFAULT_VALUE - }) + quote!(<#ty as ::std::default::Default>::default()) }; - self.methods.push(Method::new(ident, val)); + let val = quote_spanned!(ident.span()=> { + clap::lazy_static::lazy_static! { + static ref DEFAULT_VALUE: &'static str = { + let val = #val; + let s = ::std::string::ToString::to_string(&val); + ::std::boxed::Box::leak(s.into_boxed_str()) + }; + } + *DEFAULT_VALUE + }); + + let raw_ident = Ident::new("default_value", ident.span()); + self.methods.push(Method::new(raw_ident, val)); } About(ident, about) => { diff --git a/clap_derive/src/parse.rs b/clap_derive/src/parse.rs index b408f33bb81d..734dd835b17a 100644 --- a/clap_derive/src/parse.rs +++ b/clap_derive/src/parse.rs @@ -26,7 +26,7 @@ pub enum ClapAttr { About(Ident, Option), Author(Ident, Option), Version(Ident, Option), - DefaultValue(Ident, Option), + DefaultValue(Ident, LitStr), // ident = "string literal" RenameAllEnv(Ident, LitStr), @@ -41,6 +41,7 @@ pub enum ClapAttr { // ident = arbitrary_expr NameExpr(Ident, Expr), + DefaultValueT(Ident, Option), // ident(arbitrary_expr,*) MethodCall(Ident, Vec), @@ -75,7 +76,7 @@ impl Parse for ClapAttr { match &*name_str { "rename_all" => Ok(RenameAll(name, lit)), "rename_all_env" => Ok(RenameAllEnv(name, lit)), - "default_value" => Ok(DefaultValue(name, Some(lit))), + "default_value" => Ok(DefaultValue(name, lit)), "version" => { check_empty_lit("version"); @@ -105,13 +106,11 @@ impl Parse for ClapAttr { } } else { match input.parse::() { - Ok(expr) => { - if name_str == "skip" { - Ok(Skip(name, Some(expr))) - } else { - Ok(NameExpr(name, expr)) - } - } + Ok(expr) => match &*name_str { + "skip" => Ok(Skip(name, Some(expr))), + "default_value_t" => Ok(DefaultValueT(name, Some(expr))), + _ => Ok(NameExpr(name, expr)), + }, Err(_) => abort! { assign_token, @@ -176,7 +175,7 @@ impl Parse for ClapAttr { "external_subcommand" => Ok(ExternalSubcommand(name)), "verbatim_doc_comment" => Ok(VerbatimDocComment(name)), - "default_value" => Ok(DefaultValue(name, None)), + "default_value_t" => Ok(DefaultValueT(name, None)), "about" => (Ok(About(name, None))), "author" => (Ok(Author(name, None))), "version" => Ok(Version(name, None)), diff --git a/clap_derive/tests/default_value.rs b/clap_derive/tests/default_value.rs index 6666ac589bd7..d4af6387c129 100644 --- a/clap_derive/tests/default_value.rs +++ b/clap_derive/tests/default_value.rs @@ -5,10 +5,10 @@ mod utils; use utils::*; #[test] -fn auto_default_value() { +fn default_value() { #[derive(Clap, PartialEq, Debug)] struct Opt { - #[clap(default_value)] + #[clap(default_value = "0")] arg: i32, } assert_eq!(Opt { arg: 0 }, Opt::parse_from(&["test"])); @@ -17,3 +17,31 @@ fn auto_default_value() { let help = get_long_help::(); assert!(help.contains("[default: 0]")); } + +#[test] +fn auto_default_value_t() { + #[derive(Clap, PartialEq, Debug)] + struct Opt { + #[clap(default_value_t)] + arg: i32, + } + assert_eq!(Opt { arg: 0 }, Opt::parse_from(&["test"])); + assert_eq!(Opt { arg: 1 }, Opt::parse_from(&["test", "1"])); + + let help = get_long_help::(); + assert!(help.contains("[default: 0]")); +} + +#[test] +fn simple_default_value_t() { + #[derive(Clap, PartialEq, Debug)] + struct Opt { + #[clap(default_value_t = 3)] + arg: i32, + } + assert_eq!(Opt { arg: 3 }, Opt::parse_from(&["test"])); + assert_eq!(Opt { arg: 1 }, Opt::parse_from(&["test", "1"])); + + let help = get_long_help::(); + assert!(help.contains("[default: 3]")); +}