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

I've got an array of commands like this:
@commands = ("add_node('W1')", "add_node('W2')", "add_edge('W2' => 'W1 +')");
that I want to use as method invokers in a loop like this:
use GraphViz; my $g = GraphViz->new(); foreach $command (@commands) { $g->$command; }
It doesn't seem to be working so I was wondering if there is something I have to do to dress up $command. I'm getting and error message like this:

Can't locate object method ")" via package "add_node('W1')"

Edited 2002-03-21 by Ovid

Replies are listed 'Best First'.
(Ovid) Re: calling methods using a variable
by Ovid (Cardinal) on Mar 22, 2002 at 00:23 UTC

    Here's a quick replication of your problem:

    use strict; use CGI; my $q = CGI->new; my $good_method = "param"; my $bad_method = "param('foo')"; print $q->$good_method( 'foo' ); print $q->$bad_method;

    To fix it, make an array of array refs with the second item being your arguments:

    @commands = ( ['add_node','W1'], ['add_node','W2'], ['add_edge,'W2' => 'W1'] ); use GraphViz; my $g = GraphViz->new(); foreach (@commands) { my ( $command, @args ) = @$_; $g->$command( @args ); }

    Cheers,
    Ovid

    Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      It would also prudent to throw a next unless $g->can($command); or something in there so that things don't go bewm if $command doesn't exist (ie, someone made a tipo [sic.]).

      You might even want to throw in some security checks for good measure...

      foreach (@commands) { my ( $command, @args ) = @$_; warn("Naughty, $command not allowed..."), next unless $permitted{$command}; warn("Ooops, I can't find $command..."), next unless $g->can($command); $g->$command( @args ); }

          --k.


Re: calling methods using a variable
by dws (Chancellor) on Mar 22, 2002 at 00:13 UTC
    If you trust that someone isn't going to hack your command array, you can do
    foreach $command( @commands ) { eval '$g->' . $command; die $@ if $@; }
Re: calling methods using a variable (FORMATTED)
by vladb (Vicar) on Mar 22, 2002 at 00:37 UTC
    Try using eval() instead, since you are trying to also pass a few arguments to the GraphViz methods:
    use GraphViz; my $g = GraphViz->new(); foreach $command (@commands) { eval('$g->'.$command); }
    I'm sure this should work as I did try something similar on CGI module. Here's the code that I used to test it on:
    use strict; use CGI; my @comm = ("header('first')","header('second')"); my $cgi = new CGI; foreach my $comm (@comm) { eval('print $cgi->'.$comm); }
    The output would be:
    Content-Type: first Content-Type: second
    This also works...
    my $comm = "header"; print $cgi->$comm('third');
    however, this won't work:
    my $comm = "header('third')"; print $cgi->$comm


    Cause the last "'" character in the $comm string is considered by Perl to be equivalent to '::' package separator. Therefore, perl is attempting to locate method ")" via package "header('third')" ;-)

    "There is no system but GNU, and Linux is one of its kernels." -- Confession of Faith
Re: calling methods using a variable
by belg4mit (Prior) on Mar 22, 2002 at 07:00 UTC
    As I think dws hinted at... Color me stupid but isn't this just one step short of symbolic references? According to "Is this a symbolic reference?" to, it isn't a symbolic reference proper, but it's in that fuzzy area that would certainly make me think twice.

    --
    perl -pe "s/\b;([st])/'\1/mg"