Writing Extensible Systems with Pluggable Modules in Perl
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
- 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')"