rjbs / Getopt-Long-Descriptive

Getopt::Long, but simpler and more powerful
20 stars 18 forks source link

one_of's are not exclusive #32

Open Davis-A opened 4 years ago

Davis-A commented 4 years ago

Exclusive one of options are not throwing an error in some combinations.

Code below:

#!/usr/bin/perl

use strict;
use ME;
use DateTime::Format::Strptime;
use Getopt::Long::Descriptive;

my ($opt, $usage) = describe_options(
    '%c %o',
    [ "mode" => hidden => { one_of => [
        [ "ten-minute|t"  => "10 minute truncation" ],
        [ "minute|m"  => "1 minute truncation" ],
        [ "hour|h" => "hour truncation" ],
    ] } ],
    [ 'help', "print usage and exit", { shortcircuit => 1 } ],
    { show_defaults => 1 },
);
print($usage->text), exit if $opt->help;

print $opt->mode . "\n";

Example running and output:

[adavis@box ~]# ./script.pl --help
 script.pl [-hmt] [long options...]
        -t --ten-minute  10 minute truncation
        -m --minute      1 minute truncation
        -h --hour        hour truncation
        --help           print usage and exit
[adavis@box ~]# ./script.pl --ten-minute
ten_minute
[adavis@box ~]# ./script.pl --minute
minute
[adavis@box ~]# ./script.pl --hour
hour
[adavis@box ~]# ./script.pl --ten-minute --minute
minute
[adavis@box ~]# ./script.pl --ten-minute --hour
hour
[adavis@box ~]# ./script.pl --minute --hour
these options conflict; each wants to set the mode: minute hour
[adavis@box ~]# ./script.pl --minute --hour --ten-minute
these options conflict; each wants to set the mode: hour minute
[adavis@box ~]#

Individually they show the correct behavior, set the $opt->mode.

But when combined in this case the top option --ten-minute never conflicts with the next two.

bpj commented 3 years ago

A reasonable workaround until this bug is fixed:

die "The --foo, --bar and --baz options are mutually exclusive.\n" . $usage->text
    if 1 < grep defined($opt->$_), qw(foo bar baz);

die "You must give exactly one of the --foo, --bar and --baz options.\n" . $usage->text 
    unless 1 == grep defined($opt->$_), qw(foo bar baz);
szr8 commented 3 years ago

@bpj I think you may have dropped these: ,,

In all seriousness, it really looks better with the oxford comma:

die "The --foo, --bar, and --baz options are mutually exclusive.\n" . $usage->text
    if 1 < grep defined($opt->$_), qw(foo bar baz);

die "You must give exactly one of the --foo, --bar, and --baz options.\n" . $usage->text 
    unless 1 == grep defined($opt->$_), qw(foo bar baz);
bpj commented 3 years ago

@szr8 I guess I have some gut reaction against separating options with anything but space! 😃 The string has to be adapted to the needs/whims of the program/programmer anyway. The code works.

abraxxa commented 4 months ago

I just stumbled over the same issue which seems to come from having a dash in the option name.