Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

comment on

( [id://3333]=superdoc: print w/replies, xml ) Need Help??
I had this same issue recently. I rolled my own solution and it's been working well. I used Getopt::Long to parse the options on the command line and my own wrapper around Config::IniFiles to parse the INI file. Basically, what I do is create an empty hash to hold the options. Then I pass that hash to a sub that processes the command line, setting any elements in the hash that are specified there. Then I pass the same hash to another sub to process the INI file which will set options ONLY if they haven't already been set on the command line (e.g. the options are not already defined in the hash). In the main program I have this:
use ConfigIni; #my own wrapper use Getopt::Long; my %config; get_options(\%config); init_config(\%config); #now %config holds all your parameters and they're properly initialize +d -- the command line overrides anything in the ini file
These two subs are defined like this (there are probably cleaner ways to process the args but this works fine for my simple prog.)
sub get_options { #process any command line options my $config = shift; #hash ref my ($debug,$test,$ini_file,$max_files, $data_dir,$log_dir,$user,$pass,$verbose, $no_ini); GetOptions('debug=i' => \$debug, 'test=i' => \$test, 'ini_file=s' => \$ini_file, 'max_files=i' => \$max_files, 'data_dir=s' => \$data_dir, 'log_dir=s' => \$log_dir, 'user=s' => \$user, 'pass=s' => \$pass, 'verbose=i' => \$verbose, 'no_ini' => \$no_ini, ); $config->{debug} = $debug if defined $debug; $config->{test} = $test if defined $test; $config->{ini_file} = $ini_file if defined $ini_file; $config->{max_files} = $max_files if defined $max_files; $config->{data_dir} = $data_dir if defined $data_dir; $config->{log_dir} = $log_dir if defined $log_dir; $config->{user} = $user if defined $user; $config->{password} = $pass if defined $pass; $config->{verbose} = $verbose if defined $verbose; $config->{no_ini} = $no_ini if defined $no_ini; } sub init_config { #initialize the config parameters for the program my $config = shift; #hash ref my $bindir = $FindBin::Bin; #these get set no matter what $config->{version} = $VERSION; #these first two are just program + constants $config->{revision} = ($REVISION =~ /(\d+\.\d+)/) ? $1 : '?'; #if command line option -no_ini specified, then don't try to load +the ini file unless ($config->{no_ini}) { #process the ini file #if we already have an ini_file, use that one, otherwise use t +he default file my $config_file = $config{ini_file} || "$bindir/configfile.ini +"; #default name for ini file my $ini = new ConfigIni($config_file) || croak "could not load + ini file $config_file"; $config->{ini_file} = $config_file if not defined $config->{in +i_file}; #now load and set the parameters $config->{debug} = $ini->get_ini_val('Debug','Debug',0) if not + defined $config->{debug}; $config->{test} = $ini->get_ini_val('Debug','Test',0) if not +defined $config->{test}; $config->{max_files} = $ini->get_ini_val('Debug','Max_files',0 +) if not defined $config->{max_files}; $config->{data_dir} = $ini->get_ini_val('General','Data_dir') +if not defined $config->{data_dir}; $config->{log_dir} = $ini->get_ini_val('General','Log_dir') if + not defined $config->{log_dir}; $config->{user} = $ini->get_ini_val('General','User') if not d +efined $config->{user}; $config->{password} = $ini->get_ini_val('General','Password') +if not defined $config->{password}; $config->{verbose} = $ini->get_ini_val('General','Verbose',1) +if not defined $config->{verbose}; } #unless ($config->{no_ini}) #if log_dir isn't set, put logs in the same directory as the progr +am $config->{log_dir} ||= $bindir; $config->{log_file} = $config{log_dir} . "/log_file_" . strftime(" +%Y%m%d_%H%M%S_",localtime) . "$$.log"; #init anything that needs to be and might not have been done on ei +ther command line or ini_file $config->{debug} = 0 if not defined $config->{debug}; $config->{test} = 0 if not defined $config->{test}; $config->{verbose} = 1 if not defined $config->{verbose}; $config->{max_files} = 0 if not defined $config->{max_files}; #check to make sure info is complete croak "User must be specified in [General] section of ini file" if + !defined $config->{user}; croak "Password must be specified in [General] ini file" if !defin +ed $config->{password}; croak "Data_dir must be specified in [General] section of ini file +" if !defined $config->{data_dir}; } #sub init_config
For various reasons I wrote a wrapper around Config::IniFiles. One reason was to allow multivalued parameters (which Config::Ini did but had other issues). Here's that custom wrapper:
package ConfigIni; use strict; use warnings; use Config::IniFiles; use Text::CSV; use Carp; our $VERSION = '0.01'; sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; $self->{file} = shift || ""; $self->{ini} = new Config::IniFiles( -file => $self->{file}, -noca +se => 1); return undef if not defined $self->{ini}; bless $self, $class; return $self; } sub get_ini_val { #return a single valued parameter my $self = shift; my $section = shift || croak "must provide section to get_ini_val" +; my $param = shift || croak "must provide param to get_ini_val"; my $default = shift; #optional default value my $val = $self->{ini}->val($section,$param); if (!defined $val) { $val = $default; #undef if default no provided } return $val; } sub get_ini_val_multi { #return a list of a multi-valued parameter my $self = shift; my $section = shift || croak "must provide section to get_ini_val" +; my $param = shift || croak "must provide param to get_ini_val"; my $default = shift; #array ref to optional default values my $values = $self->{ini}->val($section,$param); my @values = (); if (defined $values) { my $csv = Text::CSV->new(); my $status = $csv->parse($values); croak "error parsing $section, $param, with value = $values" u +nless $status; @values = $csv->fields(); } else { @values = $default ? @{$default} : (); } return @values; } 1;

In reply to (RhetTbull) Re: Prioritizing command line options by RhetTbull
in thread Prioritizing command line options by kvh009

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others cooling their heels in the Monastery: (5)
As of 2024-04-19 20:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found