File Coverage

blib/lib/Pod/Loom.pm
Criterion Covered Total %
statement 61 64 95.3
branch 19 24 79.1
condition 6 9 66.6
subroutine 12 13 92.3
pod 1 1 100.0
total 99 111 89.1


line stmt bran cond sub pod time code
1             #---------------------------------------------------------------------
2             package Pod::Loom;
3             #
4             # Copyright 2009 Christopher J. Madsen
5             #
6             # Author: Christopher J. Madsen <perl@cjmweb.net>
7             # Created: October 6, 2009
8             #
9             # This program is free software; you can redistribute it and/or modify
10             # it under the same terms as Perl itself.
11             #
12             # This program is distributed in the hope that it will be useful,
13             # but WITHOUT ANY WARRANTY; without even the implied warranty of
14             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the
15             # GNU General Public License or the Artistic License for more details.
16             #
17             # ABSTRACT: Weave pseudo-POD into real POD
18             #---------------------------------------------------------------------
19              
20 2     2   58176 use 5.008;
  2         6  
  2         93  
21             our $VERSION = '0.08';
22             # This file is part of Pod-Loom 0.08 (March 23, 2014)
23              
24 2     2   1052 use Moose 0.65; # attr fulfills requires
  2         705703  
  2         14  
25 2     2   11109 use Carp qw(croak);
  2         4  
  2         112  
26 2     2   1309 use PPI ();
  2         177934  
  2         65  
27 2     2   854 use String::RewritePrefix ();
  2         1597  
  2         1172  
28              
29             #=====================================================================
30             {
31             package Pod::Loom::_EventCounter;
32             our @ISA = 'Pod::Eventual';
33             sub new {
34 14     14   484 require Pod::Eventual;
35 14         9890 my $events = 0;
36 14         33 bless \$events => shift;
37             }
38              
39 0     0   0 sub handle_event { ++${$_[0]} }
  0         0  
40 14     14   17 sub events { ${ +shift } }
  14         77  
41             }
42              
43             #=====================================================================
44             # Package Pod::Loom:
45              
46             has template => (
47             is => 'rw',
48             isa => 'Str',
49             default => 'Default',
50             );
51             #=====================================================================
52              
53              
54             sub weave
55             {
56 14     14 1 3894 my ($self, $docRef, $filename, $data) = @_;
57              
58 14         115 my $ppi = PPI::Document->new($docRef);
59              
60 14 100       9557 my $sourcePod = join("\n", @{ $ppi->find('PPI::Token::Pod') || [] });
  14         48  
61              
62 14         2932 $ppi->prune('PPI::Token::Pod');
63              
64 14 50       3122 croak "Can't use Pod::Loom on $filename: there is POD inside string literals"
65             if $self->_has_pod_events("$ppi");
66              
67              
68             # Determine the template to use:
69 14         343 my $templateClass = $self->template;
70              
71 14 50       40 if ($sourcePod =~ /^=for \s+ Pod::Loom-template \s+ (\S+)/mx) {
72 0         0 $templateClass = $1;
73             }
74              
75 14         98 $templateClass = String::RewritePrefix->rewrite(
76             {'=' => q{}, q{} => 'Pod::Loom::Template::'},
77             $templateClass
78             );
79              
80             # Instantiate the template and let it weave the new POD:
81 14 50       706 croak "Invalid class name $templateClass"
82             unless $templateClass =~ /^[:_A-Z0-9]+$/i;
83 14 50       638 eval "require $templateClass;" or croak "Unable to load $templateClass: $@";
84              
85              
86 14         410 my $template = $templateClass->new($data);
87              
88 14         53 my $newPod = $template->weave(\$sourcePod, $filename);
89 14         1139 $newPod =~ s/(?:\s*\n=cut)*\s*\z/\n\n=cut\n/; # ensure it ends with =cut
90 14 100       50 $newPod = '' if $newPod =~ /^\s*=cut$/; # if it's blank, ignore it
91              
92             # Plug the new POD back into the code:
93              
94 14         10 my $end = do {
95 14         57 my $end_elem = $ppi->find('PPI::Statement::Data');
96              
97 14 100       2584 unless ($end_elem) {
98 13         32 $end_elem = $ppi->find('PPI::Statement::End');
99              
100             # If there's nothing after __END__, we can put the POD there:
101 13 100 33     2027 if (not $end_elem or (@$end_elem == 1 and
      66        
102             $end_elem->[0] =~ /^__END__\s*\z/)) {
103 12         24 $end_elem = [];
104             } # end if no significant text after __END__
105             } # end unless found __DATA__
106              
107 14 100       54 @$end_elem ? join q{}, @$end_elem : undef;
108             };
109              
110 14         61 $ppi->prune('PPI::Statement::End');
111 14         2317 $ppi->prune('PPI::Statement::Data');
112              
113 14         2221 my $docstr = $ppi->serialize;
114 14         473 $docstr =~ s/\n*\z/\n/; # ensure it ends with one LF
115              
116 14 100 100     381 return $newPod if $docstr eq "\n" and not defined $end; # Pure POD file
117              
118 3 100       108 return defined $end
119             ? "$docstr\n$newPod\n$end"
120             : "$docstr\n__END__\n\n$newPod";
121             } # end weave_document
122              
123             #---------------------------------------------------------------------
124             sub _has_pod_events
125             {
126 14     14   214 my $pe = Pod::Loom::_EventCounter->new;
127             # We can't use read_string, because that treats the string as
128             # encoded in UTF-8, for which some byte sequences aren't valid.
129 14 50   1   213 open my $handle, '<:encoding(iso-8859-1)', \$_[1]
  1     1   6  
  1         1  
  1         22  
  1         769  
  1         1  
  1         4  
130             or die "error opening string for reading: $!";
131 14         1063 $pe->read_handle($handle);
132              
133 14         1164 $pe->events;
134             } # end _has_pod_events
135              
136             #=====================================================================
137             # Package Return Value:
138              
139 2     2   12 no Moose;
  2         3  
  2         15  
140             __PACKAGE__->meta->make_immutable;
141             1;
142              
143             __END__
144              
145             =head1 NAME
146              
147             Pod::Loom - Weave pseudo-POD into real POD
148              
149             =head1 VERSION
150              
151             This document describes version 0.08 of
152             Pod::Loom, released March 23, 2014
153             as part of Pod-Loom version 0.08.
154              
155             =head1 WARNING
156              
157             This code is still in flux. Use it at your own risk, and be prepared
158             to adapt to changes. The POD syntax should be fairly stable, but if
159             you write your own templates, they might need to change.
160              
161             =head1 SYNOPSIS
162              
163             use Pod::Loom;
164              
165             my $document = ...; # Text of Perl program including POD
166             my $filename = "filename/of/document.pm"; # For messages
167             my %data = ...; # Configuration required by template
168              
169             my $loom = Pod::Loom->new(template => 'Custom');
170             my $new_doc = $loom->weave(\$document, $filename, \%data);
171              
172             =head1 DESCRIPTION
173              
174             Pod::Loom extracts all the POD sections from Perl code, passes the POD
175             to a template that may reformat it in various ways, and then returns a
176             copy of the code with the reformatted POD at the end.
177              
178             A template may convert non-standard POD commands like C<=method> and
179             C<=attr> into standard POD, reorder sections, and generally do
180             whatever it likes to the POD.
181              
182             The document being reformatted can specify the template to use with a
183             line like this:
184              
185             =for Pod::Loom-template TEMPLATE_NAME
186              
187             Otherwise, you can specify the template in the Pod::Loom constructor:
188              
189             $loom = Pod::Loom->new(template => TEMPLATE_NAME);
190              
191             TEMPLATE_NAME is automatically prefixed with C<Pod::Loom::Template::>
192             to form a class name. If you want to use a template outside that
193             namespace, prefix the class name with C<=> to indicate that.
194              
195             =head1 METHODS
196              
197             =head2 new
198              
199             $loom = Pod::Loom->new(template => TEMPLATE_NAME);
200              
201             Constructs a new Pod::Loom. The C<template> parameter is optional; it
202             defaults to C<Default> (meaning L<Pod::Loom::Template::Default>).
203              
204              
205              
206             =head2 weave
207              
208             $new_doc = $loom->weave(\$doc, $filename, $data);
209              
210             This method does all the work (see L</"DESCRIPTION">). You pass it a
211             reference to a string containing Perl code mixed with POD. (This
212             string is not modified.) It returns a new string containing the
213             reformatted POD moved to the end of the code. C<$doc> should contain
214             raw bytes (i.e. UTF8 flag off). If C<$doc> is encoded in something
215             other than Latin-1, it must contain an C<=encoding> directive
216             specifying the encoding. C<$new_doc> will likewise contain raw bytes
217             in the same encoding as C<$doc>.
218              
219             The C<$filename> is used for error messages. It does not need to
220             actually exist on disk.
221              
222             C<$data> is passed as the only argument to the template class's
223             constructor (which must be named C<new>). Pod::Loom does not inspect
224             it, but for consistency and compatibility between templates it should
225             be a hashref.
226              
227             =head1 REQUIREMENTS OF A TEMPLATE CLASS
228              
229             A template class must have a constructor named C<new> and a method
230             named C<weave> that matches the one in L<Pod::Loom::Template>. It
231             should be in the C<Pod::Loom::Template::> namespace (to make it easy
232             to specify the template name), but it does not need to be a subclass
233             of Pod::Loom::Template.
234              
235             =head1 DIAGNOSTICS
236              
237             Pod::Loom may generate the following error messages, in addition to
238             whatever errors the template class generates.
239              
240              
241              
242             =over
243              
244             =item C<< Can't use Pod::Loom on %s: there is POD inside string literals >>
245              
246             You have POD commands inside a string literal (probably a here doc).
247             Since Pod::Loom moves all POD to the end of the file, running it on
248             your program would change its behavior. Move the POD outside the
249             string, or quote any equals sign at the beginning of a line so it no
250             longer looks like POD.
251              
252              
253             =item C<< Invalid class name %s >>
254              
255             A template name may only contain ASCII alphanumerics and underscore.
256              
257              
258             =item C<< Unable to load %s: %s >>
259              
260             Pod::Loom got an error when it tried to C<require> your template class.
261              
262              
263              
264             =back
265              
266             =head1 CONFIGURATION AND ENVIRONMENT
267              
268             Pod::Loom requires no configuration files or environment variables.
269              
270             =head1 DEPENDENCIES
271              
272             Pod::Loom depends on L<Moose>, L<Pod::Eventual>, L<PPI>, and
273             L<String::RewritePrefix>, which can be found on CPAN. The template
274             class may have additional dependencies.
275              
276             =head1 INCOMPATIBILITIES
277              
278             None reported.
279              
280             =head1 BUGS AND LIMITATIONS
281              
282             No bugs have been reported.
283              
284             =head1 AUTHOR
285              
286             Christopher J. Madsen S<C<< <perl AT cjmweb.net> >>>
287              
288             Please report any bugs or feature requests
289             to S<C<< <bug-Pod-Loom AT rt.cpan.org> >>>
290             or through the web interface at
291             L<< http://rt.cpan.org/Public/Bug/Report.html?Queue=Pod-Loom >>.
292              
293             You can follow or contribute to Pod-Loom's development at
294             L<< https://github.com/madsen/pod-loom >>.
295              
296             =head1 COPYRIGHT AND LICENSE
297              
298             This software is copyright (c) 2014 by Christopher J. Madsen.
299              
300             This is free software; you can redistribute it and/or modify it under
301             the same terms as the Perl 5 programming language system itself.
302              
303             =head1 DISCLAIMER OF WARRANTY
304              
305             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
306             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
307             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
308             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
309             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
310             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
311             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
312             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
313             NECESSARY SERVICING, REPAIR, OR CORRECTION.
314              
315             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
316             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
317             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENSE, BE
318             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
319             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
320             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
321             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
322             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
323             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
324             SUCH DAMAGES.
325              
326             =cut