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

Hi Monks,

I would like to evaluate a method belonging to a module named within a xml configuration file with each block being:
<word method="MyModule::MethodName()"> MyWord </word>
The module "MyModule" will have been initialised previously by the calling script and passed as within an array reference to the method which reads the configuration file.
my $mod = MyModule->new(); $mod->initialise_stuff("settings");
Then it is passed to the Method which manages the configuration in this manner (the $TPL below is from the excerpts in my implementation, it is an instance of a template module).
$TPL->load_XMLkeywords([ $mod ], cwd()."/../conf/keywords.xml");
Out $TPL->load_XMLkeywords method looks like this (I'm using XML::Twig to parse the XML).
sub load_XMLkeywords { my $self = shift; my $modules = shift; my $filename = shift; warn "Loading XML Keywords\n" if (qw/DEBUG/); my $X = XML::Twig->new(); $X->parsefile($filename); my $root = $X->root(); my @words = $root->children("word"); warn "Element Count ".scalar @words ."\n" if (qw/DEBUG/); foreach my $word(@words) { # Include this word as a keyword. my $key = $word->text(); $key =~ s/\n//g; $self->add_keyword($key); warn "Keyword: ".$key."\n" if (qw/DEBUG/); # Now we need to evaluate the method or query. # and create a field set within our T_KEYWORDS reference. if ($word->att("query")) { # In this case this is a singular database query. my $qq = $word->att("query"); my $sth = $self->dbh()->prepare($qq); $sth->execute(); my $val = $sth->fetchrow(); $self->{T_KEYWORDS}{$key} = $val; warn $key." = $val\n" if (qw/DEBUG/); $X->flush(); } elsif ($word->att("method")) { my $invoke = $word->att("method"); # find a corresponding class. foreach my $class(@$modules) { my $type = ref $class; if ($invoke =~ /$type/) { warn "Found Type $type\n" if (qw/DEBUG/); $invoke =~ s/$type:://g; } my $val; my $statement = '$val = $class->$invoke'; eval $statement; $self->{T_KEYWORDS}{$key} = $val; warn $key." = $val\n" if (qw/DEBUG/); } $X->flush(); } } }
What I am having trouble with is the eval statement where the "method" attribute is set on the word. I am not sure whether I can join a live instance of our $class with the method named in the config file and whether during evaluation I am actually able to evaluate the method of the $class that I am passing this method. I'll still be messing with this but I thought I'd ask the monks to see if anyone had some suggestions.

Thanks,

Chris.

Replies are listed 'Best First'.
Re: Joining Module reference with its method named as string.
by djantzen (Priest) on May 28, 2003 at 03:52 UTC

    Actually, because methods are looked up at runtime you can drop the eval altogether and just do $class->$invoke();. Of course this assumes you've already vetted the value of $invoke to ensure that it's 1) defined in the module; and 2) not a private method or otherwise unfit for use. To be on the safe side, probably using the BLOCK form of eval is the best way to go:

    eval { $val = $class->$invoke() }; warn $@ if $@; # or something

    BTW, it may work better to use an environment variable to indicate debugging mode rather than a harcoded string scattered about.


    "The dead do not recognize context" -- Kai, Lexx
      To be on the safe side, probably using the BLOCK form of eval is the best way to go
      Or better yet, just use can e.g
      sub foo { } my($class, $invoke) = qw/ main foo /; print "$class can $invoke" if UNIVERSAL::can($class, $invoke); __output__ yup

      HTH

      _________
      broquaint

Re: Joining Module reference with its method named as string.
by ceedee (Sexton) on May 28, 2003 at 03:41 UTC
    Well sometimes I need to adopt the foot in mouth position in order to see what I'm saying...this seems to do the trick...
    $invoke =~ s/$type\:\:/\$class\-\>/g;
    my $val; my $statement = "\$val = $invoke"; warn "EVAL:\n $statement\n" if (qw/DEBUG/); eval $statement;