These are chat archives for kbknapp/clap-rs

23rd
Feb 2018
Kevin K.
@kbknapp
Feb 23 2018 01:04
@sdleffler If I were tackling that problem I'd use the normal clap builder pattern. Each subcommand is actually just a facade to an App struct anyways, so it's very easy to split each subcommand up into different modules that are cfg'ed away at compile time. Then you only load the ones you need into your parent App struct
If you go the YAML route, each YAML file would be it's own subcommand (at least the ones you may not be compiling due to feature flags)
Because of how clap nests subcommands in a tree like hierarchy, it's pretty simple to also pass the handling of each subcommand's matches to whatever module the subcommand was made from
I would start with the scaffolding of bare subcommands that do nothing, just to make sure my structure is correct and all modules are built and nested how I'd like. You can also then play with sending the matches for each subcommand into their respective handlers. After that, adding args to each subcommand is the easy part.
So it's easy to build a CLI incrementally, little by little, until all of a sudden you've got a full CLI
Sean Leffler
@sdleffler
Feb 23 2018 01:07
@kbknapp I was originally using the builder pattern. I've been thinking of ways to try to make things more robust, because a lot of hair-tearing madness I ended up with was because things needed to be registered in two places: as a subcommand and then in the match statement from matches.subcommand()
Kevin K.
@kbknapp
Feb 23 2018 01:08
What you do you mean registered in two places?
If the code is open source, if you'd like to point to a link I can take a look
Sean Leffler
@sdleffler
Feb 23 2018 01:09
I made some silly gaffes like creating a subcommand but not connecting it to anything, because I didn't handle the resulting subcommand. So it did nothing and I spent a good two sleep-deprived hours staring at it :P
I basically ended up with a structure that consisted of modules. Each module had two functions: fn command() -> App<'static, 'static> and fn go() -> Result<(), Error>
I think when I start really cementing this stuff in place I'm going to build a Dispatcher type to associate subcommand Apps with functions fn(&ArgMatches) -> Result<(), Error>.
Kevin K.
@kbknapp
Feb 23 2018 01:11
Yep, that's what I meant, except I would probably change the signature of go to fn go(matches: &ArgMatches) -> Result
Sean Leffler
@sdleffler
Feb 23 2018 01:11
Yes, typo, that's what I actually had at the time.
Kevin K.
@kbknapp
Feb 23 2018 01:11
ah gotcha
Sean Leffler
@sdleffler
Feb 23 2018 01:12
I really like the YAML style! It's great not to have the builder cluttering up the actual code. I'll probably go with YAML/an Arena to get the lifetimes out of the way and then eventually a Dispatcher of a sort. Thanks for the pointers :)
Kevin K.
@kbknapp
Feb 23 2018 01:12
no problem! feel free to drop back by or file an issue you need some help :)
And yes, the YAML is a nice way to go if you want to separate things out.
Sean Leffler
@sdleffler
Feb 23 2018 08:30
@tanriol I thought about structopt. Then I figured, "eh, that's way too much." Then I looked at it again, and realized, it's actually perfect! What I can do with structopt is unify CLI and API. I ensure all of my library's public-facing API, that which is meant to be accessed by an end-user, has a structopt-enabled FooArgs struct for any given fn foo(&mut self, args: FooArgs) -> .... And then these, I can easily shove into a clap::App for CLI.
So this way the CLI and API are identical! Thanks much for the suggestion. :)
Sean Leffler
@sdleffler
Feb 23 2018 08:38
I am now extra hyped for clap v3
Kevin K.
@kbknapp
Feb 23 2018 21:41
:)