Skip to content
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

Closed
wants to merge 2 commits into from
Closed

Conversation

kbknapp
Copy link
Member

@kbknapp kbknapp commented Mar 28, 2016

Do not merge

To Do
  • Implement Functionality for Subcommands
  • Add subcommands! macro
  • Update Subcommands Docs
  • Update Subcommands Examples
  • Add Subcommands Enum Examples
  • Implement functionality for Args
  • Add args! macro
  • Update Args Docs
  • Update Args Examples
  • Add Args Enum Examples
Notes

I've decided to bump to 3x once this merges, so breakages shouldn't be an issue.

@yo-bot
Copy link

yo-bot commented Mar 28, 2016

r? @sru

(yo-bot has picked a reviewer for you, use r? to override)

kbknapp added 2 commits March 27, 2016 22:57
… 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
@coveralls
Copy link

Coverage Status

Coverage decreased (-0.04%) to 88.681% when pulling 548036c on issue-459 into 72ccf0c on master.

@coveralls
Copy link

Coverage Status

Coverage decreased (-0.02%) to 88.704% when pulling 548036c on issue-459 into 72ccf0c on master.

@jhelwig
Copy link

jhelwig commented Mar 28, 2016

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. 👍

@kbknapp
Copy link
Member Author

kbknapp commented Mar 28, 2016

@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.

@homu
Copy link
Contributor

homu commented Apr 17, 2016

☔ The latest upstream changes (presumably #482) made this pull request unmergeable. Please resolve the merge conflicts.

@kbknapp
Copy link
Member Author

kbknapp commented Apr 17, 2016

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

@kbknapp
Copy link
Member Author

kbknapp commented May 18, 2016

This pull request will be super-ceded by the v3.x branch merge once ready.

@kbknapp kbknapp closed this May 18, 2016
@kbknapp kbknapp deleted the issue-459 branch May 20, 2016 01:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants