Creating Module::Loader

reviewsplugins Sun 5 October 2014

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.

Update

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