File Coverage

blib/lib/Pod/Abstract/BuildNode.pm
Criterion Covered Total %
statement 76 100 76.0
branch 4 8 50.0
condition n/a
subroutine 19 25 76.0
pod 17 19 89.4
total 116 152 76.3


line stmt bran cond sub pod time code
1             package Pod::Abstract::BuildNode;
2 6     6   42 use strict;
  6         30  
  6         278  
3              
4 6     6   35 use Exporter;
  6         14  
  6         257  
5 6     6   34 use Pod::Abstract;
  6         42  
  6         223  
6 6     6   3332 use Pod::Abstract::Parser;
  6         37  
  6         466  
7 6     6   48 use Pod::Abstract::Node;
  6         14  
  6         169  
8 6     6   33 use base qw(Exporter);
  6         92  
  6         9164  
9              
10             our $VERSION = '0.26';
11              
12             our @EXPORT_OK = qw(node nodes);
13              
14 41     41 0 457830 sub node { 'Pod::Abstract::BuildNode' };
15 1     1 0 7 sub nodes { 'Pod::Abstract::BuildNode' };
16              
17             =head1 NAME
18              
19             Pod::Abstract::BuildNode - Build new nodes for use in Pod::Abstract.
20              
21             =head1 SYNOPSIS
22              
23             use Pod::Abstract::BuildNode qw(node nodes); # shorthand
24              
25             my $root_doc = node->root;
26             for(my $i = 1; $i < 10; $i ++) {
27             $root_doc->push(node->head1("Heading number $i"));
28             }
29             print $root_doc->pod;
30              
31             =head1 DESCRIPTION
32              
33             For building a new Pod::Abstract document, or adding nodes to an
34             existing one. This provides easy methods to generate correctly set
35             nodes for most common Pod::Abstract elements.
36              
37             =head1 NOTES
38              
39             Pod::Abstract::BuildNode can export two functions, C and
40             C. These are constant functions to provide a shorthand so
41             instead of writing:
42              
43             use Pod::Abstract::BuildNode;
44             # ...
45             my @nodes = Pod::Abstract::BuildNode->from_pod( $pod );
46              
47             You can instead write:
48              
49             use Pod::Abstract::BuildNode qw(node nodes);
50             # ...
51             my @nodes = nodes->from_pod($pod);
52              
53             Which is more readable, and less typing. C and C are both
54             synonyms of C.
55              
56             This shorthand form is shown in all the method examples below. All
57             methods operate on the class.
58              
59             =head1 METHODS
60              
61             =cut
62              
63             =head2 from_pod
64              
65             my @nodes = nodes->from_pod($pod_text);
66              
67             Given some literal Pod text, generate a full subtree of nodes. The
68             returned array is all of the top level nodes. The full document tree
69             will be populated under the returned nodes.
70              
71             =cut
72              
73             sub from_pod {
74 1     1 1 3 my $class = shift;
75 1         2 my $str = shift;
76              
77 1         12 my $root = Pod::Abstract->load_string($str);
78 1 50       23 return undef unless $root;
79              
80 1         4 my @r = map { $_->detach; $_ } $root->children;
  1         5  
  1         4  
81 1         14 return @r;
82             }
83              
84             =head2 root
85              
86             my $root = node->root;
87              
88             Generate a root node. A root node generates no output, and is used to
89             hold a document tree. Use this to make a new document.
90              
91             =cut
92              
93             sub root {
94 3     3 1 8 my $class = shift;
95 3         18 my $para = Pod::Abstract::Node->new(
96             type => '[ROOT]',
97             );
98             }
99              
100             =head2 begin
101              
102             my $begin_block = node->begin($command);
103              
104             Generates a begin/end block. Nodes nested inside the begin node will
105             appear between the begin/end.
106              
107             Note that there is no corresponding C method - the end command
108             belongs to it's corresponding begin.
109              
110             =cut
111              
112             sub begin {
113 0     0 1 0 my $class = shift;
114 0         0 my $cmd = shift;
115              
116 0         0 my $begin = Pod::Abstract::Node->new(
117             type => 'begin',
118             body => $cmd,
119             close_element => Pod::Abstract::Node->new(
120             type => 'end',
121             body => $cmd,
122             ),
123             );
124 0         0 return $begin;
125             }
126              
127             =head2 for
128              
129             my $for = node->for('overlay from ');
130              
131             Create a =for node. The argument is the literal body of the for node,
132             no parsing will be performed.
133              
134             =cut
135              
136             sub for {
137 0     0 1 0 my $class = shift;
138 0         0 my $str = shift;
139              
140 0         0 return Pod::Abstract::Node->new(
141             type => 'for',
142             body => $str,
143             );
144             }
145              
146             =head2 paragraph
147              
148             my $para = node->paragraph('Pod text');
149              
150             Generates a Pod paragraph, possibly containing interior sequences. The
151             argument will be parsed as Pod, and will generate text and sequence
152             nodes inside the paragraph.
153              
154             =cut
155              
156             sub paragraph {
157 7     7 1 15 my $class = shift;
158 7         14 my $str = shift;
159              
160 7         25 my $para = Pod::Abstract::Node->new(
161             type => ':paragraph',
162             );
163 7         26 my $parser = Pod::Abstract::Parser->new;
164 7         410 my $pt = $parser->parse_text($str);
165              
166 7 50       26 if($pt) {
167 7         26 $parser->load_pt($para,$pt);
168             } else {
169 0         0 return undef;
170             }
171             }
172              
173             =head2 verbatim
174              
175             my $v = node->verbatim($text);
176              
177             Add the given text as a verbatim node to the document. All lines in
178             the fiven C<$text> will be indented by one space to ensure they are
179             treated as verbatim.
180              
181             =cut
182              
183             sub verbatim {
184 1     1 1 3 my $class = shift;
185 1         3 my $str = shift;
186              
187 1         6 my @strs = split "\n",$str;
188 1         6 for(my $i = 0; $i < @strs; $i ++) {
189 7         15 my $str_line = $strs[$i];
190 7         18 $strs[$i] = ' '.$str_line;
191             }
192 1         10 my $verbatim = Pod::Abstract::Node->new(
193             type => ':verbatim',
194             body => (join("\n", @strs) . "\n\n"),
195             );
196 1         4 return $verbatim;
197             }
198              
199             =head2 heading
200              
201             my $head2 = node->heading(2, $heading);
202              
203             Generate a heading node at the given level. Nodes that "belong" in the
204             heading's section should be nested in the heading node. The
205             C<$heading> text will be parsed for interior sequences.
206              
207             =cut
208              
209             sub heading {
210 26     26 1 171 my $class = shift;
211 26         39 my $level = shift;
212 26         47 my $heading = shift;
213              
214 26         82 my $attr_node = Pod::Abstract::Node->new(
215             type => '@attribute',
216             );
217 26         89 my $parser = Pod::Abstract::Parser->new;
218 26         1089 my $pt = $parser->parse_text($heading);
219 26         117 $parser->load_pt($attr_node, $pt);
220              
221 26         96 my $element_node = Pod::Abstract::Node->new(
222             type => "head$level",
223             heading => $attr_node,
224             body_attr => 'heading',
225             );
226 26         544 return $element_node;
227             }
228              
229             =head2 head1
230              
231             node->head1($heading);
232              
233             =cut
234              
235             sub head1 {
236 6     6 1 15 my $class = shift;
237 6         13 my $heading = shift;
238              
239 6         21 return $class->heading(1,$heading);
240             }
241              
242             =head2 head2
243              
244             node->head2($heading);
245              
246             =cut
247              
248             sub head2 {
249 20     20 1 36 my $class = shift;
250 20         74 my $heading = shift;
251              
252 20         54 return $class->heading(2,$heading);
253             }
254              
255             =head2 head3
256              
257             node->head3($heading);
258              
259             =cut
260              
261             sub head3 {
262 0     0 1 0 my $class = shift;
263 0         0 my $heading = shift;
264              
265 0         0 return $class->heading(3,$heading);
266             }
267              
268             =head2 head4
269              
270             node->head4($heading);
271              
272             =cut
273              
274             sub head4 {
275 0     0 1 0 my $class = shift;
276 0         0 my $heading = shift;
277              
278 0         0 return $class->heading(4,$heading);
279             }
280              
281             =head2 over
282              
283             my $list = node->over([$num]);
284              
285             Generates an over/back block, to contain list items. The optional
286             parameter C<$num> specifies the number of spaces to indent by. Note
287             that the back node is part of the over, there is no separate back
288             method.
289              
290             =cut
291              
292             sub over {
293 1     1 1 3 my $class = shift;
294 1         3 my $number = shift;
295 1 50       5 $number = '' unless defined $number;
296              
297 1 50       8 return Pod::Abstract::Node->new(
298             type => 'over',
299             body => ($number ? $number : undef),
300             close_element => Pod::Abstract::Node->new(
301             type => 'back',
302             ),
303             );
304             }
305              
306             =head2 link
307              
308             my $link = node->link('Pod::Abstract');
309              
310             Generates an inline link. This will nest the passed link text only.
311              
312             There's special inline parsing for Perl POD links, which is not handled
313             by this method.
314              
315             =cut
316              
317             sub link {
318 0     0 1 0 my $class = shift;
319 0         0 my $link = shift;
320              
321 0         0 my $l = Pod::Abstract::Node->new(
322             type => ':L',
323             body => undef,
324             );
325 0         0 my $body = $class->text($link);
326 0         0 $l->nest($body);
327 0         0 return $l;
328             }
329              
330             =head2 item
331              
332             my $item = node->item('*');
333              
334             Generates an item with the specified label. To fill in the text of the
335             item, nest paragraphs into the item. Items should be contained in over
336             nodes.
337              
338             =cut
339              
340             sub item {
341 1     1 1 4 my $class = shift;
342 1         2 my $label = shift;
343              
344 1         6 my $attr_node = Pod::Abstract::Node->new(
345             type => '@attribute',
346             );
347 1         5 my $parser = Pod::Abstract::Parser->new;
348 1         43 my $pt = $parser->parse_text($label);
349 1         5 $parser->load_pt($attr_node, $pt);
350              
351 1         5 my $element_node = Pod::Abstract::Node->new(
352             type => "item",
353             label => $attr_node,
354             body_attr => 'label',
355             );
356 1         24 return $element_node;
357             }
358              
359             =head2 text
360              
361             my $text = node->text('Literal text');
362              
363             Generates a literal text node. You generally B want this, you
364             probably want a paragraph. Use this if you want to, for example,
365             append a word at the end of a paragraph.
366              
367             =cut
368              
369             sub text {
370 0     0 1 0 my $class = shift;
371 0         0 my $text = shift;
372              
373 0         0 my $attr_node = Pod::Abstract::Node->new(
374             type => ':text',
375             body => $text,
376             );
377 0         0 return $attr_node;
378             }
379              
380             =head2 pod
381              
382             my $n = node->pod;
383              
384             Generates an "=pod" command. Can be useful to force pod mode at the
385             end of cut nodes.
386              
387             Do not confuse with L!
388              
389             =cut
390              
391             sub pod {
392 1     1 1 3 my $class = shift;
393 1         4 return Pod::Abstract::Node->new(
394             type => 'pod',
395             body => '',
396             );
397             }
398              
399             =head2 cut
400              
401             my $cut = node->cut;
402              
403             Generates an explicit "=cut" command.
404              
405             =cut
406              
407             sub cut {
408 1     1 1 3 my $class = shift;
409 1         4 return Pod::Abstract::Node->new(
410             type => '#cut',
411             body => "=cut\n\n",
412             );
413             }
414              
415             =head1 AUTHOR
416              
417             Ben Lilburne
418              
419             =head1 COPYRIGHT AND LICENSE
420              
421             Copyright (C) 2009-2025 Ben Lilburne
422              
423             This program is free software; you can redistribute it and/or modify
424             it under the same terms as Perl itself.
425              
426             =cut
427              
428             1;