After writing my review of modules that can load other modules, I ended up using Mojo::Loader a number of times. Not everyone is keen to require the installation of Mojolicious just to use one module, and the Mojolicious project didn't want to spin out Mojo::Loader (fair enough), so I've created Module::Loader.
It's a simple class that can be used to find all modules in a given namespace, and also to load them. It's very similar to Mojo::Loader, but with a couple of differences. As of 0.02 I've made it drop-in compatible with Mojo::Loader.
To find all locally-installed plugins for the Template toolkit:
use Module::Loader;
my $loader = Module::Loader->new;
my @plugins = $loader->find_modules('Template::Plugin');
The find_modules
method scans all directories in @INC
,
and returns a list of all modules found in the given namespace.
By default it will return all modules found, but you can use the
max_depth
attribute to limit it, typically to one:
my $loader = Module::Loader->new(max_depth => 1);
my @plugins = $loader->find_modules('Template::Plugin');
The above is equivalent to the search()
method of Mojo::Loader —
it only returns modules at a depth of one.
For full compatibility with Mojo::Loader
I've added a search()
method, which has the same behaviour:
my @plugins = $loader->search('Template::Plugin');
This sets max_depth
to 1 before searching for modules, then restores
whatever value it had before.
Having found some modules, you can then load one or more of them:
foreach my $plugin (@plugins) {
$loader->load($plugin);
}
This just uses the require_module()
function from Module::Runtime.
I was tempted to lift the relevant code, to save a dependency,
but so far have resisted that temptation.
I've also used Moo, which almost felt like overkill for such a simple class, with just one attribute. It's quite a small module, but the reason I was able to whip it up so quickly, and feel confident in it, is that it builds on Moo, Path::Iterator::Rule, File::Spec::Functions, and Module::Runtime.
If you're looking for a plugin loader, there are a number of modules
you can consider. I've listed all those I'm currently aware of in
the SEE ALSO
section of the doc. If you've written a class Foo::Bar
, and want
to load plugins from the namespace Foo::Bar::Plugin
,
then Module::Pluggable is probably the first place you should look.
When I started thinking about this module, I wasn't sure whether to
call it Plugin::Loader
or Module::Loader
. The latter was taken,
so I initially went with Plugin::Loader
, but in writing the doc
and this blog post, I realised that Module::Loader
was a more
appropriate name. Thanks to BRADH for letting me take over the name.
Following comments and further thought, I've dropped Moo and have
changed max_depth
to be an attribute you can specify at construction time,
and a parameter to find_modules
:
$loader = Module::Loader->new();
@plugins = $loader->find_modules('Template::Plugin',
{ max_depth => 1 });
I considered dropping Module::Runtime, but another look at its code convinced me not to.
comments powered by Disqus