Coding challenge: Can you parse the command line args more elegantly?

J

jrwats

Challenge:
3 options that take an arbitrary parameter afterwards => (n, flavor,
path)
2 options that serve as flags (take no params) => (noupload, debug)
1 option that takes in everything (no matter what follows) to pass to
the helper script as its argument => (options)

The spec requires handling of DOS and UNIX style command line option
prefixes (/ and - respectively). Note that double dashes for prefixes
(--) are not handled. I'm created a hash with the option as key and
the optional param(s) as its value. If the option had no value I just
store the option as the value as well for boolean's sake.

The following is what I did. I feel that someone, somewhere, somehow
can do better:

#!/usr/bin/perl
#perl test.pl -n 3 -flavor retail -debug -path /path/to/file first.dll
second.dll third.dll -options /matches:highlight

use strict;

my $strUsage = <<HEREDOC;

This is a heredoc string!
One day we'll have a real Usage string...

Usage:
-n {number} : Number of times to run
-flavor {flavor} : Flavor or build
-path {path/to/exe} : Exe path
-noupload: Do not upload results
-debug: Run in debugger
-options {options to pass}: Options to pass to cmd

HEREDOC

my @rgArgOptions = ('n', 'flavor', 'path'); #options taking one single
argument
my @rgFlagOptions = ('noupload', 'debug'); #options which take no
argument (flags)

my $strDLL = "";
my %hOpts;

for(my $nArg = 0; $nArg <= $#ARGV; ++$nArg ){

#Look for option prefix
if ($ARGV[$nArg] =~ m/^[\/-].*/ ) {
my $bFound = 0;
# if option matches an option requiring other input add that #
to the options hash and increment $nArg
map {
if (!$bFound && @ARGV[$nArg] =~ m/[\/-]$_/) { $bFound = 1;
$hOpts{$_} = $ARGV[++$nArg]; }
} @rgArgOptions;
# if option matches an option flag (not requiring any input) #
add that to the options hash and do NOT increment $nArg
map {
if (!$bFound && @ARGV[$nArg] =~ m/[\/-]$_/) { $bFound = 1;
$hOpts{$_} = $ARGV[$nArg]; }
} @rgFlagOptions;

if (!$bFound && @ARGV[$nArg] =~ m/[\/-]options/){
$hOpts{'options'} = join (' ', @ARGV[++$nArg .. $#ARGV]);
last; #analagous to 'break;' in C
}
if(!$bFound){
print $strUsage;
exit -1;
}
}else{
# if not an option, must be a DLL
$strDLL .= $ARGV[$nArg] . " ";
}

}

print "strDLL: $strDLL\n";
map { print "$_: $hOpts{$_}\n"} keys %hOpts;
 
K

Kiss Gabor

Challenge:
3 options that take an arbitrary parameter afterwards => (n, flavor,
path)
2 options that serve as flags (take no params) => (noupload, debug)
1 option that takes in everything (no matter what follows) to pass to
the helper script as its argument => (options)

The spec requires handling of DOS and UNIX style command line option
prefixes (/ and - respectively). Note that double dashes for prefixes
(--) are not handled. I'm created a hash with the option as key and
the optional param(s) as its value. If the option had no value I just
store the option as the value as well for boolean's sake.

If I were you first I would transform @ARGV
(change dashes and slashes to double dash in general)
then I'd call Getopt::Long.

Gabor
 
S

sln

If I were you first I would transform @ARGV
(change dashes and slashes to double dash in general)
then I'd call Getopt::Long.

Gabor
Can you just pay money instead of flowery bullshit 'coding challenge'
crapola?

sln
 
U

Uri Guttman

KG> If I were you first I would transform @ARGV
KG> (change dashes and slashes to double dash in general)
KG> then I'd call Getopt::Long.

that won't work in all cases. what if the argument for an option started
with / or -? you wouldn't know if you blindly converted them all to
--. you do need to scan @ARGV to find which args are the option names
and which are the values.

that said, the OP's code is horrible. but i am not in the mood to recode
it or even make snarky comments. this smells like homework again. who in
their right mind would request this for real world work?

uri
 
A

A. Sinan Unur

KG> In article

....

KG> If I were you first I would transform @ARGV
KG> (change dashes and slashes to double dash in general)
KG> then I'd call Getopt::Long. ....

that said, the OP's code is horrible. but i am not in the mood to
recode it or even make snarky comments. this smells like homework
again. who in their right mind would request this for real world work?

Well, I had half an hour to kill so here is a version that seems to
work. As usual, I would love for you to rip it apart (if you have the
time) so i can learn:

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;
use Readonly;

Readonly::Hash my %WITH_VALUE => map { $_ => 1 } qw( n flavor path );
Readonly::Hash my %SWITCHES => map { $_ => 1 } qw( upload debug );
Readonly::Hash my %TO_SLURP => map { $_ => 1 } qw( options );

my @argv = qw(
-n 3
-flavor retail
-debug
-path /path/to/file first.dll second.dll third.dll
-options /matches:highlight
);

print Dumper( parse(@argv) );


sub parse {
my @argv = @_;
my %args;

while ( @argv ) {
my $x = shift @argv;
if ( $x =~ m{^([-/])(.+)} ) {
my ($char, $name) = ($1, $2);
if ( exists $WITH_VALUE{$name} ) {
VALUE:
while ( my $y = shift @argv ) {
if ( $y =~ m{^\Q$char} ) {
unshift @argv, $y;
last VALUE;
}
push @{ $args{$name} }, $y;
}
}
elsif ( exists $SWITCHES{$name} ) {
$args{$name} = $name;
}
elsif ( exists $TO_SLURP{$name} ) {
$args{$name} = join q{ }, @argv;
last;
}
else {
warn "unrecognized: '$name'\n";
}
}
}
return \%args;
}

__END__

Sinan

--
A. Sinan Unur <[email protected]>
(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW:
http://www.rehabitation.com/clpmisc/
 
G

Gary E. Ansok

If I were you first I would transform @ARGV
(change dashes and slashes to double dash in general)
then I'd call Getopt::Long.

Getopt::Long has options to change the option prefix, see its documentation
for more details (look for configuration options prefix, prefix_pattern,
and long_prefix_pattern).

I think calling Getopt::Long::configure('prefix_pattern=-|\/') before
calling GetOptions might allow the OP to do what he wants using
Getopt::Long. However, I haven't used these options myself, so I'm
not able to be more specific.

Gary Ansok
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,537
Members
45,023
Latest member
websitedesig25

Latest Threads

Top