File Coverage

lib/MetaPOD/Extractor.pm
Criterion Covered Total %
statement 100 110 90.9
branch 22 34 64.7
condition 2 5 40.0
subroutine 27 28 96.4
pod 11 11 100.0
total 162 188 86.1


line stmt bran cond sub pod time code
1 3     3   59313 use 5.008; # utf8
  3         12  
  3         199  
2 3     3   21 use strict;
  3         7  
  3         112  
3 3     3   170 use warnings;
  3         8  
  3         258  
4 3     3   3203 use utf8;
  3         64  
  3         24  
5              
6             package MetaPOD::Extractor;
7             $MetaPOD::Extractor::VERSION = '0.3.6';
8             # ABSTRACT: Extract MetaPOD declarations from a file.
9              
10             our $AUTHORITY = 'cpan:KENTNL'; # AUTHORITY
11              
12 3     3   3329 use Moo qw( extends has );
  3         62126  
  3         28  
13             extends 'Pod::Eventual';
14              
15              
16              
17              
18              
19              
20              
21              
22              
23              
24              
25              
26              
27             ## no critic (Bangs::ProhibitDebuggingModule)
28 3     3   17328 use Data::Dump qw(pp);
  3         50331  
  3         302  
29 3     3   141 use Carp qw(croak);
  3         7  
  3         6984  
30              
31             has formatter_regexp => (
32             is => ro =>,
33             lazy => 1,
34             builder => sub {
35              
36             # _Pulp__5010_qr_m_propagate_properly
37             ## no critic (Compatibility::PerlMinimumVersionAndWhy)
38 5     5   1303 return qr/MetaPOD::([^[:space:]]+)/sxm;
39             },
40             );
41              
42             has version_regexp => (
43             is => ro =>,
44             lazy => 1,
45             builder => sub {
46              
47             # _Pulp__5010_qr_m_propagate_properly
48             ## no critic (Compatibility::PerlMinimumVersionAndWhy)
49 5     5   1318 return qr/(v[[:digit:].]+)/sxm;
50             },
51             );
52              
53             has regexp_begin_with_version => (
54             is => ro =>,
55             lazy => 1,
56             builder => sub {
57 3     3   1442 my $formatter_regexp = $_[0]->formatter_regexp;
58 3         49 my $version_regexp = $_[0]->version_regexp;
59              
60             # _Pulp__5010_qr_m_propagate_properly
61             ## no critic (Compatibility::PerlMinimumVersionAndWhy)
62 3         1309 return qr{ ^ ${formatter_regexp} \s+ ${version_regexp} \s* $ }smx;
63             },
64             );
65              
66             has regexp_begin => (
67             is => ro =>,
68             lazy => 1,
69             builder => sub {
70 2     2   1010 my $formatter_regexp = $_[0]->formatter_regexp;
71              
72             # _Pulp__5010_qr_m_propagate_properly
73             ## no critic (Compatibility::PerlMinimumVersionAndWhy)
74 2         89 return qr{ ^ ${formatter_regexp} \s* $ }smx;
75             },
76             );
77              
78             has regexp_for_with_version => (
79             is => ro =>,
80             lazy => 1,
81             builder => sub {
82 2     2   747 my $formatter_regexp = $_[0]->formatter_regexp;
83 2         30 my $version_regexp = $_[0]->version_regexp;
84              
85             # _Pulp__5010_qr_m_propagate_properly
86             ## no critic (Compatibility::PerlMinimumVersionAndWhy)
87 2         344 return qr{ ^ ${formatter_regexp} \s+ ${version_regexp} \s+ ( .*$ ) }smx;
88             },
89             );
90              
91             has regexp_for => (
92             is => ro =>,
93             lazy => 1,
94             builder => sub {
95 1     1   705 my $formatter_regexp = $_[0]->formatter_regexp;
96              
97             # _Pulp__5010_qr_m_propagate_properly
98             ## no critic (Compatibility::PerlMinimumVersionAndWhy)
99 1         42 return qr{ ^ ${formatter_regexp} \s+ ( .* $ ) $ }smx;
100             },
101             );
102              
103             has end_segment_callback => (
104             is => ro =>,
105             lazy => 1,
106             builder => sub {
107 4     4   8 return sub { };
  4         620  
108             },
109             );
110              
111              
112              
113              
114              
115              
116              
117             has segment_cache => (
118             is => ro =>,
119             lazy => 1,
120             writer => 'set_segment_cache',
121 0     0   0 builder => sub { {} },
122             );
123              
124              
125              
126              
127              
128              
129              
130             has segments => (
131             is => ro =>,
132             lazy => 1,
133             writer => 'set_segments',
134 5     5   1242 builder => sub { [] },
135             );
136              
137              
138              
139              
140              
141              
142              
143              
144              
145              
146              
147              
148              
149             has in_segment => (
150             is => ro =>,
151             lazy => 1,
152             writer => 'set_in_segment',
153             clearer => 'unset_in_segment',
154 5     5   1278 builder => sub { undef },
155             );
156              
157              
158              
159              
160              
161              
162              
163             sub begin_segment {
164 3     3 1 12 my ( $self, $format, $version, $start_line ) = @_;
165 3 100       31 $self->set_segment_cache(
166             {
167             format => $format,
168             start_line => $start_line,
169             ( defined $version ? ( version => $version ) : () ),
170             },
171             );
172 3         10 $self->set_in_segment(1);
173 3         14 return $self;
174             }
175              
176              
177              
178              
179              
180              
181              
182             sub end_segment {
183 3     3 1 6 my ($self) = @_;
184 3         72 my $segment = $self->segment_cache;
185 3         22 push @{ $self->segments }, $segment;
  3         104  
186 3         17 $self->set_segment_cache( {} );
187 3         33 $self->unset_in_segment();
188 3         1395 my $cb = $self->end_segment_callback;
189 3         605 $cb->($segment);
190 3         13 return $self;
191             }
192              
193              
194              
195              
196              
197              
198              
199             sub append_segment_data {
200 3     3 1 6 my ( $self, $segment_data ) = @_;
201 3   50     330 $self->segment_cache->{data} ||= q{};
202 3         1212 $self->segment_cache->{data} .= $segment_data;
203 3         35 return $self;
204             }
205              
206              
207              
208              
209              
210              
211              
212             sub add_segment {
213 2     2 1 10 my ( $self, $format, $version, $section_data, $start_line ) = @_;
214 2         4 my $segment = {};
215 2         5 $segment->{format} = $format;
216 2 100       8 $segment->{version} = $version if defined $version;
217 2         33 $segment->{data} = $section_data;
218 2 50       9 $segment->{start_line} = $start_line if defined $start_line;
219              
220 2         3 push @{ $self->segments }, $segment;
  2         29  
221 2         28 my $cb = $self->end_segment_callback;
222 2         6 $cb->($segment);
223              
224 2         9 return $self;
225             }
226              
227              
228              
229              
230              
231              
232              
233             sub handle_begin {
234 3     3 1 6 my ( $self, $event ) = @_;
235 3 50       51 if ( $self->in_segment ) {
236 0         0 croak '=begin MetaPOD:: cannot occur inside =begin MetaPOD:: at line ' . $event->{start_line};
237             }
238 3 100       33 if ( $event->{content} =~ $self->regexp_begin_with_version ) {
239 1         5 return $self->begin_segment( $1, $2, $event->{start_line} );
240             }
241 2 50       16 if ( $event->{content} =~ $self->regexp_begin ) {
242 2         16 return $self->begin_segment( $1, undef, $event->{start_line} );
243             }
244 0         0 return $self->handle_ignored($event);
245             }
246              
247              
248              
249              
250              
251              
252              
253             sub handle_end {
254 3     3 1 7 my ( $self, $event ) = @_;
255 3         15 chomp $event->{content};
256 3         15 my $statement = q{=} . $event->{command} . q{ } . $event->{content};
257              
258 3 0 33     79 if ( not $self->in_segment and not $event->{content} =~ $self->regexp_begin ) {
259 0         0 return $self->handle_ignored($event);
260             }
261              
262 3 50       93 if ( $self->in_segment ) {
263 3         145 my $expected_end = '=end MetaPOD::' . $self->segment_cache->{format};
264 3 50       35 if ( $statement ne $expected_end ) {
265 0         0 croak "$statement seen but expected $expected_end at line " . $event->{start_line};
266             }
267 3         14 return $self->end_segment();
268             }
269 0 0       0 if ( $event->{content} =~ $self->regexp_begin ) {
270 0         0 croak "unexpected $statement without =begin MetaPOD::$1 at line" . $event->{start_line};
271             }
272 0         0 return $self->handle_ignored($event);
273             }
274              
275              
276              
277              
278              
279              
280              
281             sub handle_for {
282 2     2 1 4 my ( $self, $event ) = @_;
283 2 100       31 if ( $event->{content} =~ $self->regexp_for_with_version ) {
284 1         5 return $self->add_segment( $1, $2, $3, $event->{start_line} );
285             }
286 1 50       14 if ( $event->{content} =~ $self->regexp_for ) {
287 1         120 return $self->add_segment( $1, undef, $2, $event->{start_line} );
288             }
289 0         0 return $self->handle_ignored($event);
290             }
291              
292              
293              
294              
295              
296              
297              
298             sub handle_cut {
299 2     2 1 4 my ( $self, $element ) = @_;
300 2         5 return $self->handle_ignored($element);
301             }
302              
303              
304              
305              
306              
307              
308              
309             sub handle_text {
310 3     3 1 8 my ( $self, $element ) = @_;
311 3 50       74 return $self->handle_ignored($element) unless $self->in_segment;
312 3         38 return $self->append_segment_data( $element->{content} );
313             }
314              
315              
316              
317              
318              
319              
320              
321             sub handle_ignored {
322 4     4 1 7 my ( $self, $element ) = @_;
323 4 50       103 if ( $self->in_segment ) {
324 0         0 croak 'Unexpected type ' . $element->{type} . ' inside segment ' . pp($element) . ' at line' . $element->{start_line};
325             }
326             }
327              
328              
329              
330              
331              
332              
333              
334             sub handle_event {
335 15     15 1 28060 my ( $self, $event ) = @_;
336 15         34 for my $command (qw( begin end for cut )) {
337 28 100       105 last unless 'command' eq $event->{type};
338 23 100       485 next unless $event->{command} eq $command;
339 10         68 my $method = $self->can( 'handle_' . $command );
340 10         42 return $self->$method($event);
341             }
342 5 100       458 if ( 'text' eq $event->{type} ) {
343 3         12 return $self->handle_text($event);
344             }
345 2         10 return $self->handle_ignored($event);
346              
347             }
348              
349             1;
350              
351             __END__