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 trivally 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 wnat 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;
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.
$self->search_path( add => "New::Path" ); # add
$self->search_path( new => "New::Path" ); # replace
Recently tried fixed to find inner packages and to make it 'just work' with PAR but there are still some issues.
However suggestions (and patches) are welcome.
Distributed under the same terms as Perl itself.