7

I wrote the following Perl Class:

package Menu;
use strict;

my @MENU_ITEMS;
my $HEADER = "Pick one of the options below\n";
my $INPUT_REQUEST = "Type your selection: ";

sub new {
    my $self = {};
   $self->{ITEM}   = undef;
   $self->{HEADER} = undef;
   $self->{INPUT_REQUEST} = undef;
   bless($self);
   return $self;
}

sub setHeader {
    my $self = shift;
    if(@_) { $self->{HEADER} = shift }
    $HEADER = $self->{HEADER}."\n";
}

sub setInputRequest {
    my $self = shift;
    if(@_) { $self->{INPUT_REQUEST} = shift }
    $INPUT_REQUEST = $self->{INPUT_REQUEST}." ";
}

sub addItem {
    my $self = shift;
    if(@_) { $self->{ITEM} = shift }
    push(@MENU_ITEMS, $self->{ITEM}); 
    }

sub getMenu {
    my $formatted_menu .= $HEADER;
    my $it=1;
    foreach(@MENU_ITEMS) {
        $formatted_menu.=$it.". ".$_."\n";
        $it++
      }
    $formatted_menu.=$INPUT_REQUEST;
    return $formatted_menu;
}
1;

If I call the following perl script:

#!/usr/bin/perl
use strict;
use Menu;

my $menu = Menu->new();
$menu->addItem("First Option");
$menu->addItem("Second Option");
print $menu->getMenu;

I'll get the following output:

Pick one of the options below
1. First Option
2. Second Option
Type your selection:

I'd like to modify given class in a way that I can pass a second argument to the method addItem()

something like: $menu->addItem("First Option", &firstOptionFunction());

and if and only if First Option is selected, then $firstOptionFunction is executed.

Is there any way to achieve such behavior in Perl? Thanks!

ILikeTacos
  • 17,464
  • 20
  • 58
  • 88

1 Answers1

8

You would want to pass a reference to the subroutine.

$menu->addItem("First Option", \&firstOptionFunction);

And your addItem method might look like this:

sub addItem { ## your logic may vary
    my ( $self, $option, $code ) = @_;
    if ( $option eq 'First Option' ) {
        $code->();
    }

    $self->{ITEM} = $option;
    push @MENU_ITEMS, $option;

    return;
}

As you mentioned in the comments, you might want to not pass the subroutine as a reference, but rather store it somewhere else. Something like this might work:

sub new {
    my $class = shift;
    my $self = bless {}, $class;
    $self->{f_o_code} = \&firstOptionFunction; ## use a better name than f_o_code
    return $self;
}

## add your other methods

sub addItem { ## your logic may vary
    my ( $self, $option ) = @_;
    if ( $option eq 'First Option' ) {
        $self->{f_o_code}->();
    }

    $self->{ITEM} = $option;
    push @MENU_ITEMS, $option;

    return;
} ## call like $menu->addItem( 'First Option' );
gpojd
  • 22,558
  • 8
  • 42
  • 71
  • and how would I handle that inside addItem method? I am quite new to Perl, less than a few weeks. I was thinking about something similar, trying to find out a way to get a reference to the location in memory every function has, but I though it would be too hard to achieve. – ILikeTacos May 09 '12 at 20:28
  • You can always store the code_ref in $self like `$self->{first_op_code} = \&firstOptionFunction;` and not pass the reference at all. – gpojd May 09 '12 at 20:31
  • Great! I'll try to tweak the code you posted and see if I can get it to work! Thank you very much. – ILikeTacos May 09 '12 at 20:33
  • Antoher thing, would it be better if use hashes instead of Arrays? In that way I can use the option number as key, and the code_ref as value, right? – ILikeTacos May 09 '12 at 20:38
  • That seems like it would work, but I don't see where `@MENU_ITEMS` is used so I can't say. I would shy away from using globals like that though. For example, consider changing `@MENU_ITEMS` from an array to an arrayref stored in `$self`. If you have two objects of this class, adding one menu item to one would add it to both. – gpojd May 09 '12 at 20:48
  • 1
    @AlanChavez, just so you are aware, my examples are calling the `firstOptionFunction` when the menu item is added. I think you wanted it called when it is selected. You'd probably want to move that if block to the correct place. – gpojd May 09 '12 at 20:53
  • I noticed that, I am working on it right now. Your example has been of great help to me. – ILikeTacos May 09 '12 at 21:06