[Chicago-talk] calling functions in a package by its name
Matt Hucke
hucke at cynico.net
Wed Jan 16 10:50:40 PST 2008
Hi,
I have a project in which I make much use of package names that aren't known at compile-time, but
are instead read from a config file. I'd like to be able to load modules, create objects, and call
arbitrary functions in unknown packages without an object reference.
Right now, I can do it by making more use of 'eval' than I'm comfortable with.
Example package:
package MysteryClass;
use strict;
our %secretStuff = ( # caller doesn't know this variable name
text => 'this is config info about package ' . __PACKAGE__
);
sub getConfig # public API, implemented by lots of similar classes
{
return \%secretStuff;
}
sub new
{
my ($class, %args) = @_;
my $self = {
name => $args{name} || "John Doe",
};
bless ($self, $class);
print "I am a new '$class'\n";
return $self;
}
sub doSomethingUseful
{
my ($self) = @_;
print "Hello World from " . ref($self) . "!\n";
}
1;
What I'd like to do is call functions in this package, without explicitly using its name, or
creating an object.
Presently, I use lots of "eval"'s, and it works:
# test.pm
use strict;
use Data::Dumper;
exit(main());
sub main
{
my $classname = "MysteryClass"; # in real life, read it from a config file.
# Load a module identified only at runtime
my $prog = "use $classname;";
eval $prog; die("eval '$prog' failed with " . $@ ) if ($@);
# call a static function from this module, without an object ref
my $conf;
$prog = '$conf = ' . $classname . '::getConfig();';
eval $prog; die("eval '$prog' failed with " . $@ ) if ($@);
print "config is: ". Dumper($conf);
# create an object
my $fred;
my $name = "Fred";
$prog = '$fred=new ' . $classname . '(name => $name)';
eval $prog; die("eval '$prog' failed with " . $@ ) if ($@);
print "object is: ". Dumper($fred);
}
I have been wondering if there's a better way to do it. PerlCritic tells me that stringy eval is
bad; a bit of googling tells me that it's considered harmful because it causes the interpreter to
begin another parsing phase.
Can anyone offer ways to call a function (known at compile-time) in a class known only at run-time,
with neither an object reference or "eval"?
Ideally, I'd also like to be able to do something like "isa" or "can" using just the class name
(after use'ing it) - that way I can have some sanity checking of whatever class name the user put in
the config file, rather than creating a wholly inappropriate object type and only finding out later
that it won't fit.
The project is a web framework that allows for object types to be specified in the config file:
session-manager = FileSession # (or DatabaseSession or NullSession)
template-adapter = TemplateToolkitAdapter # (or TextTemplateAdapter or others)
user-object-class = LocalStuff::MySiteUser # (classes might be customer-written rather than
# part of the framework)
(None of this is really critical... right now, I have a solution - lots of eval's - I'm just hoping
for something a bit more efficient).
thanks
--
hucke at cynico.net
http://www.graveyards.com
More information about the Chicago-talk
mailing list