File Coverage

blib/lib/Pod/Tree.pm
Criterion Covered Total %
statement 112 149 75.1
branch 21 32 65.6
condition 1 3 33.3
subroutine 20 26 76.9
pod 13 13 100.0
total 167 223 74.8


line stmt bran cond sub pod time code
1             # Copyright (c) 1999-2009 by Steven McDougall. This module is free
2             # software; you can redistribute it and/or modify it under the same
3             # terms as Perl itself.
4              
5             package Pod::Tree;
6 18     18   676638 use 5.006;
  18         151  
7              
8 18     18   139 use strict;
  18         53  
  18         507  
9 18     18   106 use warnings;
  18         44  
  18         639  
10 18     18   5735 use IO::File;
  18         100682  
  18         2389  
11 18     18   9692 use Pod::Tree::Node;
  18         70  
  18         500  
12 18     18   7482 use Pod::Tree::Stream;
  18         45  
  18         12371  
13              
14             our $VERSION = '1.30';
15              
16             sub new {
17 84     84 1 47607 my $class = shift;
18 84         351 my $tree = {
19             loaded => 0,
20             paragraphs => []
21             };
22 84         258 bless $tree, $class;
23             }
24              
25             sub load_file {
26 75     75 1 305 my ( $tree, $file, %options ) = @_;
27              
28 75         414 Pod::Tree::Node->set_filename($file);
29              
30 75         361 my $fh = IO::File->new;
31 75 50       2796 $fh->open($file) or return '';
32 75         4000 $tree->load_fh( $fh, %options );
33              
34 75         275 Pod::Tree::Node->set_filename("");
35 75         1316 1;
36             }
37              
38             sub load_fh {
39 77     77 1 267 my ( $tree, $fh, %options ) = @_;
40              
41 77         632 $tree->{in_pod} = 0;
42 77         274 $tree->_load_options(%options);
43 77         176 my $limit = $tree->{limit};
44              
45 77         529 my $stream = Pod::Tree::Stream->new($fh);
46 77         158 my $paragraph;
47             my @paragraphs;
48 77         233 while ( $paragraph = $stream->get_paragraph ) {
49 2079         3686 push @paragraphs, $paragraph;
50 2079 50 33     9644 $limit and $limit == @paragraphs and last;
51             }
52              
53 77         277 $tree->{paragraphs} = \@paragraphs;
54 77         262 $tree->_parse;
55             }
56              
57             sub load_string {
58 5     5 1 30 my ( $tree, $string, %options ) = @_;
59              
60 5         193 my @chunks = split /( \n\s*\n | \r\s*\r | \r\n\s*\r\n )/x, $string;
61              
62 5         12 my (@paragraphs);
63 5         18 while (@chunks) {
64 167         411 push @paragraphs, join '', splice @chunks, 0, 2;
65             }
66              
67 5         23 $tree->load_paragraphs( \@paragraphs, %options );
68             }
69              
70             sub load_paragraphs {
71 7     7 1 23 my ( $tree, $paragraphs, %options ) = @_;
72              
73 7         16 $tree->{in_pod} = 1;
74 7         24 $tree->_load_options(%options);
75              
76 7         14 my $limit = $tree->{limit};
77 7         41 my @paragraphs = @$paragraphs;
78 7 50       18 $limit and splice @paragraphs, $limit;
79              
80 7         17 $tree->{paragraphs} = \@paragraphs;
81 7         17 $tree->_parse;
82             }
83              
84 51     51 1 168 sub loaded { shift->{'loaded'} }
85              
86             sub _load_options {
87 84     84   171 my ( $tree, %options ) = @_;
88              
89 84         133 my ( $key, $value );
90 84         372 while ( ( $key, $value ) = each %options ) {
91 4         16 $tree->{$key} = $value;
92             }
93             }
94              
95             sub _parse {
96 84     84   136 my $tree = shift;
97              
98 84         243 $tree->_make_nodes;
99 84         250 $tree->_make_for;
100 84         244 $tree->_make_sequences;
101              
102 84         180 my $root = $tree->{root};
103              
104 84         265 $root->parse_links;
105 84         286 $root->unescape;
106 84         326 $root->consolidate;
107 84         253 $root->make_lists;
108              
109 84         471 $tree->{'loaded'} = 1;
110             }
111              
112             sub _add_paragraph {
113 0     0   0 my ( $tree, $paragraph ) = @_;
114              
115 0         0 for ($paragraph) {
116 0 0       0 /^=cut/ and do {
117 0         0 $tree->{in_pod} = 0;
118 0         0 last;
119             };
120 0 0       0 $tree->{in_pod} and do {
121 0         0 push @{ $tree->{paragraphs} }, $paragraph;
  0         0  
122 0         0 last;
123             };
124 0 0       0 /^=\w/ and do {
125 0         0 $tree->{in_pod} = 1;
126 0         0 push @{ $tree->{paragraphs} }, $paragraph;
  0         0  
127 0         0 last;
128             };
129             }
130             }
131              
132             my %Command = map { $_ => 1 } qw(=pod =cut
133             =head1 =head2 =head3 =head4
134             =over =item =back
135             =for =begin =end);
136              
137             sub _make_nodes {
138 84     84   128 my $tree = shift;
139 84         136 my $paragraphs = $tree->{paragraphs};
140 84         148 my $in_pod = $tree->{in_pod};
141 84         128 my @children;
142              
143 84         211 for my $paragraph (@$paragraphs) {
144 2389         6545 my ($word) = split( /\s/, $paragraph );
145 2389         3346 my $node;
146              
147 2389 100       3605 if ($in_pod) {
148 2257 100       5313 if ( $paragraph =~ /^\s/ ) {
    100          
149 79         226 $node = Pod::Tree::Node->verbatim($paragraph);
150             }
151             elsif ( $Command{$word} ) {
152 1152         2315 $node = Pod::Tree::Node->command($paragraph);
153 1152         1670 $in_pod = $word ne '=cut';
154             }
155             else {
156 1026         2178 $node = Pod::Tree::Node->ordinary($paragraph);
157             }
158             }
159             else {
160 132 100       340 if ( $Command{$word} ) {
161 88         490 $node = Pod::Tree::Node->command($paragraph);
162 88         196 $in_pod = $word ne '=cut';
163             }
164             else {
165 44         178 $node = Pod::Tree::Node->code($paragraph);
166             }
167             }
168              
169 2389         4363 push @children, $node;
170             }
171              
172 84         338 $tree->{root} = Pod::Tree::Node->root( \@children );
173             }
174              
175             sub _make_for {
176 84     84   149 my $tree = shift;
177 84         146 my $root = $tree->{root};
178 84         239 my $old = $root->get_children;
179              
180 84         143 my @new;
181 84         225 while (@$old) {
182 2357         2974 my $node = shift @$old;
183 2357 100       3952 $node->is_c_for and $node->force_for;
184 2357 100       4228 $node->is_c_begin and $node->parse_begin($old);
185 2357         4708 push @new, $node;
186             }
187              
188 84         290 $root->set_children( \@new );
189             }
190              
191             sub _make_sequences {
192 84     84   138 my $tree = shift;
193 84         125 my $root = $tree->{root};
194 84         221 my $nodes = $root->get_children;
195              
196 84         173 for my $node (@$nodes) {
197 2357 100       4580 $node->is_code and next;
198 2313 100       4498 $node->is_verbatim and next;
199 2242 100       4026 $node->is_for and next;
200 2212         4230 $node->make_sequences;
201             }
202             }
203              
204             sub dump {
205 15     15 1 103 my $tree = shift;
206 15         48 $tree->{root}->dump;
207             }
208              
209 129     129 1 450 sub get_root { shift->{root} }
210              
211             sub set_root {
212 0     0 1 0 my ( $tree, $root ) = @_;
213 0         0 $tree->{root} = $root;
214             }
215              
216             sub push {
217 0     0 1 0 my ( $tree, @nodes ) = @_;
218 0         0 my $root = $tree->{root};
219 0         0 my $children = $root->get_children;
220 0         0 push @$children, @nodes;
221             }
222              
223             sub pop {
224 0     0 1 0 my $tree = shift;
225 0         0 my $root = $tree->get_root;
226 0         0 my $children = $root->get_children;
227 0         0 pop @$children;
228             }
229              
230             sub walk {
231 0     0 1 0 my ( $tree, $sub ) = @_;
232              
233 0         0 my $root = $tree->get_root;
234 0         0 _walk( $root, $sub );
235             }
236              
237             sub _walk {
238 0     0   0 my ( $tree, $sub ) = @_;
239              
240 0         0 my $descend = &$sub($tree); # :TRICKY: sub can modify node
241 0 0       0 $descend or return;
242              
243 0         0 my $node = $tree;
244              
245 0         0 my $children = $node->get_children;
246 0         0 for my $child (@$children) {
247 0         0 _walk( $child, $sub );
248             }
249              
250 0         0 my $siblings = $node->get_siblings;
251 0         0 for my $sibling (@$siblings) {
252 0         0 _walk( $sibling, $sub );
253             }
254             }
255              
256             sub has_pod {
257 63     63 1 121 my $tree = shift;
258 63         139 my $root = $tree->get_root;
259 63         202 my $children = $root->get_children;
260              
261 63         143 scalar grep { $_->get_type ne 'code' } @$children;
  824         1382  
262             }
263              
264             1
265              
266             __END__