File Coverage

blib/lib/Pod/Loom/Parser.pm
Criterion Covered Total %
statement 62 70 88.5
branch 19 32 59.3
condition 10 20 50.0
subroutine 12 12 100.0
pod 6 6 100.0
total 109 140 77.8


line stmt bran cond sub pod time code
1             #---------------------------------------------------------------------
2             package Pod::Loom::Parser;
3             #
4             # Copyright 2009 Christopher J. Madsen
5             #
6             # Author: Christopher J. Madsen <perl@cjmweb.net>
7             # Created: 6 Oct 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: Subclass Pod::Eventual for Pod::Loom
18             #---------------------------------------------------------------------
19              
20 1     1   15 use 5.008;
  1         2  
  1         44  
21             our $VERSION = '0.05';
22             # This file is part of Pod-Loom 0.08 (March 23, 2014)
23              
24 1     1   4 use strict;
  1         1  
  1         27  
25 1     1   3 use warnings;
  1         1  
  1         69  
26              
27 1     1   5 use Encode qw(find_encoding);
  1         1  
  1         51  
28 1     1   5 use Pod::Eventual ();
  1         1  
  1         698  
29             our @ISA = qw(Pod::Eventual);
30             #---------------------------------------------------------------------
31              
32              
33             sub new
34             {
35 13     13 1 13 my ($class, $collectCommands) = @_;
36              
37 13         28 my %collect = map { $_ => [] } @$collectCommands;
  65         102  
38 13         25 my %groups = map { $_ => {} } @$collectCommands;
  65         78  
39              
40 13         70 bless {
41             collect => \%collect,
42             dest => undef,
43             groups => \%groups,
44             }, $class;
45             } # end new
46              
47             #---------------------------------------------------------------------
48             sub _handle_encoding
49             {
50 2     2   4 my ($self, $event) = @_;
51              
52 2         4 my $encoding = $event->{content};
53              
54 2         4 $encoding =~ s/^\s+//;
55 2         11 $encoding =~ s/\s+\z//;
56              
57 2 50       7 my $e = find_encoding($encoding)
58             or die "Invalid =encoding $encoding at line $event->{start_line}\n";
59              
60 2 50       402 if (defined $self->{encoding}) {
61 0 0       0 return if $e->name eq $self->{encoding}->name;
62 0         0 die "Conflicting =encoding directive at line $event->{start_line}\n";
63             }
64              
65 2         6 $self->{encoding} = $e;
66             } # end _handle_encoding
67              
68             #---------------------------------------------------------------------
69             sub handle_event
70             {
71 46     46 1 5533 my ($self, $event) = @_;
72              
73 46         51 my $dest = $self->{dest};
74              
75 46 100       89 if ($event->{type} eq 'command') {
76 23         28 my $cmd = $event->{command};
77 23 100       53 return if $cmd eq 'cut';
78              
79 21 100       43 return $self->_handle_encoding($event) if $cmd eq 'encoding';
80              
81             # See if this changes the output location:
82 19         37 my $collector = $self->{collect}{ $cmd };
83              
84 19 50 66     81 if (not $collector and $cmd =~ /^(\w+)-(\S+)/ and $self->{collect}{$1}) {
      33        
85 0         0 $collector = $self->{collect}{$cmd} = [];
86 0         0 $self->{groups}{$1}{$2} = 1;
87             } # end if new group
88              
89             # Special handling for Pod::Loom sections:
90 19 100 66     184 if ($cmd =~ /^(begin|for)$/ and
    50 33        
91             $event->{content} =~ s/^\s*(Pod::Loom\b\S*)\s*//) {
92 12   50     64 $collector = ($self->{collect}{$1} ||= []);
93 12 50       26 if ($cmd eq 'for') {
94 12         20 push @$collector, $event->{content};
95 12         32 return;
96             }
97 0         0 undef $cmd;
98             } elsif ($cmd eq 'end' and
99             $event->{content} =~ /^\s*Pod::Loom\b/) {
100             # Handle =end Pod::Loom:
101 0         0 $self->{dest} = undef;
102 0         0 return;
103             }
104              
105             # Either set output location, or make sure we have one:
106 7 50       11 if ($collector) {
107 7         13 push @$collector, '';
108 7         14 $dest = $self->{dest} = \$collector->[-1];
109             } else {
110 0 0       0 die "=$cmd used too soon at line $event->{start_line}\n" unless $dest;
111             }
112              
113 7 50       14 if ($cmd) {
114 7         13 $$dest .= "=$cmd";
115 7 50       22 $$dest .= ' ' unless $event->{content} =~ /^\n/;
116             }
117             } # end if command event
118              
119 30         60 $$dest .= $event->{content};
120             } # end handle_event
121              
122             #---------------------------------------------------------------------
123             sub handle_blank
124             {
125 16     16 1 1114 my ($self, $event) = @_;
126              
127 16 100       39 if ($self->{dest}) {
128 14         17 $event->{type} = 'text';
129 14         24 $self->handle_event($event);
130             }
131             } # end handle_blank
132             #---------------------------------------------------------------------
133              
134              
135             sub collected
136             {
137 13     13 1 18 my ($self) = @_;
138              
139 13         27 my $collected = $self->{collect};
140 13   66     51 my $encoding = $self->{encoding} ||= find_encoding('iso-8859-1');
141              
142 13 50       131 unless ($self->{collect_decoded}++) {
143 13         36 for my $array (values %$collected) {
144 77         96 for my $value (@$array) {
145 19         94 $value = $encoding->decode($value);
146             }
147             }
148             }
149              
150 13         390 $collected;
151             } # end collected
152              
153             #---------------------------------------------------------------------
154              
155              
156 13   33 13 1 365 sub encoding { shift->{encoding} ||= find_encoding('iso-8859-1') }
157             #---------------------------------------------------------------------
158              
159              
160 13     13 1 334 sub groups { shift->{groups} }
161              
162             #=====================================================================
163             # Package Return Value:
164              
165             1;
166              
167             __END__
168              
169             =head1 NAME
170              
171             Pod::Loom::Parser - Subclass Pod::Eventual for Pod::Loom
172              
173             =head1 VERSION
174              
175             This document describes version 0.05 of
176             Pod::Loom::Parser, released March 23, 2014
177             as part of Pod-Loom version 0.08.
178              
179             =head1 SYNOPSIS
180              
181             use Pod::Loom::Parser;
182              
183             my $parser = Pod::Loom::Parser->new( ['head1'] );
184             $parser->read_file('lib/Foo/Bar.pm');
185             my $collectedHash = $parser->collected;
186              
187             foreach my $block (@{ $collectedHash->{head1} }) {
188             printf "---\n%s\n", $block;
189             }
190              
191             =head1 DESCRIPTION
192              
193             Pod::Loom::Parser is a subclass of L<Pod::Eventual> intended for use
194             by L<Pod::Loom::Template>. It breaks the POD into chunks based on a
195             list of POD commands. Each chunk begins with one of the commands, and
196             contains all the POD up until the next selected command.
197              
198             The commands do not need to be valid POD commands. You can invent
199             commands like C<=attr> or C<=method>.
200              
201             =head1 METHODS
202              
203             See L<Pod::Eventual> for the C<read_handle>, C<read_file>, and
204             C<read_string> methods, which you use to feed POD into the parser.
205              
206             =head2 new
207              
208             $parser = Pod::Loom::Parser->new(\@collect_commands);
209              
210             Constructs a new Pod::Loom::Parser. You pass it an arrayref of the
211             POD commands at which the POD should be chopped.
212              
213              
214             =head2 collected
215              
216             $hashRef = $parser->collected;
217              
218             This returns the POD chunks that the document was chopped into. There
219             is one entry for each of the C<@collect_commands> that were passed to
220             the constructor. The value is an arrayref of strings, one for each
221             time that command appeared in the document. Each chunk contains all
222             the text from the command up to (but not including) the command that
223             started the next chunk. Chunks appear in document order.
224              
225             If one of the commands did not appear in the document, its value will
226             be an empty arrayref.
227              
228             In addition, any POD targeted to a format matching C</^Pod::Loom\b/>
229             will be collected under the format name.
230              
231              
232             =head2 encoding
233              
234             $encoding = $parser->encoding;
235              
236             This returns the encoding that was used for the document as an
237             L<Encode> object. If no encoding was explicitly defined, then the
238             default Latin-1 encoding is returned.
239              
240              
241             =head2 groups
242              
243             $hashRef = $parser->groups;
244              
245             This returns a hashref with one entry for each of the
246             C<@collect_commands>. Each value is a hashref whose keys are the
247             categories used with that command. For example, if C<attr> was a
248             collected command, and the document contained these entries:
249              
250             =attr-foo attr1
251             =attr-bar attr2
252             =attr-foo attr3
253             =attr attr4
254              
255             then C<< keys %{ $parser->groups->{attr} } >> would return C<bar> and
256             C<foo>. (The C<=attr> without a category does not get an entry in
257             this hash.)
258              
259             =head1 CONFIGURATION AND ENVIRONMENT
260              
261             Pod::Loom::Parser requires no configuration files or environment variables.
262              
263             =head1 DEPENDENCIES
264              
265             Pod::Loom::Parser requires L<Pod::Eventual>, which can be found on CPAN.
266              
267             =head1 INCOMPATIBILITIES
268              
269             None reported.
270              
271             =head1 BUGS AND LIMITATIONS
272              
273             No bugs have been reported.
274              
275             =head1 AUTHOR
276              
277             Christopher J. Madsen S<C<< <perl AT cjmweb.net> >>>
278              
279             Please report any bugs or feature requests
280             to S<C<< <bug-Pod-Loom AT rt.cpan.org> >>>
281             or through the web interface at
282             L<< http://rt.cpan.org/Public/Bug/Report.html?Queue=Pod-Loom >>.
283              
284             You can follow or contribute to Pod-Loom's development at
285             L<< https://github.com/madsen/pod-loom >>.
286              
287             =head1 COPYRIGHT AND LICENSE
288              
289             This software is copyright (c) 2014 by Christopher J. Madsen.
290              
291             This is free software; you can redistribute it and/or modify it under
292             the same terms as the Perl 5 programming language system itself.
293              
294             =head1 DISCLAIMER OF WARRANTY
295              
296             BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
297             FOR THE SOFTWARE, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
298             OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
299             PROVIDE THE SOFTWARE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
300             EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
301             WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
302             ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH
303             YOU. SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
304             NECESSARY SERVICING, REPAIR, OR CORRECTION.
305              
306             IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
307             WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
308             REDISTRIBUTE THE SOFTWARE AS PERMITTED BY THE ABOVE LICENSE, BE
309             LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL,
310             OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE
311             THE SOFTWARE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
312             RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
313             FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
314             SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
315             SUCH DAMAGES.
316              
317             =cut