murarth / gumdrop

Rust option parser with custom derive support

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Use Option for optional arguments

canadaduane opened this issue · comments

This would potentially be a breaking API change, but I'd like to suggest that the Option type be used for optional arguments.

Currently, Option seems to be superfluous, as arguments are still optional unless the "required" meta flag is set.

In addition, the following scenario seems to be unachievable with the current implementation:

  • an optional argument that optionally accepts a value
  • has a default value when not set

As an example, let's say a command-line tool normally has output that is unsorted. If you pass the -s argument in, then output should become sorted in some default way (e.g. alphabetically). Additionally, if you pass a value to the -s argument, you can specify the way in which the sort occurs (e.g. "-sa" for alphabetical, "-sn" for numerical).

In my case, the "principal of least surprise" led me to think that the following might achieve that result:

#[derive(Debug, Options)]
struct GramsOptions {
    #[options(help = "sort tallied output: a=alphabetic [DEFAULT], n=numeric")]
    sort: Option<String>,
}

I expected I might be able to parse this as follows:

let sort: Option<Sort> = match opts.sort.as_ref().map(|s| &s[..]) {
    Some("a") => Some(Sort::Alphabetic),
    Some("n") => Some(Sort::Numeric),
    None => Some(Sort::Alphabetic),
};

In addition, the following scenario seems to be unachievable with the current implementation:

  • an optional argument that optionally accepts a value
  • has a default value when not set

Not true. There are at least two ways of accomplishing this:

#[derive(Options)]
struct OptionA {
    sort: Option<String>
}

let opts = OptionA::parse_args_default_or_exit();

// Your code handling the option provides the default value
let sort = match opts.sort.as_ref().map(|s| &s[..]) {
    Some("a") => Sort::Alphabetic,
    Some("n") => Sort::Numeric,
    Some(_) => // error
    None => Sort::Alphabetic,
};

Or:

#[derive(Options)]
struct OptionB {
    #[options(default = "a")]
    sort: String,
}

let opts = OptionB::parse_args_default_or_exit();

// gumdrop provides the default value
let sort = match &opts.sort[..] {
    "a" => Sort::Alphabetic,
    "n" => Sort::Numeric,
    _ => // error
};

The OptionA example is quite similar to your provided example. In what way is this not working as expected?