Search code examples
perlperl-modulegetopt-long

command line option used in a module and in the main script


I have a module misc which is used by a few scripts. Each script accept two standard options (-help and -verbose) as well as a bunch of its own ones.

So, every scripts now has

my ($verbose,$quiet) = (1,0);
my $help = undef;
...
GetOptions("verbose|v+" => \$verbose, "quiet|q+" => \$quiet, "help|h" => \$help,
           ....)
  or die "GetOptions: error (see above)\n";
if (defined $help) { usage(); exit; }
$verbose -= $quiet;

which is already boring.

Now, I want the misc functions to be aware of the value of $verbose too, so I have to move $verbose et al to misc and use $misc::verbose in scripts:

misc:

our $verbose = 1;
my $quiet = 0;
our $help = undef;
our %common_options = ("verbose|v+" => \$verbose, "quiet|q+" => \$quiet, "help|h" => \$help);
sub set_verbose () { $verbose -= $quiet; }

script:

GetOptions(\%misc::common_options,"verbose|v","quiet|q","help|h",
           "count=i" => \$count, "start=i" => \$start, "mincoverage=i" => \$mincoverage,
           "output=s" => \$output, "input=s" => \$input, "targets=s" => \$targets)
  or die "GetOptions: error (see above)\n";
if (defined $misc::help) { usage(); exit; }
misc::set_verbose();

which does not look much better (and appears to not work anyway, at least -help is ignored).

So, what do people use for command line options shared between modules and scripts?


Solution

  • Personally, I do it simpler:

    • use a hash to store command line options

        GetOptions(\%args, "xxx1","xxx2");
      
    • Pass that hash - as is - to ANY classes' constructrs, or module setters

        my $object = Class1->new(%args, %constructor_args);
        Module2::set_args(\%args); # 
      
    • Argument setter in the module would be:

        # Module2
        our %args;
        sub set_args { %args = %{ shift }; }
      

    This ensures that:

    • I NEVER have to worry about moving parameters from scope to scope and having to modify some calls. They are ALL passed around 100% of needed places

    • Neat and non-messy code. Since we are broadcasting, we don't need to worry about subscribers' individual needs.

    • Pattern easily replicated to ALL classes you own.

    As a matter of fact, if you want to be extra crafty, you can even replace Module2::set_args(\%args); calls for several classes with a smart code that:

    1. Reads in a list of loaded modules

    2. Checks which of those modules implements set_args() call via UNIVERSAL::can()

    3. Calls the supporting modules' set_args() call

    The latter makes the code even cleaner, in that N calls to set_args() one for each non-class module is are all replaced by one set_all_modules_args() call.