-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue 459 - Use enums in place of strings #465
Conversation
r? @sru (yo-bot has picked a reviewer for you, use r? to override) |
… vice strings This allows one to use enum variants to access subcommands from the ArgMatches struct in order to reduce the number of "stringly typed" items and reduce errors. In order to use a custom enum, the enum must implement the SubCommandKey trait which defines two methods, one to convert from a &str to it's Self, and one to define the "None" value, meaning no subcommand was used. The enum must also implement the AsRef<str> trait which should be a cheap variant->&str conversion. Relates to #459
…s subcommands Instead of defining all trait implementations manually, one can now do the following: ``` // Note lowercase variants, the subcommand will be exactly as typed here subcommands!{ enum MyProg { show, delete, do, } } // Alternatively, if you wish to have variants which display // differently, or contain hyphens ("-") one can use this variation of // the macro subcommands!{ enum MyProgAlt { Show => "show", Delete => "delete", DoStuff => "do-stuff", } } fn main() { let m = App::new("myprog") .subcommand(SubCommand::with_name(MyProg::show)) .subcommand(SubCommand::with_name(MyProg::delete)) .subcommand(SubCommand::with_name(MyProg::do)) .get_matches(); match m.subcommand() { (MyProg::show, _) => println!("'myprog show' was used"), (MyProg::delete, _) => println!("'myprog delete' was used"), (MyProg::do, _) => println!("'myprog do' was used"), (MyProg::None, _) => println!("No subcommand was used"), } } ``` **NOTE:** It's good practice to make the name of the enum the same as the parent command, and the variants the names of the actual subcommands Notice a fourth "None" option was automatically added. This allows rustc to do some checking for you, i.e. if you add another subcommand later, but forget to check for it, rustc will complain about NonExaustive matches. Likewise, if you make a simple spelling or typing error. Relates to #459
You can consider jhelwig/homers informed/warned. 😉 I've been following the discussion around this pretty closely, and have been looking forward to trying it out. 👍 |
@jhelwig great! This may change slightly as I work with different ideas to try and minimize the breaking changes and such. Once I'm reading to merge, I'll at-mention everyone and give some reasonable notice about how to fix before merging. |
☔ The latest upstream changes (presumably #482) made this pull request unmergeable. Please resolve the merge conflicts. |
An update, I've come up with a way to combine this with a docopt style macro to get rid of nearly all the "stringly" typed-ness. I'm going to be working on this and add it to this PR as I work through some of the final bugs, but here's what it looks like so far: #[macro_use]
extern crate clap;
use clap::{App, Arg};
args!{
MyProg => MyProgArgs {
name: String,
age: u32
}
}
fn main() {
let args: MyProg = App::new("Test Struct App")
.arg(Arg::with_name(MyProgArgs::name)
.long("name")
.value_name("NAME")
.help"(some name"))
.arg(Arg::with_name(MyProgArgs::age)
.long("age")
.short("a")
.value_name("NUM")
.help"(some age"))
.get_matches()
.into();
println!("My name is {} and I'm {} years old", args.name.unwrap(), args.age.unwrap_or(2000));
} Like, I said, there's still some kinks to workout so it'll be a bit before I get it all figured out...but just wanted to update. Relates to #465 |
This pull request will be super-ceded by the v3.x branch merge once ready. |
Do not merge
To Do
subcommands!
macroargs!
macroNotes
I've decided to bump to 3x once this merges, so breakages shouldn't be an issue.