File Coverage

blib/lib/Module/Pluggable.pm
Criterion Covered Total %
statement 49 56 87.5
branch 3 12 25.0
condition 4 8 50.0
subroutine 10 11 90.9
pod n/a
total 66 87 75.8


line stmt bran cond sub pod time code
1             package Module::Pluggable;
2              
3 39     39   778210 use strict;
  39         77  
  39         1312  
4 39     39   172 use vars qw($VERSION $FORCE_SEARCH_ALL_PATHS);
  39         58  
  39         2224  
5 39     39   17312 use Module::Pluggable::Object;
  39         98  
  39         1805  
6              
7 39     39   271 use if $] > 5.017, 'deprecate';
  39         56  
  39         258  
8              
9             # ObQuote:
10             # Bob Porter: Looks like you've been missing a lot of work lately.
11             # Peter Gibbons: I wouldn't say I've been missing it, Bob!
12              
13              
14             $VERSION = '5.2';
15             $FORCE_SEARCH_ALL_PATHS = 0;
16              
17             sub import {
18 49     49   712 my $class = shift;
19 49         157 my %opts = @_;
20              
21 49         135 my ($pkg, $file) = caller;
22             # the default name for the method is 'plugins'
23 49   100     334 my $sub = $opts{'sub_name'} || 'plugins';
24             # get our package
25 49   66     281 my ($package) = $opts{'package'} || $pkg;
26 49         83 $opts{filename} = $file;
27 49         76 $opts{package} = $package;
28 49 50       220 $opts{force_search_all_paths} = $FORCE_SEARCH_ALL_PATHS unless exists $opts{force_search_all_paths};
29              
30              
31 49         278 my $finder = Module::Pluggable::Object->new(%opts);
32 49     70   193 my $subroutine = sub { my $self = shift; return $finder->plugins(@_) };
  70         22568  
  70         376  
33              
34             my $searchsub = sub {
35 0     0   0 my $self = shift;
36 0         0 my ($action,@paths) = @_;
37              
38 0 0 0     0 $finder->{'search_path'} = ["${package}::Plugin"] if ($action eq 'add' and not $finder->{'search_path'} );
39 0 0       0 push @{$finder->{'search_path'}}, @paths if ($action eq 'add');
  0         0  
40 0 0       0 $finder->{'search_path'} = \@paths if ($action eq 'new');
41 0         0 return $finder->{'search_path'};
42 49         304 };
43              
44              
45             my $onlysub = sub {
46 3     3   1410 my ($self, $only) = @_;
47              
48 3 50       11 if (defined $only) {
49 3         8 $finder->{'only'} = $only;
50             };
51              
52 3         6 return $finder->{'only'};
53 49         124 };
54              
55             my $exceptsub = sub {
56 3     3   1592 my ($self, $except) = @_;
57              
58 3 50       13 if (defined $except) {
59 3         10 $finder->{'except'} = $except;
60             };
61              
62 3         8 return $finder->{'except'};
63 49         115 };
64              
65              
66 39     39   17210 no strict 'refs';
  39         68  
  39         1697  
67 39     39   179 no warnings qw(redefine prototype);
  39         94  
  39         7607  
68              
69 49         63 *{"$package\::$sub"} = $subroutine;
  49         282  
70 49         65 *{"$package\::search_path"} = $searchsub;
  49         657  
71 49         64 *{"$package\::only"} = $onlysub;
  49         166  
72 49         64 *{"$package\::except"} = $exceptsub;
  49         46864  
73              
74             }
75              
76             1;
77              
78             =pod
79              
80             =head1 NAME
81              
82             Module::Pluggable - automatically give your module the ability to have plugins
83              
84             =head1 SYNOPSIS
85              
86              
87             Simple use Module::Pluggable -
88              
89             package MyClass;
90             use Module::Pluggable;
91              
92              
93             and then later ...
94              
95             use MyClass;
96             my $mc = MyClass->new();
97             # returns the names of all plugins installed under MyClass::Plugin::*
98             my @plugins = $mc->plugins();
99              
100             =head1 EXAMPLE
101              
102             Why would you want to do this? Say you have something that wants to pass an
103             object to a number of different plugins in turn. For example you may
104             want to extract meta-data from every email you get sent and do something
105             with it. Plugins make sense here because then you can keep adding new
106             meta data parsers and all the logic and docs for each one will be
107             self contained and new handlers are easy to add without changing the
108             core code. For that, you might do something like ...
109              
110             package Email::Examiner;
111              
112             use strict;
113             use Email::Simple;
114             use Module::Pluggable require => 1;
115              
116             sub handle_email {
117             my $self = shift;
118             my $email = shift;
119              
120             foreach my $plugin ($self->plugins) {
121             $plugin->examine($email);
122             }
123              
124             return 1;
125             }
126              
127              
128              
129             .. and all the plugins will get a chance in turn to look at it.
130              
131             This can be trivially extended so that plugins could save the email
132             somewhere and then no other plugin should try and do that.
133             Simply have it so that the C method returns C<1> if
134             it has saved the email somewhere. You might also want to be paranoid
135             and check to see if the plugin has an C method.
136              
137             foreach my $plugin ($self->plugins) {
138             next unless $plugin->can('examine');
139             last if $plugin->examine($email);
140             }
141              
142              
143             And so on. The sky's the limit.
144              
145              
146             =head1 DESCRIPTION
147              
148             Provides a simple but, hopefully, extensible way of having 'plugins' for
149             your module. Obviously this isn't going to be the be all and end all of
150             solutions but it works for me.
151              
152             Essentially all it does is export a method into your namespace that
153             looks through a search path for .pm files and turn those into class names.
154              
155             Optionally it instantiates those classes for you.
156              
157             =head1 ADVANCED USAGE
158              
159             Alternatively, if you don't want to use 'plugins' as the method ...
160              
161             package MyClass;
162             use Module::Pluggable sub_name => 'foo';
163              
164              
165             and then later ...
166              
167             my @plugins = $mc->foo();
168              
169              
170             Or if you want to look in another namespace
171              
172             package MyClass;
173             use Module::Pluggable search_path => ['Acme::MyClass::Plugin', 'MyClass::Extend'];
174              
175             or directory
176              
177             use Module::Pluggable search_dirs => ['mylibs/Foo'];
178              
179              
180             Or if you want to instantiate each plugin rather than just return the name
181              
182             package MyClass;
183             use Module::Pluggable instantiate => 'new';
184              
185             and then
186              
187             # whatever is passed to 'plugins' will be passed
188             # to 'new' for each plugin
189             my @plugins = $mc->plugins(@options);
190              
191              
192             alternatively you can just require the module without instantiating it
193              
194             package MyClass;
195             use Module::Pluggable require => 1;
196              
197             since requiring automatically searches inner packages, which may not be desirable, you can turn this off
198              
199              
200             package MyClass;
201             use Module::Pluggable require => 1, inner => 0;
202              
203              
204             You can limit the plugins loaded using the except option, either as a string,
205             array ref or regex
206              
207             package MyClass;
208             use Module::Pluggable except => 'MyClass::Plugin::Foo';
209              
210             or
211              
212             package MyClass;
213             use Module::Pluggable except => ['MyClass::Plugin::Foo', 'MyClass::Plugin::Bar'];
214              
215             or
216              
217             package MyClass;
218             use Module::Pluggable except => qr/^MyClass::Plugin::(Foo|Bar)$/;
219              
220              
221             and similarly for only which will only load plugins which match.
222              
223             Remember you can use the module more than once
224              
225             package MyClass;
226             use Module::Pluggable search_path => 'MyClass::Filters' sub_name => 'filters';
227             use Module::Pluggable search_path => 'MyClass::Plugins' sub_name => 'plugins';
228              
229             and then later ...
230              
231             my @filters = $self->filters;
232             my @plugins = $self->plugins;
233              
234             =head1 PLUGIN SEARCHING
235              
236             Every time you call 'plugins' the whole search path is walked again. This allows
237             for dynamically loading plugins even at run time. However this can get expensive
238             and so if you don't expect to want to add new plugins at run time you could do
239              
240              
241             package Foo;
242             use strict;
243             use Module::Pluggable sub_name => '_plugins';
244              
245             our @PLUGINS;
246             sub plugins { @PLUGINS ||= shift->_plugins }
247             1;
248              
249             =head1 INNER PACKAGES
250              
251             If you have, for example, a file B that
252             contains package definitions for both C and
253             C then as long as you either have either
254             the B or B option set then we'll also find
255             C. Nifty!
256              
257             =head1 OPTIONS
258              
259             You can pass a hash of options when importing this module.
260              
261             The options can be ...
262              
263             =head2 sub_name
264              
265             The name of the subroutine to create in your namespace.
266              
267             By default this is 'plugins'
268              
269             =head2 search_path
270              
271             An array ref of namespaces to look in.
272              
273             =head2 search_dirs
274              
275             An array ref of directories to look in before @INC.
276              
277             =head2 instantiate
278              
279             Call this method on the class. In general this will probably be 'new'
280             but it can be whatever you want. Whatever arguments are passed to 'plugins'
281             will be passed to the method.
282              
283             The default is 'undef' i.e just return the class name.
284              
285             =head2 require
286              
287             Just require the class, don't instantiate (overrides 'instantiate');
288              
289             =head2 inner
290              
291             If set to 0 will B search inner packages.
292             If set to 1 will override C.
293              
294             =head2 only
295              
296             Takes a string, array ref or regex describing the names of the only plugins to
297             return. Whilst this may seem perverse ... well, it is. But it also
298             makes sense. Trust me.
299              
300             =head2 except
301              
302             Similar to C it takes a description of plugins to exclude
303             from returning. This is slightly less perverse.
304              
305             =head2 package
306              
307             This is for use by extension modules which build on C:
308             passing a C option allows you to place the plugin method in a
309             different package other than your own.
310              
311             =head2 file_regex
312              
313             By default C only looks for I<.pm> files.
314              
315             By supplying a new C then you can change this behaviour e.g
316              
317             file_regex => qr/\.plugin$/
318              
319             =head2 include_editor_junk
320              
321             By default C ignores files that look like they were
322             left behind by editors. Currently this means files ending in F<~> (~),
323             the extensions F<.swp> or F<.swo>, or files beginning with F<.#>.
324              
325             Setting C changes C so it does
326             not ignore any files it finds.
327              
328             =head2 follow_symlinks
329              
330             Whether, when searching directories, to follow symlinks.
331              
332             Defaults to 1 i.e do follow symlinks.
333              
334             =head2 min_depth, max_depth
335              
336             This will allow you to set what 'depth' of plugin will be allowed.
337              
338             So, for example, C will have a depth of 3 and
339             C will have a depth of 4 so to only get the former
340             (i.e C) do
341              
342             package MyClass;
343             use Module::Pluggable max_depth => 3;
344              
345             and to only get the latter (i.e C)
346              
347             package MyClass;
348             use Module::Pluggable min_depth => 4;
349              
350              
351             =head1 TRIGGERS
352              
353             Various triggers can also be passed in to the options.
354              
355             If any of these triggers return 0 then the plugin will not be returned.
356              
357             =head2 before_require
358              
359             Gets passed the plugin name.
360              
361             If 0 is returned then this plugin will not be required either.
362              
363             =head2 on_require_error
364              
365             Gets called when there's an error on requiring the plugin.
366              
367             Gets passed the plugin name and the error.
368              
369             The default on_require_error handler is to C the error and return 0.
370              
371             =head2 on_instantiate_error
372              
373             Gets called when there's an error on instantiating the plugin.
374              
375             Gets passed the plugin name and the error.
376              
377             The default on_instantiate_error handler is to C the error and return 0.
378              
379             =head2 after_require
380              
381             Gets passed the plugin name.
382              
383             If 0 is returned then this plugin will be required but not returned as a plugin.
384              
385             =head1 METHODs
386              
387             =head2 search_path
388              
389             The method C is exported into you namespace as well.
390             You can call that at any time to change or replace the
391             search_path.
392              
393             $self->search_path( add => "New::Path" ); # add
394             $self->search_path( new => "New::Path" ); # replace
395              
396             =head1 BEHAVIOUR UNDER TEST ENVIRONMENT
397              
398             In order to make testing reliable we exclude anything not from blib if blib.pm is
399             in %INC.
400              
401             However if the module being tested used another module that itself used C
402             then the second module would fail. This was fixed by checking to see if the caller
403             had (^|/)blib/ in their filename.
404              
405             There's an argument that this is the wrong behaviour and that modules should explicitly
406             trigger this behaviour but that particular code has been around for 7 years now and I'm
407             reluctant to change the default behaviour.
408              
409             You can now (as of version 4.1) force Module::Pluggable to look outside blib in a test environment by doing either
410              
411             require Module::Pluggable;
412             $Module::Pluggable::FORCE_SEARCH_ALL_PATHS = 1;
413             import Module::Pluggable;
414              
415             or
416              
417             use Module::Pluggable force_search_all_paths => 1;
418              
419             =head1 @INC hooks and App::FatPacker
420              
421             If a module's @INC has a hook and that hook is an object which has a C method then we will
422             try and require those files too. See C for an example.
423              
424             This has allowed L (as of version 0.10.0) to provide support for Module::Pluggable.
425              
426             This should also, theoretically, allow someone to modify PAR to do the same thing.
427              
428             =head1 Module::Require recommended
429              
430             Up until version 5.2 L used a string C to require plugins.
431              
432             This has now been changed to optionally use L and it's C method when
433             available and fall back to using a path based C when not.
434              
435             It's recommended, but not required, that you install Module::Runtime.
436              
437             =head1 FUTURE PLANS
438              
439             This does everything I need and I can't really think of any other
440             features I want to add. Famous last words of course (not least
441             because we're up to version 5.0 at the time of writing).
442              
443             However suggestions (and patches) are always welcome.
444              
445             =head1 DEVELOPMENT
446              
447             The master repo for this module is at
448              
449             https://github.com/simonwistow/Module-Pluggable
450              
451             =head1 AUTHOR
452              
453             Simon Wistow
454              
455             =head1 COPYING
456              
457             Copyright, 2006 Simon Wistow
458              
459             Distributed under the same terms as Perl itself.
460              
461             =head1 BUGS
462              
463             None known.
464              
465             =head1 SEE ALSO
466              
467             L, L, L, L, L
468              
469             =cut
470              
471