Samuel
Samuel

Reputation: 8905

GetOptions Check Option Values

I am updating an existing Perl script that uses GetOptions from Getopt::Long. I want to add an option that takes a string as its parameter and can only have one of 3 values: small, medium, or large. Is there any way to make Perl throw an error or kill the script if any other string value is specified? So far I have:

my $value = 'small';
GetOptions('size=s'  => \$value);

Upvotes: 1

Views: 3312

Answers (5)

ikegami
ikegami

Reputation: 385657

It's just one of a few checks you need to perform after GetOptions returned.

  • You need to check if GetOptions succeeded.
  • You may need to check the value provided for each optional argument.
  • You may need to check the number of arguments in @ARGV.
  • You may need to check the arguments in @ARGV.

Here's how I perform those checks:

use Getopt::Long qw( );

my %sizes = map { $_ => 1 } qw( small medium large );

my $opt_size;

sub parse_args {
   Getopt::Long::Configure(qw( :posix_default ));

   $opt_size = undef;

   Getopt::Long::GetOptions(
      'help|h|?' => \&exit_with_usage,
      'size=s'   => \$opt_size,
   )
      or exit_bad_usage();

   exit_bad_usage("Invalid size.\n")
      if defined($size) && !$sizes{$size};

   exit_bad_usage("Invalid number of arguments.\n")
      if @ARGV;
}

Here's how I handle failures:

use File::Basename qw( basename );

sub exit_with_usage {
   my $prog = basename($0);
   print("usage: $prog [options]\n");
   print("       $prog --help\n");
   print("\n");
   print("Options:");
   print("   --size {small|medium|large}\n");
   print("      Controls the size of ...\n"
   exit(0);
} 

sub exit_bad_usage {
   my $prog = basename($0);
   warn(@_) if @_;
   die("Use $prog --help for help\n");
   exit(1);
} 

Upvotes: 1

Hunter McMillen
Hunter McMillen

Reputation: 61512

An alternative to Getopt::Long is Getopt::Declare which has built in pattern support, but is slightly more verbose:

use strict; 
use warnings; 

use feature qw/say/;
use Getopt::Declare; 

my $args = Getopt::Declare->new(
   join "\n",
      '[strict]', 
      "-size <s:/small|medium|large/>\t small, medium, or large [required]"
) or exit(1);

say $args->{-size};

Test runs:

[hmcmillen]$ perl test.pl -size small
small
[hmcmillen]$ perl test.pl -size medium
medium
[hmcmillen]$ perl test.pl -size large
large
[hmcmillen]$ perl test.pl -size extra-large
Error: incorrect specification of '-size' parameter
Error: required parameter -size not found.
Error: unrecognizable argument ('extra-large')

(try 'test.pl -help' for more information)

Upvotes: 0

Ron Bergin
Ron Bergin

Reputation: 1068

You could use a subroutine to handle the processing of that option. User-defined subroutines to handle options

my $size = 'small';  # default
GetOptions('size=s'  => \&size);
print "$size\n";

sub size {
    my %sizes = (
            small  => 1,
            medium => 1,
            large  => 1
    );

    if (! exists $sizes{$_[1]}) {
        # die "$_[1] is not a valid size\n";

        # Changing it to use an exit statement works as expected
        print "$_[1] is not a valid size\n";
        exit;
    }

    $size = $_[1];
}

I put the sizes into a hash, but you could use an array and grep as toolic showed.

Upvotes: 3

simbabque
simbabque

Reputation: 54323

This might be overkill, but also take a look Getopt::Again, which implements validation through its process configuration value per command line argument.

use strict;
use warnings;
use Getopt::Again;

opt_add my_opt => (
    type        => 'string',
    default     => 'small',     
    process     => qr/^(?:small|medium|large)$/, 
    description => "My option ...",
);

my (%opts, @args) = opt_parse(@ARGV);

Upvotes: 0

toolic
toolic

Reputation: 62037

One way is to use grep to check if the value is legal:

use warnings;
use strict;
use Getopt::Long;

my $value = 'small';
GetOptions('size=s'  => \$value);

my @legals = qw(small medium large);
die "Error: must specify one of @legals" unless grep { $_ eq $value } @legals;

print "$value\n";

Upvotes: 1

Related Questions