File Coverage

blib/lib/Pod/Readme.pm
Criterion Covered Total %
statement 71 79 89.8
branch 11 26 42.3
condition 5 7 71.4
subroutine 18 18 100.0
pod 5 5 100.0
total 110 135 81.4


line stmt bran cond sub pod time code
1             package Pod::Readme;
2              
3             =head1 NAME
4              
5             Pod::Readme - Intelligently generate a README file from POD
6              
7             =for readme plugin version
8              
9             =head1 SYNOPSIS
10              
11             In a module's POD:
12              
13             =head1 NAME
14              
15             MyApp - my nifty app
16              
17             =for readme plugin version
18              
19             =head1 DESCRIPTION
20              
21             This is a nifty app.
22              
23             =begin :readme
24              
25             =for readme plugin requires
26              
27             =head1 INSTALLATION
28              
29             ...
30              
31             =end :readme
32              
33             =for readme stop
34              
35             =head1 METHODS
36              
37             ...
38              
39             Then from the command-line:
40              
41             pod2readme lib/MyModule.pm README
42              
43             =for readme stop
44              
45             From within Perl:
46              
47             use Pod::Readme;
48              
49             my $prf = Pod::Readme->new(
50             input_file => 'lib/MyModule.pm',
51             translate_to_file => $dest,
52             translation_class => 'Pod::Simple::Text',
53             );
54              
55             $prf->run();
56              
57             =for readme start
58              
59             =head1 DESCRIPTION
60              
61             This module filters POD to generate a F file, by using POD
62             commands to specify which parts are included or excluded from the
63             F file.
64              
65             =begin :readme
66              
67             See the L documentation for more details on the POD
68             syntax that this module recognizes.
69              
70             See L for command-line usage.
71              
72             =head1 INSTALLATION
73              
74             See
75             L.
76              
77             =for readme plugin requires heading-level=2 title="Required Modules"
78              
79             =for readme plugin changes
80              
81             =end :readme
82              
83             =for readme stop
84              
85             =head1 POD COMMANDS
86              
87             =head2 C<=for readme stop>
88              
89             Stop including the POD that follows in the F.
90              
91             =head2 C<=for readme start>
92              
93             =head2 C<=for readme continue>
94              
95             Start (or continue to) include the POD that follows in the F.
96              
97             Note that the C command was added as a synonym in version
98             1.0.0.
99              
100             =head2 C<=for readme include>
101              
102             =for readme include file="INSTALL" type="text"
103              
104             Include a text or POD file in the F. It accepts the following
105             options:
106              
107             =over
108              
109             =item C
110              
111             Required. This is the file name to include.
112              
113             =item C
114              
115             Can be "text" or "pod" (default).
116              
117             =item C
118              
119             An optional regex of where to start including the file.
120              
121             =item C
122              
123             An optional regex of where to stop including the file.
124              
125             =back
126              
127             =head2 C<=for readme plugin>
128              
129             Loads a plugin, e.g.
130              
131             =for readme plugin version
132              
133             Note that specific plugins may add options, e.g.
134              
135             =for readme plugin changes title='CHANGES'
136              
137             See L for more information.
138              
139             Note that the C command was added in version 1.0.0.
140              
141             =head2 C<=begin :readme>
142              
143             =head2 C<=end :readme>
144              
145             Specify a block of POD to include only in the F.
146              
147             You can also specify a block in another format:
148              
149             =begin readme text
150              
151             ...
152              
153             =end readme text
154              
155             This will be translated into
156              
157             =begin text
158              
159             ...
160              
161             =end text
162              
163             and will only be included in F files of that format.
164              
165             Note: earlier versions of this module suggested using
166              
167             =begin readme
168              
169             ...
170              
171             =end readme
172              
173             While this version supports that syntax for backwards compatibility,
174             it is not standard POD.
175              
176             =cut
177              
178 4     4   22126 use v5.10.1;
  4         15  
179              
180 4     4   2039 use Moo;
  4         45781  
  4         19  
181             extends 'Pod::Readme::Filter';
182              
183             our $VERSION = 'v1.2.3';
184              
185 4     4   5833 use Carp;
  4         10  
  4         278  
186 4     4   25 use IO qw/ File Handle /;
  4         6  
  4         26  
187 4     4   6829 use List::Util 1.33 qw/ any /;
  4         64  
  4         396  
188 4     4   1774 use Module::Load qw/ load /;
  4         4451  
  4         27  
189 4     4   363 use Path::Tiny qw/ path tempfile /;
  4         13  
  4         226  
190 4     4   1991 use Pod::Simple;
  4         88255  
  4         156  
191 4     4   2224 use Types::Standard qw/ Bool Maybe Str /;
  4         298789  
  4         38  
192              
193 4     4   6128 use Pod::Readme::Types qw/ File WriteIO /;
  4         12  
  4         4149  
194              
195             # RECOMMEND PREREQ: Pod::Man
196             # RECOMMEND PREREQ: Pod::Markdown
197             # RECOMMEND PREREQ: Pod::Markdown::Github
198             # RECOMMEND PREREQ: Pod::Simple::HTML
199             # RECOMMEND PREREQ: Pod::Simple::LaTeX
200             # RECOMMEND PREREQ: Pod::Simple::RTF
201             # RECOMMEND PREREQ: Pod::Simple::Text
202             # RECOMMEND PREREQ: Pod::Simple::XHTML
203              
204             =head1 ATTRIBUTES
205              
206             This module extends L with the following
207             attributes:
208              
209             =head2 C
210              
211             The class used to translate the filtered POD into another format,
212             e.g. L.
213              
214             If it is C, then there is no translation.
215              
216             Only subclasses of L are supported.
217              
218             =cut
219              
220             has translation_class => (
221             is => 'ro',
222             isa => Maybe [Str],
223             default => undef,
224             );
225              
226             =head2 C
227              
228             The L to save the translated file to.
229              
230             =cut
231              
232             has translate_to_fh => (
233             is => 'ro',
234             isa => WriteIO,
235             lazy => 1,
236             builder => '_build_translate_to_fh',
237             coerce => sub { WriteIO->coerce(@_) },
238             );
239              
240             sub _build_translate_to_fh {
241 2     2   42 my ($self) = @_;
242 2 50       36 if ( $self->translate_to_file ) {
243 2         54 $self->translate_to_file->openw;
244             }
245             else {
246 0         0 my $fh = IO::Handle->new;
247 0 0       0 if ( $fh->fdopen( fileno(STDOUT), 'w' ) ) {
248 0         0 return $fh;
249             }
250             else {
251 0         0 croak "Cannot get a filehandle for STDOUT";
252             }
253             }
254             }
255              
256             =head2 C
257              
258             The L filename to save the translated file to. If omitted,
259             then it will be saved to C.
260              
261             =cut
262              
263             has translate_to_file => (
264             is => 'ro',
265             isa => File,
266             coerce => sub { File->coerce(@_) },
267             lazy => 1,
268             builder => 'default_readme_file',
269             );
270              
271             =head2 C
272              
273             The L C will default to a temporary
274             file.
275              
276             =cut
277              
278             has '+output_file' => (
279             lazy => 1,
280             default => sub { tempfile( SUFFIX => '.pod', UNLINK => 1 ); },
281             );
282              
283             around '_build_output_fh' => sub {
284             my ( $orig, $self ) = @_;
285             if ( defined $self->translation_class ) {
286             $self->$orig();
287             }
288             else {
289             $self->translate_to_fh;
290             }
291             };
292              
293             =head2 C
294              
295             For a new F to be generated, even if the dependencies have not
296             been updated.
297              
298             See L.
299              
300             =cut
301              
302             has 'force' => (
303             is => 'ro',
304             isa => Bool,
305             default => 0,
306             );
307              
308             =head2 C
309              
310             For use with L plugins.
311              
312             This allows plugins which normally depend on files in the distribution
313             to use metadata from here instead.
314              
315             =cut
316              
317             =head1 METHODS
318              
319             This module extends L with the following methods:
320              
321             =head2 C
322              
323             The default name of the F file, which depends on the
324             L.
325              
326             =cut
327              
328             sub default_readme_file {
329 3     3 1 96 my ($self) = @_;
330              
331 3         48 my $name = uc( $self->target );
332              
333 3         31 state $extensions = {
334             'Pod::Man' => '.1',
335             'Pod::Markdown' => '.md',
336             'Pod::Simple::HTML' => '.html',
337             'Pod::Simple::LaTeX' => '.tex',
338             'Pod::Simple::RTF' => '.rtf',
339             'Pod::Simple::Text' => '',
340             'Pod::Simple::XHTML' => '.xhtml',
341             };
342              
343 3         24 my $class = $self->translation_class;
344 3 50       15 if ( defined $class ) {
345 0 0       0 if ( my $ext = $extensions->{$class} ) {
346 0         0 $name .= $ext;
347             }
348             }
349             else {
350 3         11 $name .= '.pod';
351             }
352              
353 3         24 path( $self->base_dir, $name );
354             }
355              
356             =head2 C
357              
358             This method runs translates the resulting POD from C.
359              
360             =cut
361              
362             sub translate_file {
363 4     4 1 10 my ($self) = @_;
364              
365 4 50       12 if ( my $class = $self->translation_class ) {
366              
367 4         14 load $class;
368 4 50       425 my $converter = $class->new()
369             or croak "Cannot instantiate a ${class} object";
370              
371 4 50       384 if ( $converter->isa('Pod::Simple') ) {
372              
373 4         142 my $tmp_file = $self->output_file->stringify;
374              
375 4 50       108 close $self->output_fh
376             or croak "Unable to close file ${tmp_file}";
377              
378 4         460 $converter->output_fh( $self->translate_to_fh );
379 4         121 $converter->parse_file($tmp_file);
380              
381             }
382             else {
383              
384 0         0 croak "Don't know how to translate POD using ${class}";
385              
386             }
387              
388             }
389             }
390              
391             =head2 C
392              
393             Used to determine when the dependencies have been updated, and a
394             translation can be run.
395              
396             Note that this only returns a meaningful value after the POD has been
397             processed, since plugins may add to the dependencies. A side-effect
398             of this is that when generating a POD formatted F is that it
399             will always be updated, even when L is false.
400              
401             =cut
402              
403             sub dependencies_updated {
404 3     3 1 3936 my ($self) = @_;
405              
406 3         100 my $dest = $self->translate_to_file;
407              
408 3 50 33     133 if ( $dest and $self->input_file) {
409              
410 3 50       19 return 1 unless -e $dest;
411              
412 3         121 my $stat = $dest->stat;
413 3 50       23155 return 1 unless $stat;
414              
415 3         63 my $time = $stat->mtime;
416 3     6   116 return any { $_->mtime > $time } ( map { $_->stat } $self->depends_on );
  6         585  
  6         433  
417              
418             }
419             else {
420 0         0 return 1;
421             }
422             }
423              
424             =head2 C
425              
426             This method runs C and then L.
427              
428             =cut
429              
430             around 'run' => sub {
431             my ( $orig, $self ) = @_;
432             $self->$orig();
433             if ( $self->force or $self->dependencies_updated ) {
434             $self->translate_file();
435             }
436             };
437              
438             =head2 C
439              
440             my $parser = Pod::Readme->new();
441             $parser->parse_from_file( 'README.pod', 'README' );
442              
443             Pod::Readme->parse_from_file( 'README.pod', 'README' );
444              
445             This is a class method that acts as a L compatibility
446             shim for software that is designed for versions of L
447             prior to v1.0.
448              
449             Its use is deprecated, and will be deleted in later versions.
450              
451             =cut
452              
453             sub parse_from_file {
454 2     2 1 5527 my ( $self, $source, $dest ) = @_;
455              
456 2   100     12 my $class = ref($self) || __PACKAGE__;
457 2         52 my $prf = $class->new(
458             input_file => $source,
459             translate_to_file => $dest,
460             translation_class => 'Pod::Simple::Text',
461             force => 1,
462             );
463 2         95 $prf->run();
464             }
465              
466             =head2 C
467              
468             Like L, this exists as a compatibility shim.
469              
470             Its use is deprecated, and will be deleted in later versions.
471              
472             =cut
473              
474             sub parse_from_filehandle {
475 2     2 1 5098 my ( $self, $source_fh, $dest_fh ) = @_;
476              
477 2   100     11 my $class = ref($self) || __PACKAGE__;
478              
479 2 50       17 my $src_io =
480             IO::Handle->new_from_fd( ( defined $source_fh ) ? fileno($source_fh) : 0,
481             'r' );
482              
483 2 50       187 my $dest_io =
484             IO::Handle->new_from_fd( ( defined $dest_fh ) ? fileno($dest_fh) : 1,
485             'w' );
486              
487 2         201 my $prf = $class->new(
488             input_fh => $src_io,
489             translate_to_fh => $dest_io,
490             translation_class => 'Pod::Simple::Text',
491             force => 1,
492             );
493 2         90 $prf->run();
494             }
495              
496 4     4   1907 use namespace::autoclean;
  4         54929  
  4         18  
497              
498             1;
499              
500             =for readme start
501              
502             =head1 CAVEATS
503              
504             This module is intended to be used by module authors for their own
505             modules. It is not recommended for generating F files from
506             arbitrary Perl modules from untrusted sources.
507              
508             =head1 SEE ALSO
509              
510             See L, L and L.
511              
512             =head1 AUTHORS
513              
514             The original version was by Robert Rothenberg until
515             2010, when maintenance was taken over by David Precious
516             .
517              
518             In 2014, Robert Rothenberg rewrote the module to use filtering instead
519             of subclassing a POD parser.
520              
521             =head2 Acknowledgements
522              
523             Thanks to people who gave feedback and suggestions to posts about the
524             rewrite of this module on L.
525              
526             =head2 Suggestions, Bug Reporting and Contributing
527              
528             This module is developed on GitHub at
529             L
530              
531             =head1 LICENSE
532              
533             Copyright (c) 2005-2014 Robert Rothenberg. All rights reserved.
534             This program is free software; you can redistribute it and/or
535             modify it under the same terms as Perl itself.
536              
537             =cut