File Coverage

blib/lib/Module/Recursive/Require.pm
Criterion Covered Total %
statement 89 92 96.7
branch 15 20 75.0
condition 4 11 36.3
subroutine 18 19 94.7
pod 5 5 100.0
total 131 147 89.1


line stmt bran cond sub pod time code
1             package Module::Recursive::Require;
2              
3 2     2   47238 use strict;
  2         5  
  2         76  
4 2     2   11 use warnings;
  2         4  
  2         57  
5 2     2   10 use Carp;
  2         7  
  2         185  
6 2     2   11 use File::Spec;
  2         4  
  2         58  
7 2     2   10 use File::Find;
  2         2  
  2         142  
8 2     2   10 use File::Basename;
  2         5  
  2         221  
9 2     2   2152 use UNIVERSAL::require;
  2         3523  
  2         21  
10 2     2   65 use vars qw/$VERSION/;
  2         3  
  2         1804  
11              
12             $VERSION = '0.04';
13              
14             sub new {
15 3     3 1 11939 my $proto = shift;
16 3   33     25 my $class = ref $proto || $proto;
17 3         5 my $args_ref = shift;
18            
19             # * Default path by $INC[0]
20 3   33     16 my $path
21             = $args_ref->{path} || $INC[0];
22              
23             # * Default extentions by .pm and .pl
24 3   50     22 my $extensions
25             = $args_ref->{extensions} || [qw/pm pl/];
26              
27 3         55 my $self
28             = {
29             _path => File::Spec->catfile( $path ),
30             _filters => [],
31             _extensions => $extensions,
32             _packages => undef,
33             _first_loads => [],
34             };
35              
36 3         15 return bless( $self, $class );
37             }
38              
39             sub first_loads {
40 1     1 1 8 my $self = shift;
41 1         3 my @modules = @_;
42              
43 1         4 $self->{_first_loads} = \@modules;
44              
45 1         5 return 1;
46             }
47              
48             sub add_filter {
49 2     2 1 12 my $self = shift;
50 2         7 my $filter = shift;
51              
52 2         4 push @{ $self->{_filters} }, $filter;
  2         9  
53              
54 2         13 return 1;
55             }
56              
57             # * deprecated!!
58             sub require_by {
59 0     0 1 0 my $self = shift;
60 0         0 my $package_name = shift;
61              
62 0         0 return $self->require_of( $package_name );
63             }
64              
65             sub require_of {
66 2     2 1 5 my $self = shift;
67 2   33     9 my $package_name = shift || croak "require package name!";
68              
69 2 50       7 my $modules
70             = $self->_get_modules( $package_name ) or return 0;
71              
72 1         4 unshift( @$modules, @{ $self->{_first_loads} })
  2         12  
73 2 100       4 if scalar @{ $self->{_first_loads} };
74              
75 2         4 my $_required = {};
76 2         4 my @required_modules = ();
77             REQUIRED:
78 2         4 for my $module ( @$modules ) {
79 9 100       22 next REQUIRED if exists $_required->{$module};
80            
81 8 50       66 $module->require() or croak $@;
82 8         1267 $_required->{$module} = 1;
83 8         19 push @required_modules, $module;
84             }
85              
86 2 50       15 return ( wantarray ) ? @required_modules : \@required_modules;
87             }
88              
89             sub _get_modules {
90 2     2   4 my $self = shift;
91 2         4 my $package_name = shift;
92              
93 2         33 my $path
94             = File::Spec->catfile(
95             $self->{_path},
96             split( '::', $package_name ),
97             );
98              
99 2         10 find( $self->_make_filter_sub_ref(), $path);
100              
101 2         22 return $self->{_packages};
102             }
103              
104             sub _make_filter_sub_ref {
105 2     2   4 my $self = shift;
106            
107 2         5 my $filters = $self->{_filters};
108 2         7 my $extensions
109             = $self->_scalar2array_ref( $self->{_extensions} );
110              
111             return sub {
112 14     14   23 my $fullname = $File::Find::name;
113 14         16 my $filename = $_;
114              
115 14 100       31 return 0
116             unless ( $self->_has_exts_by($fullname, $extensions) );
117              
118 10         19 for my $filter ( @$filters ) {
119 10 100       672 return 0 if $filename =~ /$filter/;
120             }
121              
122             # * path to package name
123             # ** UNIX OS only.. orz
124 8         84 my $package_name
125             = $self->_get_package_name(
126             {
127             fullname => $fullname,
128             libpath => $self->{_path}
129             }
130             );
131              
132 8         19 push @{ $self->{_packages} }, $package_name;
  8         16  
133              
134 8         163 return 1;
135             }
136 2         274 }
137              
138             sub _get_package_name {
139 8     8   13 my $self = shift;
140 8         9 my $arg_ref = shift;
141              
142 8         13 my $fullname = $arg_ref->{fullname};
143 8         9 my $libpath = $arg_ref->{libpath};
144              
145 8         8 my $package_name = undef;
146 8 50       60 if ( $fullname =~ m|^$libpath/(.+)\..+$| ) {
147 8         15 $package_name = $1;
148 8         24 $package_name =~ s/\//::/g;
149             }
150              
151 8         24 return $package_name;
152             }
153              
154             sub _has_exts_by {
155 14     14   16 my $self = shift;
156 14         15 my $fullpath = shift;
157 14         39 my $extensions = shift;
158            
159 14         646 my ($name, $path, $ext)
160             = fileparse( $fullpath, @$extensions );
161              
162 14 100       402 return ( $ext ) ? 1 : 0;
163             }
164              
165             sub _scalar2array_ref {
166 2     2   5 my $self = shift;
167 2         4 my $val = shift;
168              
169 2 50       9 return ( ref $val eq 'ARRAY' ) ? $val : [($val)];
170             }
171              
172              
173             1;
174              
175             =head1 NAME
176              
177             Module::Recursive::Require - This class require module recursively.
178              
179             =head1 DESCRIPTION
180              
181             # ************************************** before
182             use MyApp::Foo;
183             use MyApp::Foo::CGI;
184             use MyApp::Foo::Mail;
185             use MyApp::Foo::Mail::Send;
186            
187             # use use use use use !!
188            
189             use MyApp::Foo::Hoge::Orz;
190              
191             # ************************************** after
192             use Module::Recursive::Require;
193             use MyApp::Foo;
194              
195             my @required_packages
196             = Module::Recursive::Require->new()->require_by('MyApp::Foo');
197              
198             =head1 SYNOPSIS
199              
200             use Module::Recursive::Require;
201            
202             my $r = Module::Recursive::Require->new();
203             $r->first_loads(
204             qw/
205             MyApp::Foo::Boo
206             /
207             ); # * It loads first.
208             $r->add_filter(qr/^Hoge/); # * Don't loaded qr/^Hoge/
209             $r->add_filter(qr/Base.pm$/); # * Don't loaded qr/Base.pm$/
210            
211             my @packages = $r->require_of('MyApp::Foo');
212              
213             # * or
214              
215             my $packages_array_ref
216             = $r->require_of('MyApp::Foo');
217              
218             =head1 METHOD
219              
220             =head2 new( \%args )
221              
222             %args = (
223             path => '/var/www/my/lib', # * default $INC[0]
224             extensions => 'pm' , # * default "pm" and "pl"
225             );
226              
227             =head2 first_loads( @package_names );
228              
229             =head2 add_filter(qr/regexp/)
230              
231             =head2 require_of( 'MyApp::Foo' );
232              
233             =head2 require_by( 'MyApp::Foo' );
234              
235             Deprecated. For backwards compatibility only.
236              
237             =head1 SEE ALSO
238              
239             L
240              
241             =head1 AUTHOR
242              
243             Masahiro Funakoshi
244              
245             =cut