File Coverage

lib/OODoc/Format/Pod.pm
Criterion Covered Total %
statement 51 286 17.8
branch 19 198 9.6
condition 0 12 0.0
subroutine 10 34 29.4
pod 17 25 68.0
total 97 555 17.4


line stmt bran cond sub pod time code
1             # Copyrights 2003-2021 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.02.
5             # This code is part of perl distribution OODoc. It is licensed under the
6             # same terms as Perl itself: https://spdx.org/licenses/Artistic-2.0.html
7              
8             package OODoc::Format::Pod;
9 2     2   72965 use vars '$VERSION';
  2         18  
  2         129  
10             $VERSION = '2.02';
11              
12 2     2   12 use base 'OODoc::Format';
  2         5  
  2         551  
13              
14 2     2   13 use strict;
  2         4  
  2         43  
15 2     2   9 use warnings;
  2         4  
  2         69  
16              
17 2     2   18 use Log::Report 'oodoc';
  2         4  
  2         8  
18              
19 2     2   530 use File::Spec ();
  2         4  
  2         61  
20 2     2   9 use List::Util qw/max/;
  2         9  
  2         111  
21 2     2   1167 use Pod::Escapes qw/e2char/;
  2         6802  
  2         8635  
22              
23              
24             sub link($$;$)
25 0     0 1 0 { my ($self, $manual, $object, $text) = @_;
26              
27 0 0       0 $object = $object->subroutine if $object->isa('OODoc::Text::Option');
28 0 0       0 $object = $object->subroutine if $object->isa('OODoc::Text::Default');
29 0 0       0 $object = $object->container if $object->isa('OODoc::Text::Example');
30 0 0       0 $object = $object->container if $object->isa('OODoc::Text::Subroutine');
31 0 0       0 $text = defined $text ? "$text|" : '';
32              
33 0 0       0 return "L<$text$object>"
34             if $object->isa('OODoc::Manual');
35              
36 0 0       0 $object->isa('OODoc::Text::Structure')
37             or error __x"cannot link to a {pkg}", pkg => ref $object;
38              
39 0 0       0 my $manlink = defined $manual ? $object->manual.'/' : '';
40 0         0 qq(L<$text$manlink"$object">);
41             }
42              
43              
44             sub createManual($@)
45 0     0 1 0 { my ($self, %args) = @_;
46 0 0       0 my $manual = $args{manual} or panic;
47 0   0     0 my $options = $args{format_options} || [];
48              
49 0         0 my $podname = $manual->source;
50 0         0 $podname =~ s/\.pm$/.pod/;
51 0         0 my $tmpname = $podname . 't';
52              
53 0         0 my $tmpfile = File::Spec->catfile($self->workdir, $tmpname);
54 0         0 my $podfile = File::Spec->catfile($self->workdir, $podname);
55              
56 0 0       0 my $output = IO::File->new($tmpfile, "w")
57             or fault __x"cannot write prelimary pod manual to {file}"
58             , file => $tmpfile;
59              
60             $self->formatManual
61             ( manual => $manual
62             , output => $output
63             , append => $args{append}
64 0         0 , @$options
65             );
66              
67 0         0 $output->close;
68              
69 0         0 $self->cleanupPOD($tmpfile, $podfile);
70 0         0 unlink $tmpfile;
71              
72 0         0 $self->manifest->add($podfile);
73              
74 0         0 $self;
75             }
76              
77              
78             sub formatManual(@)
79 0     0 1 0 { my $self = shift;
80 0         0 $self->chapterName(@_);
81 0         0 $self->chapterInheritance(@_);
82 0         0 $self->chapterSynopsis(@_);
83 0         0 $self->chapterDescription(@_);
84 0         0 $self->chapterOverloaded(@_);
85 0         0 $self->chapterMethods(@_);
86 0         0 $self->chapterExports(@_);
87 0         0 $self->chapterDetails(@_);
88 0         0 $self->chapterDiagnostics(@_);
89 0         0 $self->chapterReferences(@_);
90 0         0 $self->chapterCopyrights(@_);
91 0         0 $self->showAppend(@_);
92 0         0 $self;
93             }
94              
95             sub showAppend(@)
96 0     0 0 0 { my ($self, %args) = @_;
97 0         0 my $append = $args{append};
98              
99 0 0       0 if(!defined $append) { ; }
    0          
100 0         0 elsif(ref $append eq 'CODE') { $append->(formatter => $self, %args) }
101             else
102 0 0       0 { my $output = $args{output} or panic;
103 0         0 $output->print($append);
104             }
105              
106 0         0 $self;
107             }
108              
109             sub showStructureExpand(@)
110 0     0 0 0 { my ($self, %args) = @_;
111              
112 0   0     0 my $examples = $args{show_chapter_examples} || 'EXPAND';
113 0 0       0 my $text = $args{structure} or panic;
114              
115 0         0 my $name = $text->name;
116 0         0 my $level = $text->level;
117 0 0       0 my $output = $args{output} or panic;
118 0 0       0 my $manual = $args{manual} or panic;
119              
120 0         0 my $descr = $self->cleanup($manual, $text->description);
121 0         0 $output->print("\n=head$level $name\n\n$descr");
122              
123 0         0 $self->showSubroutines(%args, subroutines => [$text->subroutines]);
124 0 0       0 $self->showExamples(%args, examples => [$text->examples])
125             if $examples eq 'EXPAND';
126              
127 0         0 return $self;
128             }
129              
130             sub showStructureRefer(@)
131 0     0 1 0 { my ($self, %args) = @_;
132              
133 0 0       0 my $text = $args{structure} or panic;
134              
135 0         0 my $name = $text->name;
136 0         0 my $level = $text->level;
137 0 0       0 my $output = $args{output} or panic;
138 0 0       0 my $manual = $args{manual} or panic;
139              
140 0         0 my $link = $self->link($manual, $text);
141 0         0 $output->print("\n=head$level $name\n\nSee $link.\n");
142 0         0 $self;
143             }
144              
145             sub chapterDescription(@)
146 0     0 0 0 { my ($self, %args) = @_;
147              
148 0         0 $self->showRequiredChapter(DESCRIPTION => %args);
149              
150 0 0       0 my $manual = $args{manual} or panic;
151 0         0 my $details = $manual->chapter('DETAILS');
152              
153 0 0       0 return $self unless defined $details;
154              
155 0 0       0 my $output = $args{output} or panic;
156 0         0 $output->print("\nSee L chapter below\n");
157 0         0 $self->showChapterIndex($output, $details, " ");
158             }
159              
160             sub chapterDiagnostics(@)
161 0     0 0 0 { my ($self, %args) = @_;
162 0 0       0 my $manual = $args{manual} or panic;
163              
164 0         0 my $diags = $manual->chapter('DIAGNOSTICS');
165 0 0       0 $self->showChapter(chapter => $diags, %args)
166             if defined $diags;
167              
168 0         0 my @diags = map {$_->diagnostics} $manual->subroutines;
  0         0  
169 0 0       0 return unless @diags;
170              
171 0 0       0 my $output = $args{output} or panic;
172 0 0       0 $diags
173             or $output->print("\n=head1 DIAGNOSTICS\n");
174              
175 0         0 $output->print("\n=over 4\n\n");
176 0         0 $self->showDiagnostics(%args, diagnostics => \@diags);
177 0         0 $output->print("\n=back\n\n");
178 0         0 $self;
179             }
180              
181              
182             sub showChapterIndex($$;$)
183 0     0 1 0 { my ($self, $output, $chapter, $indent) = @_;
184 0 0       0 $indent = '' unless defined $indent;
185              
186 0         0 foreach my $section ($chapter->sections)
187 0         0 { $output->print($indent, $section->name, "\n");
188 0         0 foreach my $subsection ($section->subsections)
189 0         0 { $output->print($indent, $indent, $subsection->name, "\n");
190             }
191             }
192 0         0 $self;
193             }
194              
195             sub showExamples(@)
196 0     0 1 0 { my ($self, %args) = @_;
197 0 0       0 my $examples = $args{examples} or panic;
198 0 0       0 return unless @$examples;
199              
200 0 0       0 my $manual = $args{manual} or panic;
201 0 0       0 my $output = $args{output} or panic;
202              
203 0         0 foreach my $example (@$examples)
204 0         0 { my $name = $self->cleanup($manual, $example->name);
205 0         0 $output->print("\nexample: $name\n\n");
206 0         0 $output->print($self->cleanup($manual, $example->description));
207 0         0 $output->print("\n");
208             }
209 0         0 $self;
210             }
211              
212             sub showDiagnostics(@)
213 0     0 0 0 { my ($self, %args) = @_;
214 0 0       0 my $diagnostics = $args{diagnostics} or panic;
215 0 0       0 return unless @$diagnostics;
216              
217 0 0       0 my $manual = $args{manual} or panic;
218 0 0       0 my $output = $args{output} or panic;
219              
220 0         0 foreach my $diag (sort @$diagnostics)
221 0         0 { my $name = $self->cleanup($manual, $diag->name);
222 0         0 my $type = $diag->type;
223 0         0 $output->print("\n=item $type: $name\n\n");
224 0         0 $output->print($self->cleanup($manual, $diag->description));
225 0         0 $output->print("\n");
226             }
227 0         0 $self;
228             }
229              
230             sub showSubroutines(@)
231 0     0 1 0 { my ($self, %args) = @_;
232 0   0     0 my $subs = $args{subroutines} || [];
233 0 0       0 @$subs or return;
234              
235 0 0       0 my $output = $args{output} or panic;
236              
237 0         0 $output->print("\n=over 4\n\n");
238 0         0 $self->SUPER::showSubroutines(%args);
239 0         0 $output->print("\n=back\n\n");
240             }
241              
242             sub showSubroutine(@)
243 0     0 1 0 { my $self = shift;
244 0         0 $self->SUPER::showSubroutine(@_);
245              
246 0         0 my %args = @_;
247 0 0       0 my $output = $args{output} or panic;
248 0         0 $output->print("\n");
249 0         0 $self;
250             }
251              
252             sub showSubroutineUse(@)
253 0     0 1 0 { my ($self, %args) = @_;
254 0 0       0 my $subroutine = $args{subroutine} or panic;
255 0 0       0 my $manual = $args{manual} or panic;
256 0 0       0 my $output = $args{output} or panic;
257              
258 0         0 my $use = $self->subroutineUse($manual, $subroutine);
259 0         0 $use =~ s/(.+)/=item $1\n\n/gm;
260              
261 0         0 $output->print($use);
262 0 0       0 $output->print("Inherited, see ". $self->link($manual, $subroutine)."\n\n")
263             if $manual->inherited($subroutine);
264              
265 0         0 $self;
266             }
267              
268             sub subroutineUse($$)
269 0     0 0 0 { my ($self, $manual, $subroutine) = @_;
270 0         0 my $type = $subroutine->type;
271 0         0 my $name = $self->cleanup($manual, $subroutine->name);
272 0         0 my $paramlist = $self->cleanup($manual, $subroutine->parameters);
273 0 0       0 my $params
    0          
274             = !length $paramlist ? '()'
275             : $paramlist =~ m/^[\[<]|[\]>]$/ ? "( $paramlist )"
276             : "($paramlist)";
277              
278 0         0 my $class = $manual->package;
279 0 0       0 my $use
    0          
    0          
    0          
    0          
    0          
280             = $type eq 'i_method' ? qq[\$obj-EB<$name>$params]
281             : $type eq 'c_method' ? qq[$class-EB<$name>$params]
282             : $type eq 'ci_method'? qq[\$obj-EB<$name>$params\n]
283             . qq[$class-EB<$name>$params]
284             : $type eq 'function' ? qq[B<$name>$params]
285             : $type eq 'overload' ? qq[overload: B<$name>]
286             : $type eq 'tie' ? qq[B<$name>$params]
287             : '';
288              
289 0 0       0 length $use
290             or warn "WARNING: unknown subroutine type $type for $name in $manual";
291              
292 0         0 $use;
293             }
294              
295             sub showSubroutineName(@)
296 0     0 1 0 { my ($self, %args) = @_;
297 0 0       0 my $subroutine = $args{subroutine} or panic;
298 0 0       0 my $manual = $args{manual} or panic;
299 0 0       0 my $output = $args{output} or panic;
300 0         0 my $name = $subroutine->name;
301              
302 0 0       0 my $url
303             = $manual->inherited($subroutine)
304             ? "M<".$subroutine->manual."::$name>"
305             : "M<$name>";
306              
307             $output->print
308             ( $self->cleanup($manual, $url)
309 0 0       0 , ($args{last} ? ".\n" : ",\n")
310             );
311             }
312              
313             sub showOptions(@)
314 0     0 1 0 { my ($self, %args) = @_;
315 0 0       0 my $output = $args{output} or panic;
316 0         0 $output->print("\n=over 2\n\n");
317 0         0 $self->SUPER::showOptions(%args);
318 0         0 $output->print("\n=back\n\n");
319             }
320              
321             sub showOptionUse(@)
322 0     0 1 0 { my ($self, %args) = @_;
323 0 0       0 my $output = $args{output} or panic;
324 0 0       0 my $option = $args{option} or panic;
325 0 0       0 my $manual = $args{manual} or panic;
326              
327 0         0 my $params = $option->parameters;
328 0         0 $params =~ s/\s+$//;
329 0         0 $params =~ s/^\s+//;
330 0 0       0 $params = " => ".$self->cleanup($manual, $params) if length $params;
331              
332 0         0 $output->print("=item $option$params\n\n");
333 0         0 $self;
334             }
335              
336             sub showOptionExpand(@)
337 0     0 1 0 { my ($self, %args) = @_;
338 0 0       0 my $output = $args{output} or panic;
339 0 0       0 my $option = $args{option} or panic;
340 0 0       0 my $manual = $args{manual} or panic;
341              
342 0         0 $self->showOptionUse(%args);
343              
344 0 0       0 my $where = $option->findDescriptionObject or return $self;
345 0         0 my $descr = $self->cleanup($manual, $where->description);
346 0 0       0 $output->print("\n$descr\n\n")
347             if length $descr;
348              
349 0         0 $self;
350             }
351              
352              
353             sub writeTable($@)
354 0     0 1 0 { my ($self, %args) = @_;
355              
356 0 0       0 my $head = $args{header} or panic;
357 0 0       0 my $output = $args{output} or panic;
358 0 0       0 my $rows = $args{rows} or panic;
359 0 0       0 return unless @$rows;
360              
361             # Convert all elements to plain text, because markup is not
362             # allowed in verbatim pod blocks.
363 0         0 my @rows;
364 0         0 foreach my $row (@$rows)
365 0         0 { push @rows, [ map {$self->removeMarkup($_)} @$row ];
  0         0  
366             }
367              
368             # Compute column widths
369 0         0 my @w = (0) x @$head;
370              
371 0         0 foreach my $row ($head, @rows)
372             { $w[$_] = max $w[$_], length($row->[$_])
373 0         0 foreach 0..$#$row;
374             }
375              
376 0 0       0 if(my $widths = $args{widths})
377             { defined $widths->[$_] && $widths->[$_] > $w[$_] && ($w[$_] = $widths->[$_])
378 0   0     0 for 0..$#$rows;
      0        
379             }
380              
381 0         0 pop @w; # ignore width of last column
382              
383             # Table head
384 0         0 my $headf = " -".join("--", map { "\%-${_}s" } @w)."--%s\n";
  0         0  
385 0         0 $output->printf($headf, @$head);
386              
387             # Table body
388 0         0 my $format = " ".join(" ", map { "\%-${_}s" } @w)." %s\n";
  0         0  
389             $output->printf($format, @$_)
390 0         0 for @rows;
391             }
392              
393              
394             sub removeMarkup($)
395 20     20 1 153 { my ($self, $string) = @_;
396 20         37 my $out = $self->_removeMarkup($string);
397 20         49 for($out)
398 20         43 { s/^\s+//gm;
399 20         43 s/\s+$//gm;
400 20         32 s/\s{2,}/ /g;
401 20         30 s/\[NB\]/ /g;
402             }
403 20         108 $out;
404             }
405              
406             sub _removeMarkup($)
407 37     37   62 { my ($self, $string) = @_;
408              
409 37         78 my $out = '';
410 37         180 while($string =~ s/(.*?) # before
411             ([BCEFILSXZ]) # known formatting codes
412             ([<]+) # capture ALL starters
413             //x)
414 27         90 { $out .= $1;
415 27         77 my ($tag, $bracks, $brack_count) = ($2, $3, length($3));
416              
417 27 50       377 if($string !~ s/^(|.*?[^>]) # contained
418             [>]{$brack_count}
419             (?![>])
420             //xs)
421 0         0 { $out .= "$tag$bracks";
422 0         0 next;
423             }
424              
425 27         60 my $container = $1;
426 27 100       110 if($tag =~ m/[XZ]/) { ; } # ignore container content
    100          
    100          
    50          
    50          
    0          
427             elsif($tag =~ m/[BCI]/) # cannot display, but can be nested
428 13         31 { $out .= $self->_removeMarkup($container);
429             }
430 3         10 elsif($tag eq 'E') { $out .= e2char($container) }
431 0         0 elsif($tag eq 'F') { $out .= $container }
432             elsif($tag eq 'L')
433 8 100       23 { if($container =~ m!^\s*([^/|]*)\|!)
434 4         11 { $out .= $self->_removeMarkup($1);
435 4         11 next;
436             }
437              
438 4         9 my ($man, $chapter) = ($container, '');
439 4 100       20 if($container =~ m!^\s*([^/]*)/\"([^"]*)\"\s*$!)
    100          
440 2         5 { ($man, $chapter) = ($1, $2);
441             }
442             elsif($container =~ m!^\s*([^/]*)/(.*?)\s*$!)
443 1         3 { ($man, $chapter) = ($1, $2);
444             }
445              
446             $out .=
447 4 100       21 ( !length $man ? "section $chapter"
    100          
448             : !length $chapter ? $man
449             : "$man section $chapter"
450             );
451             }
452             elsif($tag eq 'S')
453 0         0 { my $clean = $self->_removeMarkup($container);
454 0         0 $clean =~ s/ /[NB]/g;
455 0         0 $out .= $clean;
456             }
457             }
458              
459 37         105 $out . $string;
460             }
461              
462             sub showSubroutineDescription(@)
463 0     0 1   { my ($self, %args) = @_;
464 0 0         my $manual = $args{manual} or panic;
465 0 0         my $subroutine = $args{subroutine} or panic;
466              
467 0           my $text = $self->cleanup($manual, $subroutine->description);
468 0 0         return $self unless length $text;
469              
470 0 0         my $output = $args{output} or panic;
471 0           $output->print("\n", $text);
472              
473 0 0         my $extends = $self->extends or return $self;
474 0 0         my $refer = $extends->findDescriptionObject or return $self;
475 0           $self->showSubroutineDescriptionRefer(%args, subroutine => $refer);
476             }
477              
478             sub showSubroutineDescriptionRefer(@)
479 0     0 0   { my ($self, %args) = @_;
480 0 0         my $manual = $args{manual} or panic;
481 0 0         my $subroutine = $args{subroutine} or panic;
482 0 0         my $output = $args{output} or panic;
483 0           $output->print("\nInherited, see ",$self->link($manual, $subroutine),"\n");
484             }
485              
486       0 0   sub showSubsIndex() {;}
487              
488              
489             sub cleanupPOD($$)
490 0     0 1   { my ($self, $infn, $outfn) = @_;
491 0 0         my $in = IO::File->new($infn, 'r')
492             or fault __x"cannot read prelimary pod from {file}", file => $infn;
493              
494 0 0         my $out = IO::File->new($outfn, 'w')
495             or fault __x"cannot write final pod to {file}", file => $outfn;
496              
497 0           my $last_is_blank = 1;
498             LINE:
499 0           while(my $l = $in->getline)
500 0 0         { if($l =~ m/^\s*$/s)
501 0 0         { next LINE if $last_is_blank;
502 0           $last_is_blank = 1;
503             }
504             else
505 0           { $last_is_blank = 0;
506             }
507              
508 0           $out->print($l);
509             }
510              
511 0           $in->close;
512 0 0         $out->close
513             or fault __x"write to {file} failed", file => $outfn;
514              
515 0           $self;
516             }
517              
518              
519             1;