File Coverage

lib/OODoc.pm
Criterion Covered Total %
statement 33 206 16.0
branch 0 114 0.0
condition 0 33 0.0
subroutine 11 24 45.8
pod 9 10 90.0
total 53 387 13.7


line stmt bran cond sub pod time code
1             # Copyrights 2003-2013 by [Mark Overmeer].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.00.
5              
6             package OODoc;
7 1     1   10011 use vars '$VERSION';
  1         2  
  1         55  
8             $VERSION = '2.00';
9              
10 1     1   5 use base 'OODoc::Object';
  1         2  
  1         77  
11              
12 1     1   4 use strict;
  1         2  
  1         41  
13 1     1   5 use warnings;
  1         1  
  1         54  
14              
15 1     1   5 use Log::Report 'oodoc';
  1         2  
  1         9  
16              
17 1     1   283 use OODoc::Manifest;
  1         2  
  1         25  
18              
19 1     1   5 use File::Copy;
  1         2  
  1         59  
20 1     1   6 use File::Spec;
  1         2  
  1         49  
21 1     1   6 use File::Basename;
  1         2  
  1         61  
22 1     1   5 use IO::File;
  1         2  
  1         175  
23 1     1   5 use List::Util 'first';
  1         2  
  1         2690  
24              
25              
26             sub init($)
27 0     0 0   { my ($self, $args) = @_;
28              
29 0 0         $self->SUPER::init($args) or return;
30              
31 0           $self->{O_pkg} = {};
32              
33 0           my $distribution = $self->{O_distribution} = delete $args->{distribution};
34 0 0         defined $distribution
35             or error __x"the produced distribution needs a project description";
36              
37 0   0       $self->{O_project} = delete $args->{project} || $distribution;
38              
39 0           my $version = delete $args->{version};
40 0 0         unless(defined $version)
41 0 0         { my $fn = -f 'version' ? 'version'
    0          
42             : -f 'VERSION' ? 'VERSION'
43             : undef;
44 0 0         if(defined $fn)
45 0 0         { my $v = IO::File->new($fn, 'r')
46             or fault __x"cannot read version from file {file}", file=> $fn;
47 0           $version = $v->getline;
48 0 0         $version = $1 if $version =~ m/(\d+\.[\d\.]+)/;
49 0           chomp $version;
50             }
51             }
52              
53 0 0         defined $version
54             or error __x"no version specified for distribution '{dist}'"
55             , dist => $distribution;
56              
57 0           $self->{O_version} = $version;
58 0           $self;
59             }
60              
61             #-------------------------------------------
62              
63              
64 0     0 1   sub distribution() {shift->{O_distribution}}
65              
66              
67 0     0 1   sub version() {shift->{O_version}}
68              
69              
70 0     0 1   sub project() {shift->{O_project}}
71              
72             #-------------------------------------------
73              
74              
75             sub selectFiles($@)
76 0     0 1   { my ($self, $files) = (shift, shift);
77              
78             my $select
79 0     0     = ref $files eq 'Regexp' ? sub { $_[0] =~ $files }
80 0 0         : ref $files eq 'CODE' ? $files
    0          
    0          
81             : ref $files eq 'ARRAY' ? $files
82             : error __x"use regex, code reference or array for file selection";
83              
84 0 0         return ($select, [])
85             if ref $select eq 'ARRAY';
86              
87 0           my (@process, @copy);
88 0           foreach my $fn (@_)
89 0 0         { if($select->($fn)) {push @process, $fn}
  0            
  0            
90             else {push @copy, $fn}
91             }
92              
93 0           ( \@process, \@copy );
94             }
95              
96              
97             sub processFiles(@)
98 0     0 1   { my ($self, %args) = @_;
99              
100 0 0         exists $args{workdir}
101             or error __x"requires a directory to write the distribution to";
102              
103 0           my $dest = $args{workdir};
104 0           my $source = $args{source};
105 0   0       my $distr = $args{distribution} || $self->distribution;
106              
107 0           my $version = $args{version};
108 0 0         unless(defined $version)
109 0 0         { my $fn = defined $source ? File::Spec->catfile($source, 'version')
110             : 'version';
111 0 0         $fn = -f $fn ? $fn
    0          
112             : defined $source ? File::Spec->catfile($source, 'VERSION')
113             : 'VERSION';
114 0 0         if(defined $fn)
    0          
115 0 0         { my $v = IO::File->new($fn, "r")
116             or fault __x"cannot read version from {file}", file => $fn;
117 0           $version = $v->getline;
118 0 0         $version = $1 if $version =~ m/(\d+\.[\d\.]+)/;
119 0           chomp $version;
120             }
121             elsif($version = $self->version) { ; }
122             else
123 0           { error __x"there is no version defined for the source files";
124             }
125             }
126              
127 0           my $notice = '';
128 0 0         if($notice = $args{notice})
129 0           { $notice =~ s/^(\#\s)?/# /mg; # put comments if none
130             }
131              
132             #
133             # Split the set of files into those who do need special processing
134             # and those who do not.
135             #
136              
137 0 0         my $manfile
    0          
138             = exists $args{manifest} ? $args{manifest}
139             : defined $source ? File::Spec->catfile($source, 'MANIFEST')
140             : 'MANIFEST';
141              
142 0           my $manifest = OODoc::Manifest->new(filename => $manfile);
143              
144 0           my $manout;
145 0 0         if(defined $dest)
146 0           { my $manif = File::Spec->catfile($dest, 'MANIFEST');
147 0           $manout = OODoc::Manifest->new(filename => $manif);
148 0           $manout->add($manif);
149             }
150             else
151 0           { $manout = OODoc::Manifest->new(filename => undef);
152             }
153              
154 0   0       my $select = $args{select} || qr/\.(pm|pod)$/;
155 0           my ($process, $copy) = $self->selectFiles($select, @$manifest);
156              
157 0           trace @$process." files to process and ".@$copy." files to copy";
158              
159             #
160             # Copy all the files which do not contain pseudo doc
161             #
162              
163 0 0         if(defined $dest)
164 0           { foreach my $filename (@$copy)
165 0 0         { my $fn = defined $source ? File::Spec->catfile($source, $filename)
166             : $filename;
167              
168 0           my $dn = File::Spec->catfile($dest, $fn);
169 0 0         unless(-f $fn)
170 0           { warning __x"no file {file} to include in the distribution"
171             , file => $fn;
172 0           next;
173             }
174              
175 0 0 0       unless(-e $dn && ( -M $dn < -M $fn ) && ( -s $dn == -s $fn ))
      0        
176 0           { $self->mkdirhier(dirname $dn);
177              
178 0 0         copy $fn, $dn
179             or fault __x"cannot copy distribution file {from} to {to}"
180             , from => $fn, to => $dest;
181              
182 0           trace " copied $fn to $dest";
183             }
184              
185 0           $manout->add($dn);
186             }
187             }
188              
189             #
190             # Create the parser
191             #
192              
193 0   0       my $parser = $args{parser} || 'OODoc::Parser::Markov';
194 0           my $skip_links = delete $args{skip_links};
195              
196 0 0         unless(ref $parser)
197 0           { eval "require $parser";
198 0 0         error __x"cannot compile {pkg} class: {err}", pkg => $parser, err => $@
199             if $@;
200              
201 0 0         $parser = $parser->new(skip_links => $skip_links)
202             or error __x"parser {name} could not be instantiated", name=>$parser;
203             }
204              
205             #
206             # Now process the rest
207             #
208              
209 0           foreach my $filename (@$process)
210 0 0         { my $fn = $source ? File::Spec->catfile($source, $filename) : $filename;
211              
212 0 0         unless(-f $fn)
213 0           { warning __x"no file {file} to include in the distribution"
214             , file => $fn;
215 0           next;
216             }
217              
218 0           my $dn;
219 0 0         if($dest)
220 0           { $dn = File::Spec->catfile($dest, $fn);
221 0           $self->mkdirhier(dirname $dn);
222 0           $manout->add($dn);
223             }
224              
225             # do the stripping
226 0           my @manuals = $parser->parse
227             ( input => $fn
228             , output => $dn
229             , distribution => $distr
230             , version => $version
231             , notice => $notice
232             );
233              
234 0 0         trace "stripped $fn into $dn" if defined $dn;
235 0           trace $_->stats for @manuals;
236              
237 0           foreach my $man (@manuals)
238 0 0         { $self->addManual($man) if $man->chapters;
239             }
240             }
241              
242             # Some general subtotals
243 0           trace $self->stats;
244              
245 0           $self;
246             }
247              
248             #-------------------------------------------
249              
250              
251             sub prepare(@)
252 0     0 1   { my ($self, %args) = @_;
253              
254 0           info "collect package relations";
255 0           $self->getPackageRelations;
256              
257 0           info "expand manual contents";
258 0           foreach my $manual ($self->manuals)
259 0           { trace " expand manual $manual";
260 0           $manual->expand;
261             }
262              
263 0           info "Create inheritance chapter";
264 0           foreach my $manual ($self->manuals)
265 0           { trace " create inheritance for $manual";
266 0           $manual->createInheritance;
267             }
268              
269 0           $self;
270             }
271              
272              
273             sub getPackageRelations($)
274 0     0 1   { my $self = shift;
275 0           my @manuals = $self->manuals; # all
276              
277             #
278             # load all distributions (which are not loaded yet)
279             #
280              
281 0           info "compile all packages";
282              
283 0           foreach my $manual (@manuals)
284 0 0         { next if $manual->isPurePod;
285 0           trace " require package $manual";
286              
287 0           eval "require $manual";
288 0 0 0       warning __x"errors from {manual}: {err}", manual => $manual, err =>$@
      0        
289             if $@ && $@ !~ /can't locate/i && $@ !~ /attempt to reload/i;
290             }
291              
292 0           info "detect inheritance relationships";
293              
294 0           foreach my $manual (@manuals)
295             {
296 0           trace " relations for $manual";
297              
298 0 0         if($manual->name ne $manual->package) # autoloaded code
299 0           { my $main = $self->mainManual("$manual");
300 0 0         $main->extraCode($manual) if defined $main;
301 0           next;
302             }
303 0           my %uses = $manual->collectPackageRelations;
304              
305 0 0         foreach (defined $uses{isa} ? @{$uses{isa}} : ())
  0            
306 0   0       { my $isa = $self->mainManual($_) || $_;
307              
308 0           $manual->superClasses($isa);
309 0 0         $isa->subClasses($manual) if ref $isa;
310             }
311              
312 0 0         if(my $realizes = $uses{realizes})
313 0   0       { my $to = $self->mainManual($realizes) || $realizes;
314              
315 0           $manual->realizes($to);
316 0 0         $to->realizers($manual) if ref $to;
317             }
318             }
319              
320 0           $self;
321             }
322              
323             #-------------------------------------------
324              
325              
326             our %formatters =
327             ( pod => 'OODoc::Format::Pod'
328             , pod2 => 'OODoc::Format::Pod2'
329             , pod3 => 'OODoc::Format::Pod3'
330             , html => 'OODoc::Format::Html'
331             , html2 => 'OODoc::Format::Html2'
332             );
333              
334             sub create($@)
335 0     0 1   { my ($self, $format, %args) = @_;
336              
337 0 0         my $dest = $args{workdir}
338             or error __x"create requires a directory to write the manuals to";
339              
340             #
341             # Start manifest
342             #
343              
344 0 0         my $manfile = exists $args{manifest} ? $args{manifest}
345             : File::Spec->catfile($dest, 'MANIFEST');
346 0           my $manifest = OODoc::Manifest->new(filename => $manfile);
347              
348             # Create the formatter
349              
350 0 0         unless(ref $format)
351 0 0         { $format = $formatters{$format}
352             if exists $formatters{$format};
353              
354 0           eval "require $format";
355 0 0         error __x"formatter {name} has compilation errors: {err}"
356             , name => $format, err => $@ if $@;
357              
358 0   0       my $options = delete $args{format_options} || [];
359              
360 0           $format = $format->new
361             ( manifest => $manifest
362             , workdir => $dest
363             , project => $self->distribution
364             , version => $self->version
365             , @$options
366             );
367             }
368              
369             #
370             # Create the manual pages
371             #
372              
373 0     0     my $select = ! defined $args{select} ? sub {1}
374             : ref $args{select} eq 'CODE' ? $args{select}
375 0 0   0     : sub { $_[0]->name =~ $args{select}};
  0 0          
376              
377 0           foreach my $package (sort $self->packageNames)
378             {
379 0           foreach my $manual ($self->manualsForPackage($package))
380 0 0         { next unless $select->($manual);
381              
382 0 0         unless($manual->chapters)
383 0           { trace " skipping $manual: no chapters";
384 0           next;
385             }
386              
387 0           trace " creating manual $manual with ".(ref $format);
388              
389 0   0       $format->createManual
390             ( manual => $manual
391             , template => $args{manual_templates}
392             , append => $args{append}
393             , format_options => ($args{manual_format} || [])
394             );
395             }
396             }
397              
398             #
399             # Create other pages
400             #
401              
402 0           trace "creating other pages";
403 0           $format->createOtherPages
404             ( source => $args{other_templates}
405             , process => $args{process_files}
406             );
407              
408 0           $format;
409             }
410              
411              
412             sub stats()
413 0     0 1   { my $self = shift;
414 0           my @manuals = $self->manuals;
415 0           my $manuals = @manuals;
416 0           my $realpkg = $self->packageNames;
417              
418 0           my $subs = map {$_->subroutines} @manuals;
  0            
419 0           my @options = map { map {$_->options} $_->subroutines } @manuals;
  0            
  0            
420 0           my $options = @options;
421 0           my $examples = map {$_->examples} @manuals;
  0            
422              
423 0           my $diags = map {$_->diagnostics} @manuals;
  0            
424 0           my $distribution = $self->distribution;
425 0           my $version = $self->version;
426              
427 0           <
428             $distribution version $version
429             Number of package manuals: $manuals
430             Real number of packages: $realpkg
431             documented subroutines: $subs
432             documented options: $options
433             documented diagnostics: $diags
434             shown examples: $examples
435             STATS
436             }
437              
438             #-------------------------------------------
439              
440              
441             1;