File Coverage

blib/lib/Pod/Abstract/Parser.pm
Criterion Covered Total %
statement 130 135 96.3
branch 36 44 81.8
condition 13 20 65.0
subroutine 13 13 100.0
pod 3 8 37.5
total 195 220 88.6


line stmt bran cond sub pod time code
1             package Pod::Abstract::Parser;
2 6     6   42 use strict;
  6         12  
  6         347  
3              
4 6     6   38 use Pod::Parser;
  6         11  
  6         296  
5 6     6   35 use Pod::Abstract::Node;
  6         12  
  6         166  
6 6     6   28 use Data::Dumper;
  6         11  
  6         452  
7 6     6   39 use base qw(Pod::Parser);
  6         12  
  6         15038  
8              
9             our $VERSION = '0.26';
10              
11             =head1 NAME
12              
13             Pod::Abstract::Parser - Internal Parser class of Pod::Abstract.
14              
15             =head1 DESCRIPTION
16              
17             This is a C subclass, used by C to convert Pod
18             text into a Node tree.
19              
20             Use this class via the L class which has "load" methods
21             provided.
22              
23             =head1 METHODS
24              
25             =head2 new
26              
27             Pod::Abstract::Parser->new( $pod_abstract );
28              
29             Requires a Pod::Abstract object to load Pod data into. Should only be
30             called internally by L.
31              
32             This is a subclass of L and uses that class to handle all basic Pod
33             parsing, but implements the additional rules from L that require
34             more context.
35              
36             =cut
37              
38             sub new {
39 45     45 1 77 my $class = shift;
40 45         84 my $p_a = shift;
41            
42             # Always accept non-POD paras, so that the input document can
43             # always be reproduced exactly as entered. These will be stored in
44             # the tree but will be available through distinct methods.
45 45         446 my $self = $class->SUPER::new();
46 45         615 $self->parseopts(
47             -want_nonPODs => 1,
48             -process_cut_cmd => 1,
49             );
50 45         141 $self->{pod_abstract} = $p_a;
51 45         183 my $root_node = Pod::Abstract::Node->new(
52             type => "[ROOT]",
53             );
54 45         143 $self->{cmd_stack} = [ $root_node ];
55 45         126 $self->{root} = $root_node;
56            
57 45         134 return $self;
58             }
59              
60             sub root {
61 44     44 0 83 my $self = shift;
62 44         343 return $self->{root};
63             }
64              
65             # Automatically nest these items: A head1 section continues until the
66             # next head1, list items continue until the next item or end of list,
67             # etc. POD doesn't specify these relationships, but they are natural
68             # and make sense in the whole document context.
69             #
70             # SPECIAL: Start node with < to pull the end node out of the tree and
71             # into the opening node - e.g, pull a "back" into an "over", but not
72             # into an "item". Pulling a command stops it from closing any more
73             # elements, so begin/end style blocks need to use a pull, or one end
74             # will close all begins.
75             my %section_commands = (
76             'head1' => [ 'head1' ],
77             'head2' => [ 'head2', 'head1' ],
78             'head3' => [ 'head3', 'head2', 'head1' ],
79             'head4' => [ 'head4', 'head3', 'head2', 'head1' ],
80             'head5' => [ 'head5', 'head4', 'head3', 'head2', 'head1' ],
81             'head6' => [ 'head6', 'head5', 'head4', 'head3', 'head2', 'head1' ],
82             'over' => [ '
83             'item' => [ 'item', 'back' ],
84             'begin' => [ '
85             );
86              
87             # Don't parse anything inside these. But there are some special cases where you
88             # might need to - see "parse_me"
89             my %no_parse = (
90             'begin' => 1,
91             'for' => 1,
92             );
93              
94             my %attr_names = (
95             head1 => 'heading',
96             head2 => 'heading',
97             head3 => 'heading',
98             head4 => 'heading',
99             item => 'label',
100             );
101              
102             sub command {
103 54     54 0 217 my ($self, $command, $paragraph, $line_num) = @_;
104 54   50     186 my $cmd_stack = $self->{cmd_stack} || [ ];
105            
106 54         96 my $p_break = "\n\n";
107 54 100       338 if($paragraph =~ s/([ \t]*\n[ \t]*\n)$//s) {
108 37         95 $p_break = $1;
109             }
110            
111 54 100       204 if($self->cutting) {
112             # Treat as non-pod - i.e, verbatim program text block.
113 7 50       39 my $element_node = Pod::Abstract::Node->new(
114             type => "#cut",
115             body => ($paragraph ? "=$command $paragraph$p_break" : "=$command$p_break"),
116             );
117 7         17 my $top = $cmd_stack->[$#$cmd_stack];
118 7         22 $top->push($element_node);
119             } else {
120             # Treat as command.
121 47         115 my $pull = undef;
122 47         123 while(@$cmd_stack > 0) {
123 77         161 my $last = scalar(@$cmd_stack) - 1;
124 77         131 my @should_end = ( );
125             @should_end =
126 92         268 grep { $command eq $_ }
127 77         155 @{$section_commands{$cmd_stack->[$last]->type}};
  77         252  
128 77         128 my @should_pull = ( );
129             @should_pull =
130 92         214 grep { "<$command" eq $_ }
131 77         125 @{$section_commands{$cmd_stack->[$last]->type}};
  77         172  
132 77 100       232 if(@should_end) {
    100          
133 30         117 my $end_cmd = pop @$cmd_stack;
134             } elsif(@should_pull) {
135 6         14 $pull = pop @$cmd_stack;
136 6         68 last;
137             } else {
138 41         93 last;
139             }
140             }
141            
142             # Don't do anything special if we're on a no_parse node
143 47         101 my $top = $cmd_stack->[$#$cmd_stack];
144 47 50 33     116 if($no_parse{$top->type} && !$top->param('parse_me')) {
145 0 0       0 my $t_node = Pod::Abstract::Node->new(
146             type => ':text',
147             body => ($paragraph ne '' ?
148             "=$command $paragraph$p_break" :
149             "=$command$p_break"),
150             );
151 0         0 $top->push($t_node);
152 0         0 return;
153             }
154            
155             # Some commands have to get expandable interior sequences
156 47         90 my $attr_node = undef;
157 47         99 my $attr_name = $attr_names{$command};
158 47         133 my %attr = ( parse_me => 0 );
159 47 100 100     194 if($attr_name) {
    100          
160 33         106 $attr_node = Pod::Abstract::Node->new(
161             type => '@attribute',
162             );
163 33         117 $paragraph =~ s/[\s\n\r]+/ /g;
164 33         1605 my $pt = $self->parse_text($paragraph);
165 33         136 $self->load_pt($attr_node, $pt);
166 33         88 $attr{$attr_name} = $attr_node;
167 33         326 $attr{body_attr} = $attr_name;
168             } elsif($command =~ m/^(begin|for)$/ && $paragraph =~ m/^\:/) {
169             # In the case of begin/for, the format name is the first word and if
170             # it begins with : then the internal POD should be parsed.
171 2         6 $attr{parse_me} = 1;
172             }
173              
174 47         115 my $for_para = undef;
175 47 100       123 if($command eq 'for') {
176             # Special case for =for - POD rules are nonsense, so the first
177             # *word* is the formatter (we will treat as body), and the
178             # following words are either a child text, or possibly interior
179             # sequences that need to be parsed.
180 2         11 my ($formatter, $rest) = split /\s/,$paragraph,2;
181 2         6 $paragraph = $formatter;
182 2         5 $for_para = $rest;
183             }
184              
185            
186 47 100       232 my $element_node = Pod::Abstract::Node->new(
187             type => $command,
188             body => ($attr_name ? undef : $paragraph),
189             p_break => $p_break,
190             %attr,
191             );
192              
193 47 100 66     169 if( $command eq 'for' && $for_para ) {
194             # Special handling for =for - the "paragraph" has been split from
195             # the formatter, and may or may not need parsing.
196 2 100       6 if( $attr{parse_me} ) {
197 1         105 my $pt = $self->parse_text($for_para);
198 1         6 $self->load_pt($element_node, $pt);
199             } else {
200 1         4 my $t_node = Pod::Abstract::Node->new(
201             type => ':text',
202             body => $for_para,
203             );
204 1         4 $element_node->push($t_node);
205             }
206             }
207              
208 47 100       101 if($pull) {
209 6         24 $pull->param('close_element', $element_node);
210             } else {
211 41         126 $top->push($element_node);
212             }
213 47 100       153 if($section_commands{$command}) {
214 39         139 push @$cmd_stack, $element_node;
215             } else {
216             # No push
217             }
218             }
219            
220 54         1538 $self->{cmd_stack} = $cmd_stack;
221             }
222              
223             =head2 verbatim
224              
225             In general, a verbatim node is created as any indented text in a POD block.
226             However, there's a special case which is that -
227              
228             =over
229              
230             =item *
231              
232             If we are in a "begin/end" block, that's by default not parsed, and this should
233             be text, not verbatim.
234              
235             =item *
236              
237             B if we are in a parsed begin/end block (C) it should still be a
238             verbatim node.
239              
240             =back
241              
242             The behaviour here is very much a DWIM - if you're in a non-parsed block this
243             will interpret it correctly even though C will tell you it's a
244             verbatim. If you're in a parsed block it will be a C<:text>.
245              
246             This would be verbatim.
247              
248             =begin example
249              
250             But if this command was at the start of the line, this would be non-parsed
251             and would instead be a text node.
252              
253             =end
254              
255             =cut
256              
257             sub verbatim {
258 23     23 1 57 my ($self, $paragraph, $line_num) = @_;
259            
260 23         43 my $cmd_stack = $self->{cmd_stack};
261 23         114 my $top = $cmd_stack->[$#$cmd_stack];
262              
263 23         45 my $type = ':verbatim';
264 23 50 33     86 if($no_parse{$top->type} && !$top->param('parse_me')) {
265 0         0 $type = ':text';
266             }
267            
268 23         71 my $element_node = Pod::Abstract::Node->new(
269             type => ':verbatim',
270             body => $paragraph,
271             );
272 23         58 $top->push($element_node);
273             }
274              
275             sub preprocess_paragraph {
276 164     164 0 5336 my ($self, $text, $line_num) = @_;
277 164 100       4057 return $text unless $self->cutting;
278            
279             # This is a non-pod text segment
280 23         131 my $element_node = Pod::Abstract::Node->new(
281             type => "#cut",
282             body => $text,
283             );
284 23         52 my $cmd_stack = $self->{cmd_stack};
285 23         52 my $top = $cmd_stack->[$#$cmd_stack];
286 23         71 $top->push($element_node);
287             }
288              
289             =head2 textblock
290              
291             Textblock handling as C class - we are keeping a command stack
292             which lets us know if we should parse the interior sequences of the text block -
293             the C<< B >> style commands. In some cases L
294             requires them to be ignored, and in some cases they should be parsed.
295              
296             The C<%no_parse> hash defines commands that generally shouldn't be parsed, but
297             the command parser may add a parameter C to the command which will
298             cause their text to be parsed as normal POD text.
299              
300             =cut
301              
302             sub textblock {
303 64     64 1 190 my ($self, $paragraph, $line_num) = @_;
304 64         115 my $p_break = "\n\n";
305 64 50       766 if($paragraph =~ s/([ \t]*\n[ \t]*\n)$//s) {
306 64         217 $p_break = $1;
307             }
308 64         138 my $cmd_stack = $self->{cmd_stack};
309 64         136 my $top = $cmd_stack->[$#$cmd_stack];
310 64 100 100     222 if($no_parse{$top->type} && !$top->param('parse_me')) {
311 1         7 my $element_node = Pod::Abstract::Node->new(
312             type => ':text',
313             body => "$paragraph$p_break",
314             );
315 1         5 $top->push($element_node);
316 1         18 return;
317             }
318              
319 63         222 my $element_node = Pod::Abstract::Node->new(
320             type => ':paragraph',
321             p_break => $p_break,
322             );
323 63         5420 my $pt = $self->parse_text($paragraph);
324 63         294 $self->load_pt($element_node, $pt);
325              
326 63         175 $top->push($element_node);
327             }
328              
329             # Recursive load
330             sub load_pt {
331 182     182 0 303 my $self = shift;
332 182         319 my $elt = shift;
333 182         281 my $pt = shift;
334            
335 182         709 my @c = $pt->children;
336 182         407 foreach my $c(@c) {
337 267 100       563 if(ref $c) {
338             # Object;
339 51 50       247 if($c->isa('Pod::InteriorSequence')) {
340 51         279 my $cmd = $c->cmd_name;
341 51         396 my $i_node = Pod::Abstract::Node->new(
342             type => ":$cmd",
343             left_delimiter => $c->left_delimiter,
344             right_delimiter => $c->right_delimiter,
345             );
346 51         291 $self->load_pt($i_node, $c->parse_tree);
347 51         124 $elt->push($i_node);
348             } else {
349 0         0 die "$c not an interior sequence!";
350             }
351             } else {
352             # text
353 216         651 my $t_node = Pod::Abstract::Node->new(
354             type => ':text',
355             body => $c,
356             );
357 216         586 $elt->push($t_node);
358             }
359             }
360 182         620 return $elt;
361             }
362              
363             sub end_pod {
364 11     11 0 94 my $self = shift;
365 11         25 my $cmd_stack = $self->{cmd_stack};
366            
367 11         22 my $end_cmd;
368 11   66     63 while(defined $cmd_stack && @$cmd_stack) {
369 14         79 $end_cmd = pop @$cmd_stack;
370             }
371 11 50       44 die "Last node was not root node" unless $end_cmd->type eq '[ROOT]';
372            
373             # Replace the root node.
374 11         199 push @$cmd_stack, $end_cmd;
375             }
376              
377             =head1 AUTHOR
378              
379             Ben Lilburne
380              
381             =head1 COPYRIGHT AND LICENSE
382              
383             Copyright (C) 2009-2025 Ben Lilburne
384              
385             This program is free software; you can redistribute it and/or modify
386             it under the same terms as Perl itself.
387              
388             =cut
389              
390             1;