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

Inconsistent and incorrect behavior with optional options that take multiple values #323

Closed
jimmycuadra opened this issue Oct 28, 2015 · 5 comments
Labels
A-parsing Area: Parser's logic and needs it changed somehow. C-bug Category: Updating dependencies
Milestone

Comments

@jimmycuadra
Copy link
Contributor

I've come across a few cases using optional options that take multiple values where the input on the CLI is parsed inconsistently or incorrectly depending on the argument order or form.

Given the sample program:

extern crate clap;

use clap::{App, Arg};

fn main() {
    let matches = App::new("example")
        .arg(
            Arg::with_name("positional")
                .index(1)
                .required(true)
        )
        .arg(
            Arg::with_name("optional")
                .short("o")
                .long("optional")
                .takes_value(true)
                .multiple(true)
        )
        .get_matches();

    println!("{:?}", matches.values_of("optional"));
}

Here are some example inputs and their output.

This works:

$ ./target/debug/clap_sample pos -ofoo
Some(["foo"])

Adding a second value for "optional" causes a complete failure:

$ ./target/debug/clap_sample pos -ofoo -obar
error: The following required arguments were not supplied:

USAGE:
    clap_sample <positional> --optional <optional>...

For more information try --help

Using the long form for the second value makes it work:

$ ./target/debug/clap_sample pos -ofoo --optional=bar
Some(["foo", "bar"])

But not if you use a space instead of an equals sign for the key/value delimiter:

$ ./target/debug/clap_sample pos -ofoo --optional bar
error: The following required arguments were not supplied:

USAGE:
    clap_sample <positional> --optional <optional>...

For more information try --help

A single value for "optional" using the long form and a space delimiter fails as well:

./target/debug/clap_sample pos --optional foo
error: The following required arguments were not supplied:

USAGE:
    clap_sample <positional> --optional <optional>...

For more information try --help

While an equals sign works:

$ ./target/debug/clap_sample pos --optional=foo
Some(["foo"])

And adding a second value using the same syntax works:

$ ./target/debug/clap_sample pos --optional=foo --optional=bar
Some(["foo", "bar"])

But using any other form of syntax fails:

$ ./target/debug/clap_sample pos --optional=foo -obar
error: The following required arguments were not supplied:

USAGE:
    clap_sample <positional> --optional <optional>...

For more information try --help
$ ./target/debug/clap_sample pos --optional=foo -o bar
error: The following required arguments were not supplied:

USAGE:
    clap_sample <positional> --optional <optional>...

For more information try --help
$ ./target/debug/clap_sample pos --optional=foo -o=bar
error: The following required arguments were not supplied:

USAGE:
    clap_sample <positional> --optional <optional>...

For more information try --help
$ ./target/debug/clap_sample pos --optional=foo --optional bar
error: The following required arguments were not supplied:

USAGE:
    clap_sample <positional> --optional <optional>...

For more information try --help

If the positional argument is removed from the clap::App, the behavior is different still.

A single value for "optional" continues to work with the short, spaceless form:

./target/debug/clap_sample -ofoo
Some(["foo"])

But adding a second value ignores the second value instead of causing an error like the version with the positional argument did:

$ ./target/debug/clap_sample -ofoo -obar
Some(["foo"])

Using the long form for the second value makes it work, as before:

$ ./target/debug/clap_sample -ofoo --optional=bar
Some(["foo", "bar"])

And even works using a space delimiter, which caused an error in the version with the positional argument!

$ ./target/debug/clap_sample -ofoo --optional bar
Some(["foo", "bar"])

A single value provided using the long option in both forms works:

$ ./target/debug/clap_sample --optional bar
Some(["bar"])
$ ./target/debug/clap_sample --optional=bar
Some(["bar"])

As does providing a second value with either form of the long option:

$ ./target/debug/clap_sample --optional foo --optional bar
Some(["foo", "bar"])
$ ./target/debug/clap_sample --optional foo --optional=bar
Some(["foo", "bar"])

But using the short form for the second value, only a space delimiter actually captures the value:

$ ./target/debug/clap_sample --optional foo -obar
Some(["foo"])
$ ./target/debug/clap_sample --optional foo -o=bar
Some(["foo"])
$ ./target/debug/clap_sample --optional foo -o bar
Some(["foo", "bar"])

I know that providing multiple values without repeating the name of the option itself (-o foo bar or --optional foo bar) works more consistently (but not in all cases!), but my expectation is that all variations of short and long forms, with or without the app having a positional argument, should correctly recognize the option and extract all the provided values.

All these examples use clap 1.4.5 on Rust 1.3 (OS X). Hope this is helpful! Thanks!

@kbknapp
Copy link
Member

kbknapp commented Oct 28, 2015

Thanks for the detailed write, we really appreciate it! I'll start working on this bug and post back here with updates 👍

@kbknapp kbknapp added C-bug Category: Updating dependencies P1: urgent A-parsing Area: Parser's logic and needs it changed somehow. labels Oct 28, 2015
@kbknapp
Copy link
Member

kbknapp commented Oct 28, 2015

These are the forms I'm tracking as not working. I'll check off as fixed.

  • $ prog pos -ofoo -obar
  • $ prog pos -o foo -obar
  • $ prog pos -ofoo -o bar
  • $ prog pos -ofoo --optional bar
  • $ prog pos --optional foo
  • $ prog pos --optional=foo -obar
  • $ prog pos --optional=foo -o bar
  • $ prog pos --optional=foo --optional bar
  • $ prog --optional foo -obar
  • $ prog -ofoo -obar
  • $ prog -o foo -obar
  • $ prog -ofoo -o bar
  • $ prog --optional foo -obar

One note is that forms like this $ ./target/debug/clap_sample pos --optional=foo -o=bar aren't designed to be supported. No reason we probably couldn't add it, but the short form with = wasn't an intended form. Just FYI ;)

@jimmycuadra
Copy link
Contributor Author

Thanks so much! I don't actually use the equals form myself, but some tools do (even exclusively) so once I realized there was some strangeness going on I started trying all the combinations I could think of. :}

@kbknapp
Copy link
Member

kbknapp commented Oct 28, 2015

@jimmycuadra All those bugs are fixed with #324

One thing that has not been added yet is using = with a short option (long option and = works). Is that required for your use case? If so, we can add it to the tracker for implementation.

@kbknapp kbknapp added this to the 1.4.6 milestone Oct 28, 2015
@jimmycuadra
Copy link
Contributor Author

That was fast! No, I don't have any particular use for the short form with an equals sign. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-parsing Area: Parser's logic and needs it changed somehow. C-bug Category: Updating dependencies
Projects
None yet
Development

No branches or pull requests

2 participants