package MyClass; use Module::Pluggable;
and then later ...
use MyClass; my $mc = MyClass->new(); # returns the names of all plugins installed under MyClass::Plugin::* my @plugins = $mc->plugins();
package Email::Examiner; use strict; use Email::Simple; use Module::Pluggable require => 1; sub handle_email { my $self = shift; my $email = shift; foreach my $plugin ($self->plugins) { $plugin->examine($email); } return 1; }
.. and all the plugins will get a chance in turn to look at it.
This can be trivially extended so that plugins could save the email somewhere and then no other plugin should try and do that. Simply have it so that the "examine" method returns 1 if it has saved the email somewhere. You might also want to be paranoid and check to see if the plugin has an "examine" method.
foreach my $plugin ($self->plugins) { next unless $plugin->can('examine'); last if $plugin->examine($email); }
And so on. The sky's the limit.
Essentially all it does is export a method into your namespace that looks through a search path for .pm files and turn those into class names.
Optionally it instantiates those classes for you.
package MyClass; use Module::Pluggable sub_name => 'foo';
and then later ...
my @plugins = $mc->foo();
Or if you want to look in another namespace
package MyClass; use Module::Pluggable search_path => ['Acme::MyClass::Plugin', 'MyClass::Extend'];
or directory
use Module::Pluggable search_dirs => ['mylibs/Foo'];
Or if you want to instantiate each plugin rather than just return the name
package MyClass; use Module::Pluggable instantiate => 'new';
and then
# whatever is passed to 'plugins' will be passed # to 'new' for each plugin my @plugins = $mc->plugins(@options);
alternatively you can just require the module without instantiating it
package MyClass; use Module::Pluggable require => 1;
since requiring automatically searches inner packages, which may not be desirable, you can turn this off
package MyClass; use Module::Pluggable require => 1, inner => 0;
You can limit the plugins loaded using the except option, either as a string, array ref or regex
package MyClass; use Module::Pluggable except => 'MyClass::Plugin::Foo';
or
package MyClass; use Module::Pluggable except => ['MyClass::Plugin::Foo', 'MyClass::Plugin::Bar'];
or
package MyClass; use Module::Pluggable except => qr/^MyClass::Plugin::(Foo|Bar)$/;
and similarly for only which will only load plugins which match.
Remember you can use the module more than once
package MyClass; use Module::Pluggable search_path => 'MyClass::Filters' sub_name => 'filters'; use Module::Pluggable search_path => 'MyClass::Plugins' sub_name => 'plugins';
and then later ...
my @filters = $self->filters; my @plugins = $self->plugins;
package Foo; use strict; use Module::Pluggable sub_name => '_plugins'; our @PLUGINS; sub plugins { @PLUGINS ||= shift->_plugins } 1;
The default is 'undef' i.e just return the class name.
By supplying a new "file_regex" then you can change this behaviour e.g
file_regex => qr/\.plugin$/
Setting "include_editor_junk" changes "Module::Pluggable" so it does not ignore any files it finds.
Defaults to 1 i.e do follow symlinks.
So, for example, "MyClass::Plugin::Foo" will have a depth of 3 and "MyClass::Plugin::Foo::Bar" will have a depth of 4 so to only get the former (i.e "MyClass::Plugin::Foo") do
package MyClass; use Module::Pluggable max_depth => 3;
and to only get the latter (i.e "MyClass::Plugin::Foo::Bar")
package MyClass; use Module::Pluggable min_depth => 4;
If any of these triggers return 0 then the plugin will not be returned.
If 0 is returned then this plugin will not be required either.
Gets passed the plugin name and the error.
The default on_require_error handler is to "carp" the error and return 0.
Gets passed the plugin name and the error.
The default on_instantiate_error handler is to "carp" the error and return 0.
If 0 is returned then this plugin will be required but not returned as a plugin.
$self->search_path( add => "New::Path" ); # add $self->search_path( new => "New::Path" ); # replace
However if the module being tested used another module that itself used "Module::Pluggable" then the second module would fail. This was fixed by checking to see if the caller had (^|/)blib/ in their filename.
There's an argument that this is the wrong behaviour and that modules should explicitly trigger this behaviour but that particular code has been around for 7 years now and I'm reluctant to change the default behaviour.
You can now (as of version 4.1) force Module::Pluggable to look outside blib in a test environment by doing either
require Module::Pluggable; $Module::Pluggable::FORCE_SEARCH_ALL_PATHS = 1; import Module::Pluggable;
or
use Module::Pluggable force_search_all_paths => 1;
This has allowed App::FatPacker (as of version 0.10.0) to provide support for Module::Pluggable.
This should also, theoretically, allow someone to modify PAR to do the same thing.
This has now been changed to optionally use Module::Runtime and it's "require_module" method when available and fall back to using a path based "require" when not.
It's recommended, but not required, that you install Module::Runtime.
However suggestions (and patches) are always welcome.
https://github.com/simonwistow/Module-Pluggable
Distributed under the same terms as Perl itself.