in reply to Subroutine references inside of a hash with arguments.

I am trying again... with the intent of trying to keep things "easy".

Use a simple command loop like shown below to get user command and do the re-prompting. If you have say just a dozen commands or so, there isn't any need for a fancy hash driven dispatch table. The 12 "if" statements will be plenty fast for the UI especially if you order them in expected frequency of occurence.

If there are sub parms on that command line then give that job to the command subroutine by giving it the original command line or part of it (can strip off "command" from $line before calling sub(), but I wouldn't - if sub has to parse anyway or have other UI interactions let it do it all)

If the defaults to the command are just supplied in the menu routine, then I would simply put them in the sub (why pass the same defaults all the time? could be some good reasons if sub() is used in other contexts, but that's not the case here?).

If passing an anon hash ref, then just go ahead and make a local copy of this thing to simplify the subroutine code (no ref to hash in the rest of code - no need to get fancy when you are learning or when performance won't matter). Code below shows passing anon hash and using defaults in sub.

If one of the "command subs" has its own user interaction, then it is responsible for error message and main command loop will just re-prompt.

#!/usr/bin/perl -w use strict; print "************************************\n"; print "* test - shift9999\n"; print "* Version 0.1 - \"The mule\"\n"; print "************************************\n"; print "\n"; while ( (print "\nEnter Command...: "), (my $line = <STDIN>) !~ /^\s*q(uit)?\s*$/i ) { next if ( $line =~ /^\s*$/); #skip blank lines #and reprompt w/o error msg chomp ($line); #I would be these if statements on one line, but here they are too +long for that... if ($line =~/^\s*one/i) {one($line,{parm1 => 'abc'});} # "one" command elsif ($line =~/^\s*two/i) {two($line);} # "two" command #...etc.. else {print "Invalid command entry!\n";} } sub one { my $line = shift; my $default_href = shift; my %defaults = %$default_href; print "sub one has $line as input line\n"; foreach my $default ( keys %defaults) { print "default: $default is $defaults{$default}\n"; } } sub two { my $line = shift; print "subroutine two has $line as input line\n"; my %defaults = (xyz => '123', ghig => '446'); foreach my $default ( keys %defaults) { print "default: $default is $defaults{$default}\n"; } } __END__ Example Interaction: Enter Command...: one sub one has one as input line default: parm1 is abc Enter Command...: two subroutine two has two as input line default: ghig is 446 default: xyz is 123 Enter Command...: three Invalid command entry! Enter Command...: quit

Replies are listed 'Best First'.
Re^2: Subroutine references inside of a hash with arguments.
by shift9999 (Acolyte) on Jul 29, 2009 at 17:44 UTC

    Thanks for all the great responses! I have not had a chance to read through all of them but I did get the script working the way I wanted, albeit, maybe not the most efficient way.

    I have changed the hash into an array as I dropped the menu names early on but never changed the hash. I am going solely off of Indexes now (thanks for pointing that out ikegami!).

    I then used an  eval() on the menu subroutine names in the array elements rather than the $menu_hash{$bs_index}->();

    I have attached a simple example of the script without the neat menu navigation back\forward\restart\ options that are in the real deal. This is just an example so don't expect a whole lot of error checking and polish.

    #!/usr/bin/perl use warnings; print "********************************************\n"; print "* test app\n"; print "* Version 0.2 - \"The mule\"\n"; print "********************************************\n"; print "\n"; #Define global args my @menu_list = ( "&default", "&get_ifc_name({'ifc_default' => 'test.ifc0'})", "&get_ip_address({'ipaddr_default' => '10.20.1.1'})", "&headr_section", ); &menu_system; sub menu_system(){ #Define our menu system here with the appropriate subs and thier argum +ents $bs_index = shift; #first run check to setup the first menu if(!$bs_index){ #start things off at the first menu $bs_index = "1"; } print "\n*** DBG MENU SYSTEM: Index from args: $bs_index ***"; #check to see if the menu index is defined, otherwise display an error +. if (defined $menu_list[$bs_index]){ #menu is valid, run the sub print "\n*** DBG MENU SYSTEM: running ID: $bs_index ***\n\n" +; eval($menu_list[$bs_index]); } else { print "*** Unknown Menu Called***\n"; } } sub get_ip_address() { my($arg) = shift; print "IP for the Interface [ \"$arg->{'ipaddr_default' +}\" ]\n"; $ip_addr = <STDIN>; chomp($ip_addr); &menu_system("3"); } sub get_ifc_name() { my($arg) = shift; print "Enter an Interface Name [ \"$arg->{'ifc_default' +}\" ]\n"; $device_name = <STDIN>; chomp($device_name); &menu_system("2"); } sub headr_section{ print "*******************************************\n"; print "* Section 2 Header\n"; print "* To skip a step, type \"skip\"\n"; print "* To go back a step, type \"back\"\n"; print "* To restart this step, type \"restart\"\n"; print "********************************************\n\n"; }
    This may not be the best way to do this but it is working for me without any side effects so far. Any pointers are welcome! I don't mind the criticism.