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

Discussion in 'Perl Misc' started by jrwats, Dec 19, 2008.

  1. jrwats

    jrwats Guest

    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;
     
    jrwats, Dec 19, 2008
    #1
    1. Advertisements

  2. jrwats

    Kiss Gabor Guest

    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
     
    Kiss Gabor, Dec 19, 2008
    #2
    1. Advertisements

  3. jrwats

    sln Guest

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

    sln
     
    sln, Dec 19, 2008
    #3
  4. jrwats

    Uri Guttman Guest

    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
     
    Uri Guttman, Dec 19, 2008
    #4
  5. 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 <>
    (remove .invalid and reverse each component for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://www.rehabitation.com/clpmisc/
     
    A. Sinan Unur, Dec 19, 2008
    #5
  6. 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
     
    Gary E. Ansok, Dec 19, 2008
    #6
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.