Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add `EnumVariantNames` This derive adds a static `variants()` methods yielding the names of the enum variants. This happens to be exactly what clap [wants][1], and is the last puzzle piece to use strum with clap/structopt. [1]: https://docs.rs/clap/2.33.0/clap/macro.arg_enum.html * Expand readme section for `EnumVariantNames` * Return slice instead of array This reduces the risk of breaking the public API by accident when adding a new variant. * Fix typo in Readme * Add generic doc comment to `variants()` method * Add test case using `variants` in clap/structopt
- Loading branch information
1 parent
970b5ce
commit 96daaf4
Showing
6 changed files
with
191 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use proc_macro2::TokenStream; | ||
use syn; | ||
|
||
use case_style::CaseStyle; | ||
use helpers::{convert_case, extract_meta, unique_attr}; | ||
|
||
pub fn enum_variant_names_inner(ast: &syn::DeriveInput) -> TokenStream { | ||
let name = &ast.ident; | ||
|
||
let variants = match ast.data { | ||
syn::Data::Enum(ref v) => &v.variants, | ||
_ => panic!("EnumVariantNames only works on Enums"), | ||
}; | ||
|
||
// Derives for the generated enum | ||
let type_meta = extract_meta(&ast.attrs); | ||
let case_style = unique_attr(&type_meta, "strum", "serialize_all") | ||
.map(|style| CaseStyle::from(style.as_ref())); | ||
|
||
let names = variants | ||
.iter() | ||
.map(|v| convert_case(&v.ident, case_style)) | ||
.collect::<Vec<_>>(); | ||
|
||
quote! { | ||
impl #name { | ||
/// Return a slice containing the names of the variants of this enum | ||
#[allow(dead_code)] | ||
pub fn variants() -> &'static [&'static str] { | ||
&[ | ||
#(#names),* | ||
] | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
#[macro_use] | ||
extern crate strum_macros; | ||
#[macro_use] | ||
extern crate structopt; | ||
extern crate strum; | ||
|
||
#[test] | ||
fn simple() { | ||
#[allow(dead_code)] | ||
#[derive(EnumVariantNames)] | ||
enum Color { | ||
Red, | ||
Blue, | ||
Yellow, | ||
} | ||
|
||
assert_eq!(&Color::variants(), &["Red", "Blue", "Yellow"]); | ||
} | ||
|
||
#[test] | ||
fn plain_kebab() { | ||
#[allow(dead_code)] | ||
#[derive(EnumVariantNames)] | ||
#[strum(serialize_all = "kebab_case")] | ||
enum Color { | ||
Red, | ||
Blue, | ||
Yellow, | ||
RebeccaPurple, | ||
} | ||
|
||
assert_eq!( | ||
&Color::variants(), | ||
&["red", "blue", "yellow", "rebecca-purple"] | ||
); | ||
} | ||
|
||
#[test] | ||
fn non_plain_camel() { | ||
#[allow(dead_code)] | ||
#[derive(EnumVariantNames)] | ||
#[strum(serialize_all = "kebab_case")] | ||
enum Color { | ||
DeepPink, | ||
GreenYellow, | ||
CornflowerBlue, | ||
Other { r: u8, g: u8, b: u8 }, | ||
} | ||
|
||
assert_eq!( | ||
&Color::variants(), | ||
&["deep-pink", "green-yellow", "cornflower-blue", "other"] | ||
); | ||
} | ||
|
||
#[test] | ||
fn clap_and_structopt() { | ||
#[derive(Debug, EnumString, EnumVariantNames)] | ||
#[strum(serialize_all = "kebab_case")] | ||
enum Color { | ||
Red, | ||
Blue, | ||
Yellow, | ||
RebeccaPurple, | ||
} | ||
|
||
assert_eq!( | ||
&Color::variants(), | ||
&["red", "blue", "yellow", "rebecca-purple"] | ||
); | ||
|
||
let _clap_example = clap::App::new("app").arg( | ||
clap::Arg::with_name("color") | ||
.long("color") | ||
.possible_values(Color::variants()) | ||
.case_insensitive(true), | ||
); | ||
|
||
#[derive(Debug, StructOpt)] | ||
#[allow(unused)] | ||
struct StructOptExample { | ||
/// The main color | ||
#[structopt( | ||
long = "color", | ||
default_value = "Color::Blue", | ||
raw(possible_values = "Color::variants()") | ||
)] | ||
color: Color, | ||
} | ||
} |