in reply to Re^4: CLI using hashes
in thread CLI using hashes

Along with the fine comments by fishbot_v2, I'd also like to point out that your subroutines need not be named. This is the perfect situation to use anonymous subroutines. Here's how I would define your hash:

my %commands = ( "set time" => sub { print "nMetrics>You have entered the settime command\n"; print "nMetrics>The argument given is $_[0]\n"; }, "show time" => sub { print "nMetrics>You have entered the show time command\n"; }, default => sub { print "nMetrics>Invalid command line options\n"; } );

Replies are listed 'Best First'.
Re^6: CLI using hashes
by bahadur (Sexton) on May 30, 2005 at 05:59 UTC
    well the thing is that this is initial code which is going to grow in length. so i need to define sub routines clearly in case i leave the programmer leaving me can understand the code easily. plus can u just tell how u are passing the arguments to the routines.
    can u just give a snippet of how it is going to work in the while loop
      Trust me on this: if you organize your code the way revdiablo suggested, no one will have trouble understanding what's going on. People who are still somewhat new to perl will most likely learn a lot from looking at such code, but I don't think they'll have trouble understanding it. You could actually put the "%commands" declaration (with all the sub definitions) in a separate source file, and just "require" that file in your main script -- on the whole, if you can "objectify" and "modularize" your scripting, you'll be better off (and so will anyone who inherits the code from you).

      As for defining the CLI grammar, you could simplify things a lot by sticking with single-word commands; e.g.:

      time # with no args, command means "show time" time arg [...] # with args, it means "set time"
      and so on. By writing the command handler functions to work this way, you'll need fewer distinct commands, which will be nice for everybody involved. So it could look like this:
      while (<STDIN>) { my ( $cmd, @args ) = split; if ( exists( $command{$cmd} )) { $command{$cmd}->( @args ); else { $command{default}->(); } }

      One more suggestion: you might look into Term::Readline, to enable various nifty unix-shell-like behaviors (command line editing, command history and recall, tab completion of commands and file names, etc).

      Update: forgot to suggest how some functions might be written:

      my %command = ( time => sub { if ( @_ == 0 ) { print "time is ", scalar localtime, $/; } else { print "let's pretend the time is @_\n"; } }, date => sub { if ( @_ == 0 ) { print "You don't have a date for tonight\n"; } else { print "Okay, we'll see if @_ will go out with you\n"; } }, # ... and so on (updated to remove undeclared array) );
      revdiablo's are full-fledged subs: they accept arguments in exactly the same way named subs do:
      my $foo = { my ($first, $second) = @_; print "first argument: [$first]\n"; print "second one : [$second]\n"; } $foo->("bar", "baz");

      Flavio (perl -e 'print(scalar(reverse("\nti.xittelop\@oivalf")))')

      Don't fool yourself.