Writing Extensible Systems with Pluggable Modules in Perl

Tags:

Module::Pluggable is an under-appreciated way to write extensible programs. It has been in the Perl core modules since Perl 5.8. [1] The author maintains a Github repository.

use Module::Pluggable instantiate => function_name;

Instantiates an object for each pluggable module by calling the named function (method); often you will want to pass "new". Or you might just want to load (require) the modules, and not instantiate them:

use Module::Pluggable require => 1;

The return value to plugins() will then change from a list of the installed module names, to a list of all the objects created. Note that the change in return-value is undocumented. See also the option, on_instantiate_error which controls what happens when things go wrong.

Module::Pluggable does expect the following protocol:

use Module::Pluggable search_path => "Plugins", instantiate => 'new';

searches the subdirectory ./Plugins for files named *.pm (although you can change this with the file_regex parameter). For example, if you are writing a Mojolicious model that should have pluggable submodules, you could do this:

# in lib/MyApp/Model/MyGeneralModel.pm
use Module::Pluggable require => 1, search_path => __PACKAGE__;

which would load all files matching lib/MyApp/Model/MyGeneralModel/*.pm

Each file, for example Plugins/plug1.pm in the first example above, is expected to contain a co-ordinating definition properly placed in the object namespace hierarchy by matching the filename:

package Plugins::plug1;

sub new {
  my $class = shift;
  my $self = {};
  return bless \$self, $class;
}

sub some_handler {
  my $class = shift;
  …
}

In the main program or calling class, then, you might do something like:

# Save list of created plugin objects
my @plugs = plugins(optional => 'arguments');

…

my @values;
foreach my $p (@plugs) {
  push @values, $p->some_handler()
    if $p->can('some_handler');
}

Notes

  1. One quick way to determine this is to use the also built-in Module::CoreList function first_release() from the command line: perl -MModule::CoreList -e "print Module::CoreList->first_release('Module::Pluggable')"