File Coverage

blib/lib/Module/Loader.pm
Criterion Covered Total %
statement 46 46 100.0
branch 10 10 100.0
condition 2 2 100.0
subroutine 11 11 100.0
pod 5 5 100.0
total 74 74 100.0


line stmt bran cond sub pod time code
1             package Module::Loader;
2             $Module::Loader::VERSION = '0.03';
3 5     5   70227 use 5.006;
  5         11  
  5         157  
4 5     5   18 use strict;
  5         6  
  5         119  
5 5     5   23 use warnings;
  5         7  
  5         117  
6 5     5   2910 use Path::Iterator::Rule;
  5         52810  
  5         165  
7 5     5   946 use File::Spec::Functions qw/ catfile splitdir /;
  5         1170  
  5         306  
8 5     5   27 use Carp qw/ croak /;
  5         8  
  5         1990  
9              
10             sub new
11             {
12 5     5 1 52 my ($class, %attributes) = @_;
13              
14 5         25 bless {%attributes}, $class;
15             }
16              
17             sub max_depth
18             {
19 4     4 1 975 my $self = shift;
20              
21 4 100       157 croak 'max_depth is immutable' if @_ > 0;
22 3 100       15 return $self->{max_depth} if exists($self->{max_depth});
23 1         6 return;
24             }
25              
26             sub find_modules
27             {
28 6     6 1 3457 my $self = shift;
29 6         8 my $base = shift;
30 6 100       19 my $argref = @_ > 0 ? shift : {};
31 6   100     32 my $max_depth = $argref->{max_depth} || $self->{max_depth} || 0;
32 6         22 my @baseparts = split(/::/, $base);
33 6         8 my %modules;
34              
35 6         10 foreach my $directory (@INC) {
36 72         183 my $path = catfile($directory, @baseparts);
37 72 100       734 next unless -d $path;
38              
39 6         38 my $rule = Path::Iterator::Rule->new->perl_module;
40 6 100       910 $rule->max_depth($max_depth) if $max_depth;
41              
42 6         82 foreach my $file ($rule->all($path)) {
43 15         5062 (my $modpath = $file) =~ s!^\Q$directory\E.|\.pm$!!g;
44              
45 15         34 my $module = join('::', splitdir($modpath));
46              
47             # Using a hash means that even if a module is installed
48             # in more than one place, it will only be reported once
49 15         235 $modules{ $module }++;
50             }
51             }
52              
53 6         33 return keys(%modules);
54             }
55              
56             sub search
57             {
58 2     2 1 750 my ($self, $base) = @_;
59              
60 2         10 return $self->find_modules($base, { max_depth => 1 });
61             }
62              
63             sub load
64             {
65 2     2 1 1017 my ($self, @modules) = @_;
66              
67 2         665 require Module::Runtime;
68 2         1391 foreach my $module (@modules) {
69 2         5 Module::Runtime::require_module($module);
70             }
71             }
72              
73             1;
74              
75             =encoding utf8
76              
77             =head1 NAME
78              
79             Module::Loader - finding and loading modules in a given namespace
80              
81             =head1 SYNOPSIS
82              
83             use Module::Loader;
84              
85             my $loader = Module::Loader->new;
86             my @plugins = $loader->find_modules('MyApp::Plugin');
87              
88             foreach my $plugin (@plugins) {
89             $loader->load($plugin);
90             }
91              
92             =head1 DESCRIPTION
93              
94             This module provides methods for finding modules in a given namespace,
95             and then loading them. It is intended for use in situations where
96             you're looking for plugins, and then loading one or more of them.
97              
98             This module was inspired by L, which I have used in
99             a number of projects. But some people were wary of requiring L
100             just to get a module loader, which prompted me to create C.
101              
102             Note: this module was initially called C, but I realised
103             that C was a more appropriate name.
104              
105             =head2 new
106              
107             When instantiating C, you can optionally set the
108             C attribute, which limits the search depth when looking for modules.
109              
110             my $loader = Module::Loader->new(max_depth => 1);
111              
112             Let's say you have all of the CPAN plugins for the template toolkit
113             installed locally. If you don't specify C, then C
114             would return L
115             as well as L. If you set C to 1,
116             then you'd get the latter but not the former.
117              
118             Why might you want to do that?
119              
120             You might have a convention where plugins are the modules immediately
121             within the specified namespace, but that each plugin can have additional
122             modules within its own namespace.
123              
124             So typically you'll either not set C, or you'll set it to 1.
125              
126             =head1 METHODS
127              
128             =head2 find_modules
129              
130             Takes a namespace, and returns all installed modules in that namespace,
131             that were found in C<@INC>. For example:
132              
133             @plugins = $loader->find_modules('Template::Plugin');
134              
135             By default this will find all modules in the given namespace,
136             unless you've specified a maximum search depth, as described above.
137             You can also specify C when you call the method:
138              
139             @plugins = $loader->find_modules('Template::Plugin',
140             { max_depth => 1 });
141              
142             =head2 search
143              
144             This is the same as C above,
145             but it hard-codes the search depth to 1.
146             This method is provided for compatibility with L:
147              
148             @plugins = $loader->search('Template::Plugin');
149              
150             It just calls C with C set to 1,
151             as shown above.
152              
153             =head2 load
154              
155             Takes a module name and tries to load the module.
156              
157             $loader->load('MyModule::Plugin::Spank');
158              
159             If loading fails, then we C.
160              
161             =head2 max_depth
162              
163             Returns the value of the C, if it was passed to the constructor,
164             otherwise C.
165              
166             =head1 SEE ALSO
167              
168             L was the inspiration for this module, but has
169             a slightly different interface. In particular, it has C
170             hard-coded to 1.
171              
172             L is effectively a role which gives a class the ability
173             to find plugins within its namespace.
174              
175             L is similar to L,
176             but lets you control the order in which modules are loaded.
177              
178             L will load all modules in a given namespace, eg with C
179              
180             L will load all modules found in a given I
181             (as opposed to a namespace).
182              
183             L provides functions for loading modules,
184             but not for finding them.
185              
186             L provides a number of functions for finding and loading
187             modules. It provides different functions depending on whether you want
188             to limit the search depth to 1 or not: C vs C.
189              
190             L will load all modules in a given namespace,
191             and return a list of the modules found / loaded.
192             It lets you provide regexps for filtering out certain namespaces.
193              
194             L provides two functions, C
195             and C which will load all locally installed modules
196             whose name matches a pattern (specified as a regular expression
197             or glob-style pattern).
198              
199             =head1 REPOSITORY
200              
201             L
202              
203             =head1 AUTHOR
204              
205             Neil Bowers Eneilb@cpan.orgE
206              
207             =head1 COPYRIGHT AND LICENSE
208              
209             This software is copyright (c) 2014 by Neil Bowers .
210              
211             This is free software; you can redistribute it and/or modify it under
212             the same terms as the Perl 5 programming language system itself.
213              
214             =cut
215