yoda54 has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks, What's the best way to create a menu script with a load of functions? I don't want to pass parameters on the command line so I'd like to avoid Get::Opt. I'm assuming something like this but I'm sure there are plenty of better ways. Please enlighten me... Thanks!!
my %hash = ( "func" => \$func, "func2 => \$func2, ... "func1000 => \$func1000 ); while () { &menu(); print "select: "; chomp($string = <STDIN>); if ($hash{$string}) { $hash{$string}->(); } else { print "No such command: $string\n"; sleep 1; system("clear"); } } sub quit { exit; } sub func { blah... } sub func2 { blah2... } sub menu { while( my ($k, $v) = each %hash) { print "$k \n"; } }

Replies are listed 'Best First'.
Re: menu script
by beable (Friar) on Jul 17, 2004 at 11:23 UTC
    It seems fair enough to me, except for some errors. Check the comments for what was wrong:
    #!/usr/bin/perl use strict; use warnings; my %hash = ( # use ampersands, not dollars func => \&func, func2 => \&func2, ); while () { # don't need ampersand to call function menu(); print "select: "; # use my to declare $string chomp(my $string = <STDIN>); # use exists to stop from auto-vivifying hash elements if (exists $hash{$string}) { $hash{$string}->(); } else { print "No such command: $string\n"; sleep 1; system("clear"); } } sub quit { exit; } sub func { print "running func\n"; } sub func2 { print "running func2\n"; } sub menu { while( my ($k, $v) = each %hash) { print "$k "; } print "\n"; } __END__
Re: menu script
by davido (Cardinal) on Jul 17, 2004 at 15:21 UTC

    Someone already pointed out that you need to define your dispatch table a little differently. Your example is creating a hash of scalar references, instead of a hash of subrefs. I won't belabor that point since it's already been made.

    I did want to mention that your dispatch table needn't use named subs at all. Consider the following code:

    my %dispatch = ( DoThis => sub { print "You asked me to do this.\n"; }, DoThat => sub { print "You asked me to do that.\n"; } );

    For trivial subs, defining them inline like this can be a simple, convenient, and readable solution.

    Another solution is the switch construct:

    SWITCH: for ( @commands ) { m/^This/ && do { print "You asked me to do this.\n"; next SWITCH; }; m/^That/ && do { print "You asked me to do that.\n"; next SWITCH; }; m/^Another/ && Another_Way(); m/^Quit/ && do { print "Goodbye.\n"; last SWITCH; } sub Another_Way { print "You asked me to do it another way.\n"; }

    Of course there are other ways to do it as well... This is Perl after all.


    Dave