Structopt: default_value and Option?

Created on 9 Jul 2018  路  10Comments  路  Source: TeXitoi/structopt

Right now, they are incompatible, but I'm not sure that's right. For example, I wanted something like my-app --db-path [DB], where there's a default database path if not set.

Is there another way to achieve that?

enhancement

Most helpful comment

extern crate clap;

use clap::{App, Arg, ArgMatches};

fn get_optional_value<'a, 'b>(m: &'a ArgMatches, name: &'b str) -> Option<&'a str> {
    if m.occurrences_of(name) == 0 {
        None
    } else {
        m.value_of(name)
    }
}

fn main() {
    let app = App::new("my-app").arg(Arg::with_name("db").long("db").default_value("my-app.db"));

    let m = app.clone().get_matches_from(vec!["my-app", "--db"]);
    assert!(get_optional_value(&m, "db") == Some("my-app.db"));

    let m = app
        .clone()
        .get_matches_from(vec!["my-app", "--db", "foo.db"]);
    assert!(get_optional_value(&m, "db") == Some("foo.db"));

    let m = app.clone().get_matches_from(vec!["my-app"]);
    assert!(get_optional_value(&m, "db") == None);
}

All 10 comments

Can you give example of command line and corresponding struct, because I don't understand what you expect.

#[derive(Clone, Debug, StructOpt)]
pub struct Options {
    #[structopt(long = "db", help = "Database path", default_value = "my-app.db")]
    pub db: Option<String>,
}

Example usage:

$ my-app # db is None
$ my-app --db # db is Some("my-app.db")
$ my-app --db foo.db # db is Some("foo.db")

In clap, an argument takes value or not: https://docs.rs/clap/2.32.0/clap/struct.Arg.html#method.takes_value

Thus, I don't think that's possible to have an argument that can optionally take value, That's why default_value is prohibited in Option, as it will always have a value, and thus will always be Some(a).

I suppose default_value and occurrences_of could be used in this case. The latter will return zero if the argument wasn't passed at all.

I can't find any way to do it using clap. If you can show me a working program doing what you want with clap, I'll try to allow using the feature in structopt.

extern crate clap;

use clap::{App, Arg, ArgMatches};

fn get_optional_value<'a, 'b>(m: &'a ArgMatches, name: &'b str) -> Option<&'a str> {
    if m.occurrences_of(name) == 0 {
        None
    } else {
        m.value_of(name)
    }
}

fn main() {
    let app = App::new("my-app").arg(Arg::with_name("db").long("db").default_value("my-app.db"));

    let m = app.clone().get_matches_from(vec!["my-app", "--db"]);
    assert!(get_optional_value(&m, "db") == Some("my-app.db"));

    let m = app
        .clone()
        .get_matches_from(vec!["my-app", "--db", "foo.db"]);
    assert!(get_optional_value(&m, "db") == Some("foo.db"));

    let m = app.clone().get_matches_from(vec!["my-app"]);
    assert!(get_optional_value(&m, "db") == None);
}

I'll try to see how I can do it cleanly in structopt. Thanks for the example.

Another way of achieving optional value of the long argument in clap is to use Arg::min_values(0) as described here: https://github.com/clap-rs/clap/issues/892

Then we can distinguish between say --help and --help topic by checking matches.is_present("help") and pattern matching matches.value_of("help") against Some (as demonstrated in the code from the issue linked above).

I am now trying to describe this behaviour with structopt, but can't find a way :( It sets the field of the datatype to None in both cases when it's omitted and when its value is empty, so I can't tell the difference.

@sphynx That's a quite different topic. You'd want support for Option<Option<T>> or Option<Vec<T>>. If that's what you're looking for, then you can create an issue about this.

As a workaround, you can do the parsing "by hand":

let app = Opt::clap();
let matches = app.get_matches();
// do something special to retrive the needed information
let opt = Opt::from_matches(&matches);

@TeXitoi Thanks for your reply! As suggested, I've created a new issue: #188

I think I'll either have to use the workaround or restructure the arguments differently for now.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wez picture wez  路  7Comments

epage picture epage  路  7Comments

jackjen picture jackjen  路  7Comments

liamdawson picture liamdawson  路  5Comments

mbrobbel picture mbrobbel  路  5Comments