Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid

Plugin-type architecture

by thor (Priest)
on Jan 10, 2006 at 17:28 UTC ( #522248=perlquestion: print w/replies, xml ) Need Help??

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

Greetings all,

I'm trying to code up something for which I want to have the ability to have optional and possibly unknown modules loaded at runtime. For instance, if I have a module TopLevel, I want it to know that there's a module called TopLevel::Foo without specifying that there's a possibility of that existing when I code the TopLevel module. Is there a clean way to do this?

Thanks in advance,

The only easy day was yesterday

Replies are listed 'Best First'.
Re: Plugin-type architecture
by john_oshea (Priest) on Jan 10, 2006 at 17:34 UTC
Re: Plugin-type architecture
by TedYoung (Deacon) on Jan 10, 2006 at 17:37 UTC

    Well, there are many ways you can go with this, so I will give you some ideas that you can combine to meet your own needs.

    It is probably a good idea to design an interface that all of your plugins must implement. That way, when you do discover what plugins are installed, you can instantiate and work with them.

    You will probably identify a plugin directory. You can easily get a list of .pm files in the directory:

    my @plugins = <plugins/*.pm>;

    or even use File::Find to recursivly search.

    When you have a file you can work with it as such:

    for (@plugins) { require $_; # Basically "use"-ing the file s/\//::/g; # Convert the path name into a package name s/\.pm$//; push @pluginInstances, $_->new; # Create a new instance }

    So, using file listing features, require (or do or eval), you can list and load your plugins. How you track your plugins within the app and how your plugins integrate will be entirely up to your needs.

    Ted Young

    ($$<<$$=>$$<=>$$<=$$>>$$) always returns 1. :-)
      You could also simply let the user specify which plugins they want at compile or run time, instead of loading them all at once. For instance, you could have your caller's say
      use YourModule qw( List Of Plugins );
      Then in YourModule have an import like this:
      use File::Spec; sub import { my $class = shift; foreach my $plugin ( @_ ) { my $fullname = File::Spec::catfile( $class, 'Plugin', "$" ); require $fullname; } }
      This assumes that your plugins are really called YourModule::Plugin::Name and that they don't go deeper (so YourModule::Plugin::TopLevel::Name won't work). But you could change the way the name is formed to take care of that.


Re: Plugin-type architecture
by doom (Deacon) on Mar 26, 2007 at 11:28 UTC
    I like Module::Pluggable too, I just started using it, myself. What it does for you is pretty simple, though: given a location in perl module namespace, it returns a list of all perl modules under that location.

    What you do with that list is up to you though. In my first application, I wanted a set of pluggable storage backend modules, so the client code tries to require a "My::Stuff::Storage::YAML" or "My::Stuff::Storage::DBI", and the list from Module::Pluggable is helpful in checking for existence first... but on the other hand you can also just do an "eval require $module" and trap the error if it fails.

    In my second application, I wanted to have an object with an extensible set of methods, where the client code specifies a method, and probably doesn't care which of a set of modules the method came from. For this application, I'm strongly considering just taking the list of plugin modules and pushing them into @ISA: yes, the dreaded "multiple inheritence".

    The one big problem I can see with doing this is that later, if you need to modify some existing method, there doesn't seem to be any effective way of subclassing one of the plugins. If you create a My::Stuff::Plugin::Glue with a method "squirt" and then add a My::Stuff::Plugin::Glue::Super that inherits from it and also has a method "squirt", the plugin system might see one or the other definition of "squirt" depending on how the plugin list is sorted.

    I've considered various solutions to this, but none strike me as terribly good ones. One point to consider is that it's important for the *client code* to be in control over which plugin module takes precedence: it would be very bad if existing code were broken without notice because someone added a new plugin module that solved their own immediate problem but is no good for the existing applications.

    So I don't know about this one: maybe it's not even very helpful to think of this as a "plugin" system. Really I'm trying to handroll some half-baked system of inheritence where the client code doesn't have to specify a dependency and yet is in control of it's dependencies.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://522248]
Approved by Old_Gray_Bear
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (3)
As of 2020-07-06 03:24 GMT
Find Nodes?
    Voting Booth?

    No recent polls found