mirror of
https://github.com/clap-rs/clap
synced 2024-12-16 15:52:44 +00:00
Merge pull request #9 from kbknapp/arg_enum_case_sensitive
Add case sensitive option for ArgEnum
This commit is contained in:
commit
f94ef37893
6 changed files with 128 additions and 3 deletions
28
examples/arg_enum_case_sensitive.rs
Normal file
28
examples/arg_enum_case_sensitive.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
#[macro_use]
|
||||
extern crate clap;
|
||||
#[macro_use]
|
||||
extern crate clap_derive;
|
||||
|
||||
use clap::{App, Arg};
|
||||
|
||||
#[derive(ArgEnum, Debug)]
|
||||
#[case_sensitive]
|
||||
enum ArgChoice {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let matches = App::new(env!("CARGO_PKG_NAME"))
|
||||
.arg(Arg::with_name("arg")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.possible_values(&ArgChoice::variants())
|
||||
).get_matches();
|
||||
|
||||
let t = value_t!(matches.value_of("arg"), ArgChoice)
|
||||
.unwrap_or_else(|e| e.exit());
|
||||
|
||||
println!("{:?}", t);
|
||||
}
|
|
@ -20,25 +20,32 @@ impl ClapDerive for ArgEnum {
|
|||
|
||||
fn impl_from_str(ast: &DeriveInput) -> Result<Tokens> {
|
||||
let ident = &ast.ident;
|
||||
let is_case_sensitive = ast.attrs.iter().any(|v| v.name() == "case_sensitive");
|
||||
let variants = helpers::variants(ast)?;
|
||||
|
||||
let strings = variants.iter()
|
||||
.map(|ref variant| String::from(variant.ident.as_ref()))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Yes, we actually need to do this.
|
||||
// All of these need to be iterators.
|
||||
let ident_slice = [ident.clone()];
|
||||
let idents = ident_slice.iter().cycle();
|
||||
|
||||
let for_error_message = strings.clone();
|
||||
|
||||
let condition_function_slice = [match is_case_sensitive {
|
||||
true => quote! { str::eq },
|
||||
false => quote! { ::std::ascii::AsciiExt::eq_ignore_ascii_case },
|
||||
}];
|
||||
let condition_function = condition_function_slice.iter().cycle();
|
||||
|
||||
Ok(quote! {
|
||||
impl ::std::str::FromStr for #ident {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(input: &str) -> ::std::result::Result<Self, Self::Err> {
|
||||
match input {
|
||||
#(val if ::std::ascii::AsciiExt::eq_ignore_ascii_case(val, #strings) => Ok(#idents::#variants),)*
|
||||
#(val if #condition_function(val, #strings) => Ok(#idents::#variants),)*
|
||||
_ => Err({
|
||||
let v = #for_error_message;
|
||||
format!("valid values: {}",
|
||||
|
|
|
@ -44,7 +44,7 @@ trait ClapDerive {
|
|||
}
|
||||
|
||||
/// It is required to have this seperate and specificly defined.
|
||||
#[proc_macro_derive(ArgEnum)]
|
||||
#[proc_macro_derive(ArgEnum, attributes(case_sensitive))]
|
||||
pub fn derive_arg_enum(input: TokenStream) -> TokenStream {
|
||||
ArgEnum::derive(input).unwrap()
|
||||
}
|
45
tests/arg_enum_basic.rs
Normal file
45
tests/arg_enum_basic.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
#[macro_use]
|
||||
extern crate clap;
|
||||
#[macro_use]
|
||||
extern crate clap_derive;
|
||||
|
||||
use clap::{App, Arg};
|
||||
|
||||
#[derive(ArgEnum, Debug, PartialEq)]
|
||||
enum ArgChoice {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_lowercase() {
|
||||
let matches = App::new(env!("CARGO_PKG_NAME"))
|
||||
.arg(Arg::with_name("arg")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.possible_values(&ArgChoice::variants())
|
||||
).get_matches_from_safe(vec![
|
||||
"",
|
||||
"foo",
|
||||
]).unwrap();
|
||||
let t = value_t!(matches.value_of("arg"), ArgChoice);
|
||||
assert!(t.is_ok());
|
||||
assert_eq!(t.unwrap(), ArgChoice::Foo);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_capitalized() {
|
||||
let matches = App::new(env!("CARGO_PKG_NAME"))
|
||||
.arg(Arg::with_name("arg")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.possible_values(&ArgChoice::variants())
|
||||
).get_matches_from_safe(vec![
|
||||
"",
|
||||
"Foo",
|
||||
]).unwrap();
|
||||
let t = value_t!(matches.value_of("arg"), ArgChoice);
|
||||
assert!(t.is_ok());
|
||||
assert_eq!(t.unwrap(), ArgChoice::Foo);
|
||||
}
|
45
tests/arg_enum_case_sensitive.rs
Normal file
45
tests/arg_enum_case_sensitive.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
#[macro_use]
|
||||
extern crate clap;
|
||||
#[macro_use]
|
||||
extern crate clap_derive;
|
||||
|
||||
use clap::{App, Arg};
|
||||
|
||||
#[derive(ArgEnum, Debug, PartialEq)]
|
||||
#[case_sensitive]
|
||||
enum ArgChoice {
|
||||
Foo,
|
||||
Bar,
|
||||
Baz,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_lowercase() {
|
||||
let matches = App::new(env!("CARGO_PKG_NAME"))
|
||||
.arg(Arg::with_name("arg")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.possible_values(&ArgChoice::variants())
|
||||
).get_matches_from_safe(vec![
|
||||
"",
|
||||
"foo",
|
||||
]); // We expect this to fail.
|
||||
assert!(matches.is_err());
|
||||
assert_eq!(matches.unwrap_err().kind, clap::ErrorKind::InvalidValue);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_capitalized() {
|
||||
let matches = App::new(env!("CARGO_PKG_NAME"))
|
||||
.arg(Arg::with_name("arg")
|
||||
.required(true)
|
||||
.takes_value(true)
|
||||
.possible_values(&ArgChoice::variants())
|
||||
).get_matches_from_safe(vec![
|
||||
"",
|
||||
"Foo",
|
||||
]).unwrap();
|
||||
let t = value_t!(matches.value_of("arg"), ArgChoice);
|
||||
assert!(t.is_ok());
|
||||
assert_eq!(t.unwrap(), ArgChoice::Foo);
|
||||
}
|
Loading…
Reference in a new issue