Skip to content
This repository has been archived by the owner on Jan 1, 2022. It is now read-only.

required_unless, required_unless_one, and required_unless_all for ArgGroup #152

Open
epage opened this issue Dec 6, 2021 · 3 comments
Open

Comments

@epage
Copy link
Owner

epage commented Dec 6, 2021

Issue by AuroransSolis
Thursday Apr 09, 2020 at 10:05 GMT
Originally opened as clap-rs/clap#1801


Describe your use case

The issue this aims to solve is the lack of required_unless, required_unless_one, and required_unless_all for ArgGroup. For example, one might have the following:

let app = App::new("example")
    .arg(Arg::with_name("foo-user")
        .takes_value(true)
        .long("foo-user"))
    .arg(Arg::with_name("foo-user-file")
        .takes_value(true)
        .long("foo-user-file"))
    .group(ArgGroup::with_name("foo-username")
        .args(&["foo-user", "foo-user-file"])
        .multiple(false)
        .requires("foo-password"))
    .arg(Arg::with_name("foo-pass")
        .takes_value(true)
        .long("foo-pass"))
    .arg(Arg::with_name("foo-pass-file")
        .takes_value(true)
        .long("foo-pass-file"))
    .group(ArgGroup::with_name("foo-password")
        .args(&["foo-pass", "foo-pass-file"])
        .multiple(false))
    .group(ArgGroup::with_name("foo-creds")
        .args(&["foo-username", "foo-password"])
        .requires_all(&["foo-username", "foo-password"])
        .multiple(true)
        .required_unless("bar-creds"))
    .arg(Arg::with_name("bar-user")
        .takes_value(true)
        .requires("bar-password")
        .long("bar-user"))
    .arg(Arg::with_name("bar-user-file")
        .takes_value(true)
        .requires("bar-password")
        .long("bar-user-file"))
    .group(ArgGroup::with_name("bar-username")
        .args(&["bar-user", "bar-user-file"])
        .multiple(false))
    .arg(Arg::with_name("bar-pass")
        .takes_value(true)
        .long("bar-pass"))
    .arg(Arg::with_name("bar-pass-file")
        .takes_value(true)
        .long("bar-pass-file"))
    .group(ArgGroup::with_name("bar-password")
        .args(&["bar-pass", "bar-pass-file"])
        .multiple(false))
    .group(ArgGroup::with_name("bar-creds")
        .args(&["bar-username", "bar-password"])
        .multiple(true))
    .arg(Arg::with_name("bar-fallback-to-foo")
        .takes_value(false)
        .requires_all(&["foo-creds", "bar-creds"]));

One might imagine a different situation where required_unless_one or required_unless_all might be of use as well, but the only short example I could come up with is one demonstrating the use of required_unless. This reduces the number of lines required to express certain requirements by moving a required_unless, required_unless_one, or required_unless_all method from each argument in the group to a single one on the group itself. This also makes requirements for group arguments more clear and maintainable, as they're located in a single spot instead of on each group argument.

Alternatives

It may be possible in some situations to use required_unless, required_unless_one, or required_unless_all on the arguments in the group one might otherwise apply to the group itself, but this would be at least one line per argument, possibly more if the slices for required_unless_one or required_unless_all are particularly long.

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by j-delaney
Friday Apr 10, 2020 at 12:18 GMT


I'm happy to take a shot at this if that's okay!

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by Dylan-DPC
Friday Apr 10, 2020 at 12:18 GMT


Go ahead. Thanks

@epage
Copy link
Owner Author

epage commented Dec 6, 2021

Comment by pksunkara
Wednesday May 20, 2020 at 14:14 GMT


Better way to fix this would be implementing the following way

factoring out most of Arg and ArgGroup into new ArgBase struct to avoid code duplication

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant