Sign In/My Account | View Cart  
advertisement


Listen Print Discuss

Option and Configuration Processing Made Easy
by Jon Allen | Pages: 1, 2, 3

If you have a lot of options, it might be helpful to generate the aliases using a function:

use strict;
use warnings;
use Data::Dumper;
use Getopt::Long;

my %specifiers = ( 'source-directory' => '=s',
                   'verbose'          => '' );
my %options;
GetOptions( \%options, optionspec(%specifiers) );

print Dumper(\%options);

sub optionspec {
  my %option_specs = @_;
  my @getopt_list;

  while (my ($option_name,$spec) = each %option_specs) {
    (my $variable_name = $option_name) =~ tr/-/_/;
    (my $nospace_name  = $option_name) =~ s/-//g;
    my  $getopt_name   = ($variable_name ne $option_name)
        ? "$variable_name|$option_name|$nospace_name" : $option_name;

    push @getopt_list,"$getopt_name$spec";
  }

  return @getopt_list;
}

Running this script with each format in turn shows that they are all valid:

varos:~/writing/argvfile jj$ ./optionspec.pl --source-directory /var/spool
$VAR1 = {
          'source_directory' => '/var/spool'
        };

varos:~/writing/argvfile jj$ ./optionspec.pl --source_directory /var/spool
$VAR1 = {
          'source_directory' => '/var/spool'
        };

varos:~/writing/argvfile jj$ ./optionspec.pl --sourcedirectory /var/spool
$VAR1 = {
          'source_directory' => '/var/spool'
        };

Additionally, Getopt::Long is case-insensitive by default (for option names, not values), so your users can also use --SourceDirectory, --sourceDirectory, etc., as well:

varos:~/writing/argvfile jj$ ./optionspec.pl --SourceDirectory /var/spool
$VAR1 = {
          'source_directory' => '/var/spool'
        };

Configuration Files

The next stage on from command-line options is to let your users save their settings into config files. After all, if your program expands to have numerous options it's going to be a real pain to type them in every time.

When it comes to the format of a configuration file, there are a lot of choices, such as XML, INI files, and the Apache httpd.conf format. However, all of these formats share a couple of problems. First, your users now have two things to learn: the command-line options and the configuration file syntax. Second, even though many CPAN modules are available to parse the various config file formats, you still must write the code in your program to interact with your chosen module's API to set whatever variables you use internally to store user settings.

Getopt::ArgvFile to the Rescue

Fortunately, someone out there in CPAN-land has the answer (you can always count on the Perl community to come up with innovative solutions). Getopt::ArgvFile tackles both of these problems, simplifying the file format and the programming interface in one fell swoop.

To start with, the file format used by Getopt::ArgvFile is extremely easy for users to understand. Config settings are stored in a plain text file that holds exactly the same directives that a user would type on the command line. Instead of typing:

myscript --source-directory /usr/local/src --verbose --logval=alert

your user can use the config file:

--source-directory /usr/local/src
--verbose
--logval=alert

and then run myscript for instant user gratification with no steep learning curve.

Now to the clever part. Getopt::ArgvFile itself doesn't actually care about the contents of the config file. Instead, it makes it appear to your program that all the settings were actually options typed on the command line--the processing of which you've already covered with Getopt::Long. As well as saving your users time by not making them learn a new syntax, you've also saved yourself time by not needing to code against a different API.

The most straightforward method of using Getopt::ArgvFile involves simply including the module in a use statement:

use Getopt::ArgvFile home=>1;

A program called myscript that contains this code will search the user's home directory (whatever the environment variable HOME is set to) for a config file called .myscript and extract the contents ready for processing by Getopt::Long.

Here's a complete example:

use strict;
use warnings;
use Getopt::ArgvFile home=>1;
use Getopt::Long;

my %config;
GetOptions( \%config, 'name=s' );

if ($config{name}) {
  print "Hello, $config{name}\n";
} else {
  print "Who am I talking to?\n";
}

Save this as hello, then run the script with and without a command-line option:

varos:~/writing/argvfile jj$ ./hello
Who am I talking to?

varos:~/writing/argvfile jj$ ./hello --name JJ
Hello, JJ

Now, create a settings file called .hello in your home directory containing the --name option. Remember to double quote the value if you want to include spaces.

varos:~/writing/argvfile jj$ cat ~/.hello
--name "Jon Allen"

Running the script without any arguments on the command line will show that it loaded the config file, but you can also override the saved settings by giving the option on the command line as normal.

varos:~/writing/argvfile jj$ ./hello
Hello, Jon Allen

varos:~/writing/argvfile jj$ ./hello --name JJ
Hello, JJ

Pages: 1, 2, 3

Next Pagearrow