File Coverage

blib/lib/Pod/Example.pm
Criterion Covered Total %
statement 99 99 100.0
branch 32 32 100.0
condition 6 6 100.0
subroutine 14 14 100.0
pod 2 2 100.0
total 153 153 100.0


line stmt bran cond sub pod time code
1             package Pod::Example;
2              
3 4     4   175407 use base qw(Exporter);
  4         9  
  4         547  
4 4     4   46 use strict;
  4         8  
  4         104  
5 4     4   15 use warnings;
  4         10  
  4         235  
6              
7 4     4   1025 use Error::Pure qw(err);
  4         23892  
  4         180  
8 4     4   2112 use Pod::Abstract 0.26;
  4         118944  
  4         166  
9 4     4   26 use Pod::Find qw(pod_where);
  4         35  
  4         247  
10 4     4   19 use Readonly;
  4         5  
  4         5102  
11              
12             # Constants.
13             Readonly::Array our @EXPORT_OK => qw(get sections);
14             Readonly::Scalar my $EMPTY_STR => q{};
15              
16             our $VERSION = 0.17;
17              
18             # Get content for file or module.
19             sub get {
20 23     23 1 361237 my ($file_or_module, $section, $number_of_example) = @_;
21              
22             # Get Pod::Abstract object.
23 23         57 my $pod_abstract = _pod_abstract($file_or_module);
24              
25             # Get section pod.
26 22         86820 my ($code, $example_filename) = _get_content($pod_abstract, $section, $number_of_example);
27              
28 22 100       396 return wantarray ? ($code, $example_filename) : $code;
29             }
30              
31             # Get example sections.
32             sub sections {
33 4     4 1 270125 my ($file_or_module, $section) = @_;
34              
35             # Get Pod::Abstract object.
36 4         18 my $pod_abstract = _pod_abstract($file_or_module);
37              
38             # Get first section.
39 4         20057 my @pod_sections = _get_sections($pod_abstract, $section);
40              
41             # Get section names.
42 4         11 my @sections = map { _get_section_name($_) } @pod_sections;
  6         20  
43              
44 4         181 return @sections;
45             }
46              
47             # Get content in Pod::Abstract object.
48             sub _get_content {
49 22     22   50 my ($pod_abstract, $section, $number_of_example) = @_;
50              
51             # Get first section.
52 22         42 my ($pod_section) = _get_sections($pod_abstract, $section,
53             $number_of_example);
54              
55             # No section.
56 22 100       50 if (! defined $pod_section) {
57 1         2 return;
58             }
59              
60             # Remove #cut.
61 21         37 my @cut = $pod_section->select("//#cut");
62 21         4429 foreach my $cut (@cut) {
63 16         29 $cut->detach;
64             }
65              
66             # Get pod.
67 21         873 my $child_pod = $EMPTY_STR;
68 21         22 my $example_filename;
69 21         23 my $first_node = 1;
70 21         40 foreach my $child ($pod_section->children) {
71 32 100       182 if ($child->type eq 'begin') {
    100          
72              
73             # =begin text as commented text.
74 2 100       9 if ($child->body =~ m/^text/ms) {
75             $child_pod .= join "\n",
76 1         15 map { ' #'.$_ }
  6         63  
77             split m/\n/ms,
78             ($child->children)[0]->pod;
79 1         3 $child_pod .= "\n\n";
80 1         1 $first_node = 0;
81              
82             # Skip =begin html and other unsupported sections.
83             } else {
84 1         7 $first_node = 0;
85 1         2 next;
86             }
87             } elsif ($child->type eq 'for') {
88             # =for paragraphs are formatter-specific data. Only a first
89             # =for comment filename=... paragraph is metadata for this module.
90 5 100 100     45 if ($first_node && $child->body eq 'comment') {
91 3         19 my ($node) = $child->tree->children;
92 3         17 my $body = $node->body;
93 3 100       21 if ($body =~ m/^filename=([\w\-\.]+)\s*$/ms) {
94 2         4 $example_filename = $1;
95             }
96             }
97 5         13 $first_node = 0;
98             } else {
99 25         191 $child_pod .= $child->pod;
100 25         935 $first_node = 0;
101             }
102             }
103              
104             # Remove spaces and return.
105 21         38 my $ret = _remove_spaces($child_pod);
106              
107 21         96 return ($ret, $example_filename);
108             }
109              
110             # Get section name.
111             # XXX Hack to structure.
112             sub _get_section_name {
113 6     6   9 my $pod_abstract_node = shift;
114             return $pod_abstract_node->{'params'}->{'heading'}->{'tree'}
115 6         24 ->{'nodes'}->[0]->{'body'};
116             }
117              
118             # Get sections.
119             sub _get_sections {
120 26     26   59 my ($pod_abstract, $section, $number_of_example) = @_;
121              
122             # Default section.
123 26 100       67 if (! $section) {
124 19         49 $section = 'EXAMPLE';
125             }
126              
127 26         61 my $section_re = quotemeta $section;
128              
129             # Concerete number of example.
130 26 100       48 if ($number_of_example) {
131 4         6 $section_re .= quotemeta $number_of_example;
132              
133             # Number of example as potential number.
134             } else {
135 22         27 $section_re .= '\d*';
136             }
137              
138             # Get and return sections.
139 26         77 my @sections = $pod_abstract->select('/head1[@heading =~ {^'.$section_re.'$}]');
140 26         14527 my $parent_section_re = quotemeta($section.'S');
141 26         82 push @sections, $pod_abstract->select('/head1[@heading =~ {^'.
142             $parent_section_re.'$}]/head2[@heading =~ {^'.$section_re.'$}]');
143              
144 26         21265 return @sections;
145             }
146              
147             # Get pod abstract for module.
148             sub _pod_abstract {
149 27     27   40 my $file_or_module = shift;
150              
151             # Module file.
152 27         40 my $file;
153 27 100       8157 if (-r $file_or_module) {
154 23         55 $file = $file_or_module;
155              
156             # Module.
157             } else {
158 4         3254 $file = pod_where({ -inc => 1 }, $file_or_module);
159 4 100       28 if (! $file) {
160 1         6 err 'Cannot open pod file or Perl module.';
161             }
162             }
163              
164             # Get and return pod.
165 26         212 return Pod::Abstract->load_file($file);
166             }
167              
168             # Remove spaces from example.
169             sub _remove_spaces {
170 21     21   50 my $string = shift;
171 21         77 my @lines = split /\n/, $string;
172              
173             # Get number of spaces in begin.
174 21         24 my $max = 0;
175 21         25 foreach my $line (@lines) {
176 112 100       154 if (! length $line) {
177 22         27 next;
178             }
179 90         171 $line =~ m/^(\ +)/ms;
180 90         84 my $spaces = $EMPTY_STR;
181 90 100       133 if ($1) {
182 86         93 $spaces = $1;
183             }
184 90 100 100     202 if ($max == 0 || length $spaces < $max) {
185 25         32 $max = length $spaces;
186             }
187             }
188              
189             # Remove spaces.
190 21 100       27 if ($max > 0) {
191 20         43 foreach my $line (@lines) {
192 107 100       109 if (! length $line) {
193 21         21 next;
194             }
195 86         110 $line = substr $line, $max;
196             }
197             }
198              
199             # Return string.
200 21         65 return join "\n", @lines;
201             }
202              
203             1;
204              
205              
206             __END__