File Coverage

blib/lib/JSAN/Librarian.pm
Criterion Covered Total %
statement 85 101 84.1
branch 9 26 34.6
condition 2 5 40.0
subroutine 22 28 78.5
pod 8 8 100.0
total 126 168 75.0


line stmt bran cond sub pod time code
1             package JSAN::Librarian;
2              
3             =pod
4              
5             =head1 NAME
6              
7             JSAN::Librarian - JavaScript::Librarian adapter for a JSAN installation
8              
9             =head1 DESCRIPTION
10              
11             L works on the concept of "libraries" of JavaScript
12             files each of which may depend on other files to be loaded before them.
13              
14             C provides a mechanism for detecting and indexing a
15             L object for a L installation.
16              
17             =head1 METHODS
18              
19             =cut
20              
21 2     2   38159 use 5.006;
  2         8  
  2         617  
22 2     2   13 use strict;
  2         4  
  2         74  
23 2     2   11 use Carp ();
  2         4  
  2         30  
24 2     2   11 use File::Spec ();
  2         3  
  2         33  
25 2     2   10 use File::Path ();
  2         3  
  2         26  
26 2     2   9 use Config::Tiny ();
  2         3  
  2         42  
27 2     2   991 use Params::Util qw{ _STRING };
  2         3389  
  2         128  
28 2     2   12 use File::Basename ();
  2         3  
  2         27  
29 2     2   2104 use File::Find::Rule ();
  2         33631  
  2         54  
30 2     2   2914 use JSAN::Parse::FileDeps ();
  2         2694  
  2         44  
31 2     2   542 use JSAN::Librarian::Book ();
  2         6  
  2         38  
32 2     2   630 use JSAN::Librarian::Library ();
  2         27  
  2         44  
33              
34 2     2   11 use vars qw{$VERSION $VERBOSE @DEFAULT};
  2         5  
  2         162  
35             BEGIN {
36 2     2   5 $VERSION = '0.03';
37              
38             # Silent by default
39 2   50     18 $VERBOSE ||= 0;
40              
41             # Look for the index at existing places.
42             # If none found, assume the first.
43 2         3367 @DEFAULT = qw{
44             openjsan.deps
45             .openjsan.deps
46             };
47             }
48              
49              
50              
51              
52              
53             #####################################################################
54             # Constructor
55              
56             =pod
57              
58             =head2 new $path, $index
59              
60             The C constructor creates a new C object for a
61             JSAN installation library/prefix located at a local directory.
62              
63             Because a JSAN installation library does not have a definitive method
64             by which its existance can be verified, at this time the only check
65             actually made is that the directory exists.
66              
67             An optional second parameter can be provided, which will be taken to
68             be the location of the index file. Relative paths will be interpreted
69             as being relative to the root path passed as the first param.
70              
71             Note: As long as the root path exists, a new C object
72             will be created whether index file exists or not.
73              
74             Returns a new C object, or undef if the directory
75             does not exist.
76              
77             =cut
78              
79             sub new {
80 1     1 1 960 my $class = shift;
81 1 50 33     29 my $root = (defined _STRING($_[0]) and -d $_[0]) ? shift : return undef;
82              
83             # Create the object
84 1         5 my $self = bless {
85             root => $root,
86             }, $class;
87              
88             # Check passed index file or use a default
89 1 50       7 $self->{index_file} = @_
    50          
90             ? $self->_new_param(shift)
91             : $self->_new_default
92             or return undef;
93              
94 1         3 return $self;
95             }
96              
97             # Check index file param
98             sub _new_param {
99 0     0   0 my $self = shift;
100 0 0       0 my $param = shift or return undef;
101 0         0 return "$param";
102             }
103              
104             # Determine default
105             sub _new_default {
106 1     1   3 my $self = shift;
107 1         4 my $root = $self->root;
108              
109             # Does it have an existing index
110 1         5 foreach my $file ( @DEFAULT ) {
111 2         34 my $path = File::Spec->catfile( $root, $file );
112 2 50       32 next unless -f $path;
113 0         0 $self->_print("Found index at $path");
114 0         0 return $file;
115             }
116              
117             # It doesn't exist, but use the primary default
118 1         11 my $path = File::Spec->catfile( $root, $DEFAULT[0] );
119 1         8 $self->_print("Using default path $DEFAULT[0]");
120 1         6 return $DEFAULT[0];
121             }
122              
123             =pod
124              
125             =head2 root
126              
127             The C accessor returns the root path of the installed JSAN library.
128              
129             =cut
130              
131             sub root {
132 5     5 1 36 $_[0]->{root};
133             }
134              
135             =pod
136              
137             =head2 index_file
138              
139             The C accessor returns the location of index file, as
140             provided to the constructor (or the default), which may be a path
141             relative to the root.
142              
143             =cut
144              
145             sub index_file {
146 1     1 1 5 $_[0]->{index_file};
147             }
148              
149              
150              
151              
152              
153             #####################################################################
154             # JSAN::Librarian Methods
155              
156             =pod
157              
158             =head2 index_path
159              
160             The C method returns the path to the index file,
161             with relative file locations converted to the full path
162             relative to the root.
163              
164             =cut
165              
166             sub index_path {
167 1     1 1 2 my $self = shift;
168 1         5 my $file = $self->index_file;
169 1 50       18 return File::Spec->file_name_is_absolute($file)
170             ? $file
171             : File::Spec->catfile( $self->root, $file );
172             }
173              
174             =pod
175              
176             =head2 index_exists
177              
178             The C method checks to see if the index file exists.
179              
180             Returns true if the index file exists, or false if not.
181              
182             =cut
183              
184             sub index_exists {
185 0     0 1 0 return -f $_[0]->index_path;
186             }
187              
188             =pod
189              
190             =head2 build_index $lib
191              
192             The C method scans the library to find all perl-file
193             dependencies and builds them into an index object.
194              
195             Returns a L object, or throws an exception on error.
196              
197             =cut
198              
199             sub build_index {
200 2     2 1 705 my $self = shift;
201 2         13 my $config = Config::Tiny->new;
202 2         18 my $root = $self->root;
203              
204             # Find all the files
205 2         13 $self->_print("Searching $root for .js files...");
206 2         25 my @files = File::Find::Rule->name('*.js')
207             ->not_name(qr/_deps\.js$/)
208             ->file
209             ->relative
210             ->in( $root );
211 2         3136 foreach my $js ( @files ) {
212 6         25 $config->{$js} = {};
213 6         75 my $path = File::Spec->catfile( $root, $js );
214 6         32 $self->_print("Scanning $js");
215 6         33 my @deps = JSAN::Parse::FileDeps->file_deps( $path );
216 6         686 foreach ( @deps ) {
217 6         24 $config->{$js}->{$_} = 1;
218             }
219             }
220              
221 2         7 return $config;
222             }
223              
224             =pod
225              
226             =head2 make_index
227              
228             The C static method scans the installed L tree and
229             creates an index file (written from a L object) containing
230             the file-level dependency information.
231              
232             Returns true on success, or throws an exception on error.
233              
234             =cut
235              
236             sub make_index {
237 1     1 1 4171 my $self = shift;
238 1         6 my $path = $self->index_path;
239              
240             # Make sure the output path exists
241 1 50       23 if ( -e $path ) {
242 0 0       0 -w $path or Carp::croak(
243             "Insufficient permissions to change index file '$path'"
244             );
245             } else {
246 1         68 my $dir = File::Basename::dirname( $path );
247 1 50       30 unless ( -d $dir ) {
248 0         0 eval { File::Path::mkpath( $dir, $VERBOSE ); };
  0         0  
249 0 0       0 Carp::croak("$!: Failed to mkdir '$dir' for JSAN::Librarian index file") if $@;
250             }
251             }
252              
253             # Generate the Config::Tiny object
254 1         5 my $config = $self->build_index( $self->root );
255              
256             # Save the index file
257 1         5 $self->_print("Saving $path");
258 1 50       6 $config->write( $path ) or Carp::croak(
259             "Failed to write JSAN::Librarian index file '$path'"
260             );
261             }
262              
263             =pod
264              
265             =head2 library
266              
267             The C method creates and returns a L
268             for the installed L library.
269              
270             If an index file exists, the pre-built index in the file will be used.
271              
272             If there is no index file, the installed JSAN library will be scanned
273             and an index built in-memory as needed.
274              
275             Returns a new L, or throws an exception
276             on error.
277              
278             =cut
279              
280             sub library {
281 0     0 1 0 my $self = shift;
282 0 0       0 my $from = $self->index_exists
283             ? $self->index_path
284             : $self->build_index;
285 0         0 return JSAN::Librarian::Library->new( $from );
286             }
287              
288              
289              
290              
291              
292             #####################################################################
293             # Coercion Support
294              
295 0     0   0 sub __as_JSAN_Librarian_Library { shift->library }
296 0     0   0 sub __as_JavaScript_Librarian_Library { shift->library }
297 0     0   0 sub __as_Algorithm_Dependency_Source { shift->library }
298              
299              
300              
301              
302              
303             #####################################################################
304             # Support Methods
305              
306             sub _print {
307 10     10   16 my $msg = shift;
308 10         254 $msg =~ s/\n*/\n/g;
309 10 50       27 print $msg if $VERBOSE;
310 10         18 return 1;
311             }
312              
313             1;
314              
315             =pod
316              
317             =head1 SUPPORT
318              
319             Bugs should always be submitted via the CPAN bug tracker
320              
321             L
322              
323             For other issues, contact the maintainer.
324              
325             =head1 AUTHORS
326              
327             Adam Kennedy Eadamk@cpan.orgE
328              
329             =head1 COPYRIGHT
330              
331             Copyright 2005 - 2008 Adam Kennedy.
332              
333             This program is free software; you can redistribute
334             it and/or modify it under the same terms as Perl itself.
335              
336             The full text of the license can be found in the
337             LICENSE file included with this module.
338              
339             =cut