Filename | /Users/timbo/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/File/ShareDir.pm |
Statements | Executed 43 statements in 1.66ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 1.82ms | 2.02ms | BEGIN@116 | File::ShareDir::
1 | 1 | 1 | 30µs | 62µs | _dist_dir_new | File::ShareDir::
1 | 1 | 1 | 16µs | 16µs | BEGIN@108 | File::ShareDir::
2 | 1 | 1 | 12µs | 12µs | CORE:ftdir (opcode) | File::ShareDir::
1 | 1 | 1 | 12µs | 12µs | BEGIN@119 | File::ShareDir::
1 | 1 | 1 | 10µs | 82µs | dist_dir | File::ShareDir::
1 | 1 | 1 | 10µs | 57µs | BEGIN@135 | File::ShareDir::
1 | 1 | 1 | 8µs | 18µs | BEGIN@445 | File::ShareDir::
1 | 1 | 1 | 8µs | 9µs | _DIST | File::ShareDir::
1 | 1 | 1 | 7µs | 11µs | BEGIN@110 | File::ShareDir::
1 | 1 | 1 | 7µs | 58µs | BEGIN@118 | File::ShareDir::
1 | 1 | 1 | 7µs | 18µs | BEGIN@109 | File::ShareDir::
1 | 1 | 1 | 4µs | 4µs | CORE:fteread (opcode) | File::ShareDir::
1 | 1 | 1 | 3µs | 3µs | BEGIN@112 | File::ShareDir::
1 | 1 | 1 | 3µs | 3µs | BEGIN@115 | File::ShareDir::
1 | 1 | 1 | 3µs | 3µs | BEGIN@113 | File::ShareDir::
1 | 1 | 1 | 3µs | 3µs | BEGIN@114 | File::ShareDir::
1 | 1 | 1 | 2µs | 2µs | CORE:match (opcode) | File::ShareDir::
0 | 0 | 0 | 0s | 0s | _CLASS | File::ShareDir::
0 | 0 | 0 | 0s | 0s | _FILE | File::ShareDir::
0 | 0 | 0 | 0s | 0s | _MODULE | File::ShareDir::
0 | 0 | 0 | 0s | 0s | _dist_dir_old | File::ShareDir::
0 | 0 | 0 | 0s | 0s | _dist_file_new | File::ShareDir::
0 | 0 | 0 | 0s | 0s | _dist_file_old | File::ShareDir::
0 | 0 | 0 | 0s | 0s | _dist_packfile | File::ShareDir::
0 | 0 | 0 | 0s | 0s | _module_dir_new | File::ShareDir::
0 | 0 | 0 | 0s | 0s | _module_dir_old | File::ShareDir::
0 | 0 | 0 | 0s | 0s | _module_subdir | File::ShareDir::
0 | 0 | 0 | 0s | 0s | class_file | File::ShareDir::
0 | 0 | 0 | 0s | 0s | dist_file | File::ShareDir::
0 | 0 | 0 | 0s | 0s | module_dir | File::ShareDir::
0 | 0 | 0 | 0s | 0s | module_file | File::ShareDir::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package File::ShareDir; | ||||
2 | |||||
3 | =pod | ||||
4 | |||||
5 | =head1 NAME | ||||
6 | |||||
7 | File::ShareDir - Locate per-dist and per-module shared files | ||||
8 | |||||
9 | =head1 SYNOPSIS | ||||
10 | |||||
11 | use File::ShareDir ':ALL'; | ||||
12 | |||||
13 | # Where are distribution-level shared data files kept | ||||
14 | $dir = dist_dir('File-ShareDir'); | ||||
15 | |||||
16 | # Where are module-level shared data files kept | ||||
17 | $dir = module_dir('File::ShareDir'); | ||||
18 | |||||
19 | # Find a specific file in our dist/module shared dir | ||||
20 | $file = dist_file( 'File-ShareDir', 'file/name.txt'); | ||||
21 | $file = module_file('File::ShareDir', 'file/name.txt'); | ||||
22 | |||||
23 | # Like module_file, but search up the inheritance tree | ||||
24 | $file = class_file( 'Foo::Bar', 'file/name.txt' ); | ||||
25 | |||||
26 | =head1 DESCRIPTION | ||||
27 | |||||
28 | The intent of L<File::ShareDir> is to provide a companion to | ||||
29 | L<Class::Inspector> and L<File::HomeDir>, modules that take a | ||||
30 | process that is well-known by advanced Perl developers but gets a | ||||
31 | little tricky, and make it more available to the larger Perl community. | ||||
32 | |||||
33 | Quite often you want or need your Perl module (CPAN or otherwise) | ||||
34 | to have access to a large amount of read-only data that is stored | ||||
35 | on the file-system at run-time. | ||||
36 | |||||
37 | On a linux-like system, this would be in a place such as /usr/share, | ||||
38 | however Perl runs on a wide variety of different systems, and so | ||||
39 | the use of any one location is unreliable. | ||||
40 | |||||
41 | Perl provides a little-known method for doing this, but almost | ||||
42 | nobody is aware that it exists. As a result, module authors often | ||||
43 | go through some very strange ways to make the data available to | ||||
44 | their code. | ||||
45 | |||||
46 | The most common of these is to dump the data out to an enormous | ||||
47 | Perl data structure and save it into the module itself. The | ||||
48 | result are enormous multi-megabyte .pm files that chew up a | ||||
49 | lot of memory needlessly. | ||||
50 | |||||
51 | Another method is to put the data "file" after the __DATA__ compiler | ||||
52 | tag and limit yourself to access as a filehandle. | ||||
53 | |||||
54 | The problem to solve is really quite simple. | ||||
55 | |||||
56 | 1. Write the data files to the system at install time. | ||||
57 | |||||
58 | 2. Know where you put them at run-time. | ||||
59 | |||||
60 | Perl's install system creates an "auto" directory for both | ||||
61 | every distribution and for every module file. | ||||
62 | |||||
63 | These are used by a couple of different auto-loading systems | ||||
64 | to store code fragments generated at install time, and various | ||||
65 | other modules written by the Perl "ancient masters". | ||||
66 | |||||
67 | But the same mechanism is available to any dist or module to | ||||
68 | store any sort of data. | ||||
69 | |||||
70 | =head2 Using Data in your Module | ||||
71 | |||||
72 | C<File::ShareDir> forms one half of a two part solution. | ||||
73 | |||||
74 | Once the files have been installed to the correct directory, | ||||
75 | you can use C<File::ShareDir> to find your files again after | ||||
76 | the installation. | ||||
77 | |||||
78 | For the installation half of the solution, see L<Module::Install> | ||||
79 | and its C<install_share> directive. | ||||
80 | |||||
81 | =head1 FUNCTIONS | ||||
82 | |||||
83 | C<File::ShareDir> provides four functions for locating files and | ||||
84 | directories. | ||||
85 | |||||
86 | For greater maintainability, none of these are exported by default | ||||
87 | and you are expected to name the ones you want at use-time, or provide | ||||
88 | the C<':ALL'> tag. All of the following are equivalent. | ||||
89 | |||||
90 | # Load but don't import, and then call directly | ||||
91 | use File::ShareDir; | ||||
92 | $dir = File::ShareDir::dist_dir('My-Dist'); | ||||
93 | |||||
94 | # Import a single function | ||||
95 | use File::ShareDir 'dist_dir'; | ||||
96 | dist_dir('My-Dist'); | ||||
97 | |||||
98 | # Import all the functions | ||||
99 | use File::ShareDir ':ALL'; | ||||
100 | dist_dir('My-Dist'); | ||||
101 | |||||
102 | All of the functions will check for you that the dir/file actually | ||||
103 | exists, and that you have read permissions, or they will throw an | ||||
104 | exception. | ||||
105 | |||||
106 | =cut | ||||
107 | |||||
108 | 2 | 38µs | 1 | 16µs | # spent 16µs within File::ShareDir::BEGIN@108 which was called:
# once (16µs+0s) by File::ShareDir::ProjectDistDir::BEGIN@237 at line 108 # spent 16µs making 1 call to File::ShareDir::BEGIN@108 |
109 | 2 | 22µs | 2 | 30µs | # spent 18µs (7+12) within File::ShareDir::BEGIN@109 which was called:
# once (7µs+12µs) by File::ShareDir::ProjectDistDir::BEGIN@237 at line 109 # spent 18µs making 1 call to File::ShareDir::BEGIN@109
# spent 12µs making 1 call to strict::import |
110 | 2 | 19µs | 2 | 15µs | # spent 11µs (7+4) within File::ShareDir::BEGIN@110 which was called:
# once (7µs+4µs) by File::ShareDir::ProjectDistDir::BEGIN@237 at line 110 # spent 11µs making 1 call to File::ShareDir::BEGIN@110
# spent 4µs making 1 call to warnings::import |
111 | |||||
112 | 2 | 16µs | 1 | 3µs | # spent 3µs within File::ShareDir::BEGIN@112 which was called:
# once (3µs+0s) by File::ShareDir::ProjectDistDir::BEGIN@237 at line 112 # spent 3µs making 1 call to File::ShareDir::BEGIN@112 |
113 | 2 | 19µs | 1 | 3µs | # spent 3µs within File::ShareDir::BEGIN@113 which was called:
# once (3µs+0s) by File::ShareDir::ProjectDistDir::BEGIN@237 at line 113 # spent 3µs making 1 call to File::ShareDir::BEGIN@113 |
114 | 2 | 15µs | 1 | 3µs | # spent 3µs within File::ShareDir::BEGIN@114 which was called:
# once (3µs+0s) by File::ShareDir::ProjectDistDir::BEGIN@237 at line 114 # spent 3µs making 1 call to File::ShareDir::BEGIN@114 |
115 | 2 | 17µs | 1 | 3µs | # spent 3µs within File::ShareDir::BEGIN@115 which was called:
# once (3µs+0s) by File::ShareDir::ProjectDistDir::BEGIN@237 at line 115 # spent 3µs making 1 call to File::ShareDir::BEGIN@115 |
116 | 2 | 103µs | 1 | 2.02ms | # spent 2.02ms (1.82+200µs) within File::ShareDir::BEGIN@116 which was called:
# once (1.82ms+200µs) by File::ShareDir::ProjectDistDir::BEGIN@237 at line 116 # spent 2.02ms making 1 call to File::ShareDir::BEGIN@116 |
117 | |||||
118 | 2 | 44µs | 2 | 109µs | # spent 58µs (7+51) within File::ShareDir::BEGIN@118 which was called:
# once (7µs+51µs) by File::ShareDir::ProjectDistDir::BEGIN@237 at line 118 # spent 58µs making 1 call to File::ShareDir::BEGIN@118
# spent 51µs making 1 call to vars::import |
119 | # spent 12µs within File::ShareDir::BEGIN@119 which was called:
# once (12µs+0s) by File::ShareDir::ProjectDistDir::BEGIN@237 at line 133 | ||||
120 | 1 | 400ns | $VERSION = '1.102'; | ||
121 | 1 | 5µs | @ISA = qw{ Exporter }; | ||
122 | 1 | 1µs | @EXPORT_OK = qw{ | ||
123 | dist_dir | ||||
124 | dist_file | ||||
125 | module_dir | ||||
126 | module_file | ||||
127 | class_dir | ||||
128 | class_file | ||||
129 | }; | ||||
130 | 1 | 6µs | %EXPORT_TAGS = ( | ||
131 | ALL => [ @EXPORT_OK ], | ||||
132 | ); | ||||
133 | 1 | 23µs | 1 | 12µs | } # spent 12µs making 1 call to File::ShareDir::BEGIN@119 |
134 | |||||
135 | 2 | 797µs | 2 | 104µs | # spent 57µs (10+47) within File::ShareDir::BEGIN@135 which was called:
# once (10µs+47µs) by File::ShareDir::ProjectDistDir::BEGIN@237 at line 135 # spent 57µs making 1 call to File::ShareDir::BEGIN@135
# spent 47µs making 1 call to constant::import |
136 | |||||
- - | |||||
141 | ##################################################################### | ||||
142 | # Interface Functions | ||||
143 | |||||
144 | =pod | ||||
145 | |||||
146 | =head2 dist_dir | ||||
147 | |||||
148 | # Get a distribution's shared files directory | ||||
149 | my $dir = dist_dir('My-Distribution'); | ||||
150 | |||||
151 | The C<dist_dir> function takes a single parameter of the name of an | ||||
152 | installed (CPAN or otherwise) distribution, and locates the shared | ||||
153 | data directory created at install time for it. | ||||
154 | |||||
155 | Returns the directory path as a string, or dies if it cannot be | ||||
156 | located or is not readable. | ||||
157 | |||||
158 | =cut | ||||
159 | |||||
160 | # spent 82µs (10+72) within File::ShareDir::dist_dir which was called:
# once (10µs+72µs) by File::ShareDir::ProjectDistDir::_get_cached_dist_dir_result at line 554 of File/ShareDir/ProjectDistDir.pm | ||||
161 | 1 | 2µs | 1 | 9µs | my $dist = _DIST(shift); # spent 9µs making 1 call to File::ShareDir::_DIST |
162 | 1 | 100ns | my $dir; | ||
163 | |||||
164 | # Try the new version | ||||
165 | 1 | 3µs | 1 | 62µs | $dir = _dist_dir_new( $dist ); # spent 62µs making 1 call to File::ShareDir::_dist_dir_new |
166 | 1 | 4µs | return $dir if defined $dir; | ||
167 | |||||
168 | # Fall back to the legacy version | ||||
169 | $dir = _dist_dir_old( $dist ); | ||||
170 | return $dir if defined $dir; | ||||
171 | |||||
172 | # Ran out of options | ||||
173 | Carp::croak("Failed to find share dir for dist '$dist'"); | ||||
174 | } | ||||
175 | |||||
176 | # spent 62µs (30+33) within File::ShareDir::_dist_dir_new which was called:
# once (30µs+33µs) by File::ShareDir::dist_dir at line 165 | ||||
177 | 1 | 400ns | my $dist = shift; | ||
178 | |||||
179 | # Create the subpath | ||||
180 | 1 | 14µs | 2 | 8µs | my $path = File::Spec->catdir( # spent 7µs making 1 call to File::Spec::Unix::catdir
# spent 800ns making 1 call to File::Spec::Unix::canonpath |
181 | 'auto', 'share', 'dist', $dist, | ||||
182 | ); | ||||
183 | |||||
184 | # Find the full dir withing @INC | ||||
185 | 1 | 1µs | foreach my $inc ( @INC ) { | ||
186 | 2 | 800ns | next unless defined $inc and ! ref $inc; | ||
187 | 2 | 16µs | 4 | 12µs | my $dir = File::Spec->catdir( $inc, $path ); # spent 10µs making 2 calls to File::Spec::Unix::catdir, avg 5µs/call
# spent 2µs making 2 calls to File::Spec::Unix::canonpath, avg 950ns/call |
188 | 2 | 19µs | 2 | 12µs | next unless -d $dir; # spent 12µs making 2 calls to File::ShareDir::CORE:ftdir, avg 6µs/call |
189 | 1 | 9µs | 1 | 4µs | unless ( -r $dir ) { # spent 4µs making 1 call to File::ShareDir::CORE:fteread |
190 | Carp::croak("Found directory '$dir', but no read permissions"); | ||||
191 | } | ||||
192 | 1 | 4µs | return $dir; | ||
193 | } | ||||
194 | |||||
195 | return undef; | ||||
196 | } | ||||
197 | |||||
198 | sub _dist_dir_old { | ||||
199 | my $dist = shift; | ||||
200 | |||||
201 | # Create the subpath | ||||
202 | my $path = File::Spec->catdir( | ||||
203 | 'auto', split( /-/, $dist ), | ||||
204 | ); | ||||
205 | |||||
206 | # Find the full dir within @INC | ||||
207 | foreach my $inc ( @INC ) { | ||||
208 | next unless defined $inc and ! ref $inc; | ||||
209 | my $dir = File::Spec->catdir( $inc, $path ); | ||||
210 | next unless -d $dir; | ||||
211 | unless ( -r $dir ) { | ||||
212 | Carp::croak("Found directory '$dir', but no read permissions"); | ||||
213 | } | ||||
214 | return $dir; | ||||
215 | } | ||||
216 | |||||
217 | return undef; | ||||
218 | } | ||||
219 | |||||
220 | =pod | ||||
221 | |||||
222 | =head2 module_dir | ||||
223 | |||||
224 | # Get a module's shared files directory | ||||
225 | my $dir = module_dir('My::Module'); | ||||
226 | |||||
227 | The C<module_dir> function takes a single parameter of the name of an | ||||
228 | installed (CPAN or otherwise) module, and locates the shared data | ||||
229 | directory created at install time for it. | ||||
230 | |||||
231 | In order to find the directory, the module B<must> be loaded when | ||||
232 | calling this function. | ||||
233 | |||||
234 | Returns the directory path as a string, or dies if it cannot be | ||||
235 | located or is not readable. | ||||
236 | |||||
237 | =cut | ||||
238 | |||||
239 | sub module_dir { | ||||
240 | my $module = _MODULE(shift); | ||||
241 | my $dir; | ||||
242 | |||||
243 | # Try the new version | ||||
244 | $dir = _module_dir_new( $module ); | ||||
245 | return $dir if defined $dir; | ||||
246 | |||||
247 | # Fall back to the legacy version | ||||
248 | return _module_dir_old( $module ); | ||||
249 | } | ||||
250 | |||||
251 | sub _module_dir_new { | ||||
252 | my $module = shift; | ||||
253 | |||||
254 | # Create the subpath | ||||
255 | my $path = File::Spec->catdir( | ||||
256 | 'auto', 'share', 'module', | ||||
257 | _module_subdir( $module ), | ||||
258 | ); | ||||
259 | |||||
260 | # Find the full dir withing @INC | ||||
261 | foreach my $inc ( @INC ) { | ||||
262 | next unless defined $inc and ! ref $inc; | ||||
263 | my $dir = File::Spec->catdir( $inc, $path ); | ||||
264 | next unless -d $dir; | ||||
265 | unless ( -r $dir ) { | ||||
266 | Carp::croak("Found directory '$dir', but no read permissions"); | ||||
267 | } | ||||
268 | return $dir; | ||||
269 | } | ||||
270 | |||||
271 | return undef; | ||||
272 | } | ||||
273 | |||||
274 | sub _module_dir_old { | ||||
275 | my $module = shift; | ||||
276 | my $short = Class::Inspector->filename($module); | ||||
277 | my $long = Class::Inspector->loaded_filename($module); | ||||
278 | $short =~ tr{/}{:} if IS_MACOS; | ||||
279 | substr( $short, -3, 3, '' ); | ||||
280 | $long =~ m/^(.*)\Q$short\E\.pm\z/s or die("Failed to find base dir"); | ||||
281 | my $dir = File::Spec->catdir( "$1", 'auto', $short ); | ||||
282 | unless ( -d $dir ) { | ||||
283 | Carp::croak("Directory '$dir', does not exist"); | ||||
284 | } | ||||
285 | unless ( -r $dir ) { | ||||
286 | Carp::croak("Directory '$dir', no read permissions"); | ||||
287 | } | ||||
288 | return $dir; | ||||
289 | } | ||||
290 | |||||
291 | =pod | ||||
292 | |||||
293 | =head2 dist_file | ||||
294 | |||||
295 | # Find a file in our distribution shared dir | ||||
296 | my $dir = dist_file('My-Distribution', 'file/name.txt'); | ||||
297 | |||||
298 | The C<dist_file> function takes two params of the distribution name | ||||
299 | and file name, locates the dist dir, and then finds the file within | ||||
300 | it, verifying that the file actually exists, and that it is readable. | ||||
301 | |||||
302 | The filename should be a relative path in the format of your local | ||||
303 | filesystem. It will simply added to the directory using L<File::Spec>'s | ||||
304 | C<catfile> method. | ||||
305 | |||||
306 | Returns the file path as a string, or dies if the file or the dist's | ||||
307 | directory cannot be located, or the file is not readable. | ||||
308 | |||||
309 | =cut | ||||
310 | |||||
311 | sub dist_file { | ||||
312 | my $dist = _DIST(shift); | ||||
313 | my $file = _FILE(shift); | ||||
314 | |||||
315 | # Try the new version first | ||||
316 | my $path = _dist_file_new( $dist, $file ); | ||||
317 | return $path if defined $path; | ||||
318 | |||||
319 | # Hand off to the legacy version | ||||
320 | return _dist_file_old( $dist, $file );; | ||||
321 | } | ||||
322 | |||||
323 | sub _dist_file_new { | ||||
324 | my $dist = shift; | ||||
325 | my $file = shift; | ||||
326 | |||||
327 | # If it exists, what should the path be | ||||
328 | my $dir = _dist_dir_new( $dist ); | ||||
329 | my $path = File::Spec->catfile( $dir, $file ); | ||||
330 | |||||
331 | # Does the file exist | ||||
332 | return undef unless -e $path; | ||||
333 | unless ( -f $path ) { | ||||
334 | Carp::croak("Found dist_file '$path', but not a file"); | ||||
335 | } | ||||
336 | unless ( -r $path ) { | ||||
337 | Carp::croak("File '$path', no read permissions"); | ||||
338 | } | ||||
339 | |||||
340 | return $path; | ||||
341 | } | ||||
342 | |||||
343 | sub _dist_file_old { | ||||
344 | my $dist = shift; | ||||
345 | my $file = shift; | ||||
346 | |||||
347 | # Create the subpath | ||||
348 | my $path = File::Spec->catfile( | ||||
349 | 'auto', split( /-/, $dist ), $file, | ||||
350 | ); | ||||
351 | |||||
352 | # Find the full dir withing @INC | ||||
353 | foreach my $inc ( @INC ) { | ||||
354 | next unless defined $inc and ! ref $inc; | ||||
355 | my $full = File::Spec->catdir( $inc, $path ); | ||||
356 | next unless -e $full; | ||||
357 | unless ( -r $full ) { | ||||
358 | Carp::croak("Directory '$full', no read permissions"); | ||||
359 | } | ||||
360 | return $full; | ||||
361 | } | ||||
362 | |||||
363 | # Couldn't find it | ||||
364 | Carp::croak("Failed to find shared file '$file' for dist '$dist'"); | ||||
365 | } | ||||
366 | |||||
367 | =pod | ||||
368 | |||||
369 | =head2 module_file | ||||
370 | |||||
371 | # Find a file in our module shared dir | ||||
372 | my $dir = module_file('My::Module', 'file/name.txt'); | ||||
373 | |||||
374 | The C<module_file> function takes two params of the module name | ||||
375 | and file name. It locates the module dir, and then finds the file within | ||||
376 | it, verifying that the file actually exists, and that it is readable. | ||||
377 | |||||
378 | In order to find the directory, the module B<must> be loaded when | ||||
379 | calling this function. | ||||
380 | |||||
381 | The filename should be a relative path in the format of your local | ||||
382 | filesystem. It will simply added to the directory using L<File::Spec>'s | ||||
383 | C<catfile> method. | ||||
384 | |||||
385 | Returns the file path as a string, or dies if the file or the dist's | ||||
386 | directory cannot be located, or the file is not readable. | ||||
387 | |||||
388 | =cut | ||||
389 | |||||
390 | sub module_file { | ||||
391 | my $module = _MODULE(shift); | ||||
392 | my $file = _FILE(shift); | ||||
393 | my $dir = module_dir($module); | ||||
394 | my $path = File::Spec->catfile($dir, $file); | ||||
395 | unless ( -e $path ) { | ||||
396 | Carp::croak("File '$file' does not exist in module dir"); | ||||
397 | } | ||||
398 | unless ( -r $path ) { | ||||
399 | Carp::croak("File '$file' cannot be read, no read permissions"); | ||||
400 | } | ||||
401 | $path; | ||||
402 | } | ||||
403 | |||||
404 | =pod | ||||
405 | |||||
406 | =head2 class_file | ||||
407 | |||||
408 | # Find a file in our module shared dir, or in our parent class | ||||
409 | my $dir = class_file('My::Module', 'file/name.txt'); | ||||
410 | |||||
411 | The C<module_file> function takes two params of the module name | ||||
412 | and file name. It locates the module dir, and then finds the file within | ||||
413 | it, verifying that the file actually exists, and that it is readable. | ||||
414 | |||||
415 | In order to find the directory, the module B<must> be loaded when | ||||
416 | calling this function. | ||||
417 | |||||
418 | The filename should be a relative path in the format of your local | ||||
419 | filesystem. It will simply added to the directory using L<File::Spec>'s | ||||
420 | C<catfile> method. | ||||
421 | |||||
422 | If the file is NOT found for that module, C<class_file> will scan up | ||||
423 | the module's @ISA tree, looking for the file in all of the parent | ||||
424 | classes. | ||||
425 | |||||
426 | This allows you to, in effect, "subclass" shared files. | ||||
427 | |||||
428 | Returns the file path as a string, or dies if the file or the dist's | ||||
429 | directory cannot be located, or the file is not readable. | ||||
430 | |||||
431 | =cut | ||||
432 | |||||
433 | sub class_file { | ||||
434 | my $module = _MODULE(shift); | ||||
435 | my $file = _FILE(shift); | ||||
436 | |||||
437 | # Get the super path ( not including UNIVERSAL ) | ||||
438 | # Rather than using Class::ISA, we'll use an inlined version | ||||
439 | # that implements the same basic algorithm. | ||||
440 | my @path = (); | ||||
441 | my @queue = ( $module ); | ||||
442 | my %seen = ( $module => 1 ); | ||||
443 | while ( my $cl = shift @queue ) { | ||||
444 | push @path, $cl; | ||||
445 | 2 | 454µs | 2 | 29µs | # spent 18µs (8+10) within File::ShareDir::BEGIN@445 which was called:
# once (8µs+10µs) by File::ShareDir::ProjectDistDir::BEGIN@237 at line 445 # spent 18µs making 1 call to File::ShareDir::BEGIN@445
# spent 10µs making 1 call to strict::unimport |
446 | unshift @queue, grep { ! $seen{$_}++ } | ||||
447 | map { s/^::/main::/; s/\'/::/g; $_ } | ||||
448 | ( @{"${cl}::ISA"} ); | ||||
449 | } | ||||
450 | |||||
451 | # Search up the path | ||||
452 | foreach my $class ( @path ) { | ||||
453 | local $@; | ||||
454 | my $dir = eval { | ||||
455 | module_dir($class); | ||||
456 | }; | ||||
457 | next if $@; | ||||
458 | my $path = File::Spec->catfile($dir, $file); | ||||
459 | unless ( -e $path ) { | ||||
460 | next; | ||||
461 | } | ||||
462 | unless ( -r $path ) { | ||||
463 | Carp::croak("File '$file' cannot be read, no read permissions"); | ||||
464 | } | ||||
465 | return $path; | ||||
466 | } | ||||
467 | Carp::croak("File '$file' does not exist in class or parent shared files"); | ||||
468 | } | ||||
469 | |||||
- - | |||||
473 | ##################################################################### | ||||
474 | # Support Functions | ||||
475 | |||||
476 | sub _module_subdir { | ||||
477 | my $module = shift; | ||||
478 | $module =~ s/::/-/g; | ||||
479 | return $module; | ||||
480 | } | ||||
481 | |||||
482 | sub _dist_packfile { | ||||
483 | my $module = shift; | ||||
484 | my @dirs = grep { -e } ( $Config::Config{archlibexp}, $Config::Config{sitearchexp} ); | ||||
485 | my $file = File::Spec->catfile( | ||||
486 | 'auto', split( /::/, $module), '.packlist', | ||||
487 | ); | ||||
488 | |||||
489 | foreach my $dir ( @dirs ) { | ||||
490 | my $path = File::Spec->catfile( $dir, $file ); | ||||
491 | next unless -f $path; | ||||
492 | |||||
493 | # Load the file | ||||
494 | my $packlist = ExtUtils::Packlist->new($path); | ||||
495 | unless ( $packlist ) { | ||||
496 | die "Failed to load .packlist file for $module"; | ||||
497 | } | ||||
498 | |||||
499 | die "CODE INCOMPLETE"; | ||||
500 | } | ||||
501 | |||||
502 | die "CODE INCOMPLETE"; | ||||
503 | } | ||||
504 | |||||
505 | # Inlined from Params::Util pure perl version | ||||
506 | sub _CLASS { | ||||
507 | (defined $_[0] and ! ref $_[0] and $_[0] =~ m/^[^\W\d]\w*(?:::\w+)*\z/s) ? $_[0] : undef; | ||||
508 | } | ||||
509 | |||||
510 | |||||
511 | # Maintainer note: The following private functions are used by | ||||
512 | # File::ShareDir::PAR. (It has to or else it would have to copy&fork) | ||||
513 | # So if you significantly change or even remove them, please | ||||
514 | # notify the File::ShareDir::PAR maintainer(s). Thank you! | ||||
515 | |||||
516 | # Matches a valid distribution name | ||||
517 | ### This is a total guess at this point | ||||
518 | # spent 9µs (8+2) within File::ShareDir::_DIST which was called:
# once (8µs+2µs) by File::ShareDir::dist_dir at line 161 | ||||
519 | 1 | 10µs | 1 | 2µs | if ( defined $_[0] and ! ref $_[0] and $_[0] =~ /^[a-z0-9+_-]+$/is ) { # spent 2µs making 1 call to File::ShareDir::CORE:match |
520 | return shift; | ||||
521 | } | ||||
522 | Carp::croak("Not a valid distribution name"); | ||||
523 | } | ||||
524 | |||||
525 | # A valid and loaded module name | ||||
526 | sub _MODULE { | ||||
527 | my $module = _CLASS(shift) or Carp::croak("Not a valid module name"); | ||||
528 | if ( Class::Inspector->loaded($module) ) { | ||||
529 | return $module; | ||||
530 | } | ||||
531 | Carp::croak("Module '$module' is not loaded"); | ||||
532 | } | ||||
533 | |||||
534 | # A valid file name | ||||
535 | sub _FILE { | ||||
536 | my $file = shift; | ||||
537 | unless ( defined $file and ! ref $file and length $file ) { | ||||
538 | Carp::croak("Did not pass a file name"); | ||||
539 | } | ||||
540 | if ( File::Spec->file_name_is_absolute($file) ) { | ||||
541 | Carp::croak("Cannot use absolute file name '$file'"); | ||||
542 | } | ||||
543 | $file; | ||||
544 | } | ||||
545 | |||||
546 | 1 | 2µs | 1; | ||
547 | |||||
548 | =pod | ||||
549 | |||||
550 | =head1 SUPPORT | ||||
551 | |||||
552 | Bugs should always be submitted via the CPAN bug tracker | ||||
553 | |||||
554 | L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=File-ShareDir> | ||||
555 | |||||
556 | For other issues, contact the maintainer. | ||||
557 | |||||
558 | =head1 AUTHOR | ||||
559 | |||||
560 | Adam Kennedy E<lt>adamk@cpan.orgE<gt> | ||||
561 | |||||
562 | =head1 SEE ALSO | ||||
563 | |||||
564 | L<File::ShareDir::Install>, L<File::HomeDir>, | ||||
565 | L<Module::Install>, L<Module::Install::Share>, | ||||
566 | L<File::ShareDir::PAR>, L<Dist::Zilla::Plugin::ShareDir> | ||||
567 | |||||
568 | =head1 COPYRIGHT | ||||
569 | |||||
570 | Copyright 2005 - 2011 Adam Kennedy. | ||||
571 | |||||
572 | This program is free software; you can redistribute | ||||
573 | it and/or modify it under the same terms as Perl itself. | ||||
574 | |||||
575 | The full text of the license can be found in the | ||||
576 | LICENSE file included with this module. | ||||
577 | |||||
578 | =cut | ||||
# spent 12µs within File::ShareDir::CORE:ftdir which was called 2 times, avg 6µs/call:
# 2 times (12µs+0s) by File::ShareDir::_dist_dir_new at line 188, avg 6µs/call | |||||
# spent 4µs within File::ShareDir::CORE:fteread which was called:
# once (4µs+0s) by File::ShareDir::_dist_dir_new at line 189 | |||||
# spent 2µs within File::ShareDir::CORE:match which was called:
# once (2µs+0s) by File::ShareDir::_DIST at line 519 |