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

Hello monks!

I need wisdom and sage advice about the Right Way ( or Ways ) to pull in modules at runtime. This is along the lines of getting the name of the module in runtime and calling a function from that module, but in an OO context.

Consider my situation:

The goal is this -- I have many different types of data collections in different languages, including nontext data - I want to be able to select the appropriate parser from a config file so that I can benefit from polymorphism. I ask the parser for word lists, and I don't want to worry about what 'word list' means for that docment collection. For some it will mean splitting on white space, for others it will be sophisticated part-of-speech tagging - whatever.

I have a document collection object ( LSI::Collection ) whose constructor reads a config file to figure out which parser to use. This parser can come in many, many flavors, all of them subclasses of a common ancestor, which serves as the default if none is defined in the config file.

My problem is this - some of these parsers do a lot of setup in the class constructor, which makes for a long wait at startup. Also, I don't want to clutter my Collection class with a zillion 'use' or 'require' statements. Here is a solution that I've found to dynamically require modules as needed, but it my bones it feels like the wrong way to do it:
my $parser; my $m = $params{'parse_method'}; # from the config file # this is a hash of parser names to modules my %flavors = ( 'POS' => 'LSI::Parser::POS', 'Regexp' => 'LSI::Parser::POS::Regexp', 'JSTOR' => 'LSI::Parser::POS::JSTOR' ); my $flavor = $flavors{ $m } || 'LSI::Parser'; # default # This is what makes me uneasy... eval "require $m" ; $self->{'parser '} = ($m)->new();
Is there a better way to do this? What is a virtuous way to add error handling here? Humble thanks in advance.

Replies are listed 'Best First'.
Re: How best to require subclasses at runtime
by fglock (Vicar) on Nov 07, 2002 at 17:30 UTC

    I'm using  eval "use $m"; to solve a similar problem.
    I'm interested in learning other options too.

    About the startup wait, Perl 5.8 has an "autouse" option, that postpone load of modules until a function is used.

      And CPAN has Class::Autouse

      OR
      # I use $module, because $m is not descriptive enough for me. $package_file = $module . '.pm'; $package_file =~ s~::~/~g; # Should probably use a module to get the seperator, but whatever. require($package_file) or die ( $@ ); $self->{'parser '} = $module->new();


      Gyan Kapur
      gyan.kapur@rhhllp.com
Re: How best to require subclasses at runtime
by webengr (Pilgrim) on Nov 07, 2002 at 18:49 UTC

    I have much the same situation with an app that I wrote. The driver script needs to load a series of modules that I specify in a hash... the keys are class names, and the values are array refs with the instantiation parms.

    Anyway, I just look for errors from the eval, which you can parse for keywords if you need. Then I write to a logging class, and move to the next classname.

    The relevant code extract:

    for my $sysName ( keys %systemList ) { ## Loop through system types $logger->msg("loading class $sysName",0); eval "require $sysName"; ## include the proper module file if ($@) { $logger->msg("Package $sysName not found.",3); next; } ## instantiate the new object my $obj = new ${sysName}( @{$systemList{$sysName}} ); ### etc... }

    It may not be the "right" way, but it is working for my purposes. Good luck!



    PCS
Re: How best to require subclasses at runtime
by impossiblerobot (Deacon) on Nov 08, 2002 at 03:06 UTC

    If I understand your problem correctly, this seems to be a good use for Class::Factory.

    It provides a subclassable interface for creating factory classes, and allows for lazy loading of the various modules. (A factory method basically exists to instantiate objects without having to know which object you are going to instantiate ahead of time. Class::Factory helps to create Abstract Factory classes containing methods that other classes can call. It then returns the proper type of object based on how it is called.)

    (I'm sorry if this isn't very clear; I'll think about how I can reword it.)

    Update: Added to explanation of factory methods/classes.

    Update: The explanation of the Abstract Factory pattern at the Wikipedia is probably better than what I could come up with. :-)


    Impossible Robot
Re: How best to require subclasses at runtime
by Ryszard (Priest) on Nov 08, 2002 at 08:28 UTC
    I've done something similar to what you want by using File::Find.

    You can find my node here and a solution here.

    To recap, I wanted to load a list of unknown modules at runtime. The application is an API, and whenever a new hook was built, I didnt want the hastle of buggerising around with config files..

    All I have to do now, is restart the server, and any modules in the path will be automatically have their instance created, and stored in $self.