Skip to content

required_unless, required_unless_one, and required_unless_all for ArgGroup #1801

@AuroransSolis

Description

@AuroransSolis

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-validatorsArea: ArgMatches validation logiC-enhancementCategory: Raise on the bar on expectationsS-waiting-on-mentorStatus: Needs elaboration on the details before doing a 'Call for participation'

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions