File Coverage

blib/lib/Pod/Snippets.pm
Criterion Covered Total %
statement 201 213 94.3
branch 83 94 88.3
condition 12 17 70.5
subroutine 44 47 93.6
pod 8 8 100.0
total 348 379 91.8


line stmt bran cond sub pod time code
1             package Pod::Snippets;
2              
3 7     7   170155 use warnings;
  7         18  
  7         305  
4 7     7   43 use strict;
  7         15  
  7         301  
5              
6             =head1 NAME
7              
8             Pod::Snippets - Extract and reformat snippets of POD so as to use them
9             in a unit test (or other Perl code)
10              
11             =head1 VERSION
12              
13             Version 0.14
14              
15             =cut
16              
17 7     7   47 use vars qw($VERSION); $VERSION = '0.14';
  7         19  
  7         18014  
18              
19             =head1 SYNOPSIS
20              
21             =for metatests "synopsis test script" begin
22              
23 1     1   23 use Pod::Snippets;
  1         2  
  1         126  
24              
25             my $snips = load Pod::Snippets($file_or_handle,
26             -markup => "test");
27              
28             my $code_snippet = $snips->named("synopsis")->as_code;
29              
30             # ... Maybe borg $code_snippet with regexes or something...
31              
32             my $result = eval $code_snippet; die $@ if $@;
33              
34             like($result->what_happen(), qr/bomb/);
35              
36             =for metatests "synopsis test script" end
37              
38             The Perl code that we want to extract snippets from might look like
39             this:
40              
41             =for metatests "synopsis POD" begin
42              
43             package Zero::Wing;
44              
45             =head1 NAME
46              
47             Zero::Wing - For great justice!
48              
49             =head1 SYNOPSIS
50              
51             =for test "synopsis" begin
52              
53             use Zero::Wing;
54              
55             my $capitain = Zero::Wing->capitain;
56              
57             =for test "synopsis" end
58              
59             =cut
60              
61             # ...
62              
63             1;
64              
65             =for metatests "synopsis POD" end
66              
67             =head1 DESCRIPTION
68              
69             This class is a very simple extension of L that extracts
70             POD snippets from Perl code, and pretty-prints it so as to make it
71             useable from other Perl code. As demonstrated above, B
72             is immediately useful to test-driven-development nutcases who want to
73             put every single line of Perl code under test, including code that is
74             in the POD (typically a SYNOPSIS section). There are other uses, such
75             as storing a piece of information that is both human- and
76             machine-readable (eg an XML schema) simultaneously as documentation
77             and code.
78              
79             =head2 Using Pod::Snippets for unit testing
80              
81             The L demonstrates how to use B to grab a
82             piece of POD and execute it with L. This can readily
83             be done using your usual unit testing methodology, without too much
84             ajusting if any. This approach has some advantages over other
85             code-in-POD devices such as L and L:
86              
87             =over
88              
89             =item *
90              
91             There is no preprocessing step involved, hence no temp files and no
92             loss of hair in the debugger due to line renumbering.
93              
94             =item *
95              
96             Speaking of which, L prepends an appropriate C<#line> if
97             possible, so you can single-step through your POD (yow!).
98              
99             =back
100              
101             The Pod-Snippets CPAN distribution consists of a single Perl file, and
102             has no dependencies besides what comes with a standard Perl 5.8.x. It
103             is therefore easy to embed into your own module so that your users
104             won't need to install B by themselves before running
105             your test suite. All that remains to do is to select the right
106             options to pass to L as part of an appropriately named wrapper
107             function in your test library.
108              
109             =head2 Snippet Syntax
110              
111             B only deals with verbatim portions of the POD (that
112             is, as per L, paragraphs that start with whitespace at the
113             right) and custom markup starting with C<=for test>, C<=begin test> or
114             C<=end test>; it discards the rest (block text, actual Perl code,
115             character markup such as BEE, =head's and so on). The keyword
116             "test" in C<=for test> and C<=begin test> can be replaced with
117             whatever one wants, using the C<-markup> argument to L.
118             Actually the default value is not even "test"; nonetheless let's
119             assume you are using "test" yourself for the remainder of this
120             discussion. The following metadata markup is recognized:
121              
122             =over
123              
124             =item B<=for test ignore>
125              
126             Starts ignoring all POD whatsoever. Verbatim portions of the POD are
127             no longer stashed by B until remanded by a subsequent
128             C<=for test>.
129              
130             =item B<=for test>
131              
132             Cancels the effect of an ongoing C<=for test ignore> directive.
133              
134             =item B<=for test "foo" begin>
135              
136             =item B<=for test "foo" end>
137              
138             These signal the start and end of a I POD snippet, that can
139             later be fetched by name using L. Unless countermanded by
140             appropriate parser options (see L), named POD snippets can
141             nest freely (even badly).
142              
143             =item B<=begin test>
144              
145             =item B<=end test>
146              
147             The POD between these markers will be seen by B, but
148             not by other POD formatters. Otherwise has no effect on the naming or
149             ignoring of snippets; in particular, if the contents of the section is
150             not in POD verbatim style, it still gets ignored.
151              
152             =item B<=begin test "foo">
153              
154             =item B<=end test "foo">
155              
156             These have the exact same effect as C<=for test "foo" begin> and
157             C<=for test "foo" end>, except that other POD formatters will not see
158             the contents of the block.
159              
160             =back
161              
162             =head1 CONSTRUCTORS
163              
164             =head2 load ($source, -opt1 => $val1, ...)
165              
166             Parses the POD from $source and returns an object of class
167             B that holds the snippets found therein. $source may
168             be the name of a file, a file descriptor (glob reference) or any
169             object that has a I method.
170              
171             Available named options are:
172              
173             =over
174              
175             =item B<< -filename => $filename >>
176              
177             The value to set for L, that is, the name of the file to
178             use for C<#line> lines in L. The default behavior is to use
179             the filename passed as the $source argument, or if it was not a
180             filename, use the string "pod snippet" instead.
181              
182             =item B<< -line => $line >>
183              
184             The line number to start counting lines from, eg in case the $source
185             got a few lines chopped off it before being passed to I.
186             Default is 1.
187              
188             =item B<< -markup => $name >>
189              
190             The markup (aka "format name" in L) to use as the first token
191             after C<=for>, C<=begin> or C<=end> to indicate that the directive is
192             to be processed by B (see L. Default
193             is "Pod::Snippets".
194              
195             =item B<< -report_errors => $sub >>
196              
197             Invokes $sub like so to deal with warnings and errors:
198              
199             $sub->($severity, $text, $file, $line);
200              
201             where $severity is either "WARNING" or "ERROR". By default the
202             standard Perl L is used.
203              
204             Regardless of the number of errors, the constructor tries to load the
205             whole file; see below.
206              
207             =item B<< -named_snippets => "warn_impure" >>
208              
209             Raises an error upon encountering this kind of construct:
210              
211             =for metatests "named_snippets impure error" begin
212              
213             =for test "foobar" begin
214              
215             my $foobar = foobar();
216              
217             =head1 And now something completely different...
218              
219             =for test "foobar" end
220              
221             =for metatests "named_snippets impure error" end
222              
223             In other words, only verbatim blocks may intervene between the B<=for
224             test "foobar" begin> and B<=for test "foobar" end> markups.
225              
226             =item B<< -named_snippets => "warn_multiple" >>
227              
228             Raises a warning upon encountering this kind of construct:
229              
230             =for metatests "named_snippets multiple error" begin
231              
232             =for test "foobar" begin
233              
234             my $foobar = foobar();
235              
236             =for test "foobar" end
237              
238             =for test "foobar" begin
239              
240             $foobar->quux_some_more();
241              
242             =for test "foobar" end
243              
244             =for metatests "named_snippets multiple error" end
245              
246             =item B<< -named_snippets => "warn_overlap" >>
247              
248             Raises a warning if named snippets overlap in any way.
249              
250             =item B<< -named_snippets => "warn_bad_pairing" >>
251              
252             Raises a warning if opening and closing markup for named snippets is
253             improperly paired (eg opening or closing twice, or forgetting to close
254             before the end of the file).
255              
256             =item B<< -named_snippets => "error_impure" >>
257              
258             =item B<< -named_snippets => "error_multiple" >>
259              
260             =item B<< -named_snippets => "error_overlap" >>
261              
262             =item B<< -named_snippets => "error_bad_pairing" >>
263              
264             Same as the C counterparts above, but cause errors instead of
265             warnings.
266              
267             =item B<< -named_snippets => "ignore_impure" >>
268              
269             =item B<< -named_snippets => "ignore_multiple" >>
270              
271             =item B<< -named_snippets => "ignore_overlap" >>
272              
273             =item B<< -named_snippets => "ignore_bad_pairing" >>
274              
275             Ignores the corresponding dubious constructs described above. The
276             default behavior is C<< -named_snippets => "warn_bad_pairing" >> and
277             ignore the rest.
278              
279             =item B<< -named_snippets => "strict" >>
280              
281             Equivalent to C<< (-named_snippets => "error_overlap", -named_snippets
282             => "error_impure", -named_snippets => "error_multiple",
283             -named_snippets => "error_bad_pairing") >>.
284              
285             =back
286              
287             Note that the correctness of the POD to be parsed is a prerequisite;
288             in other words, I won't touch the error management
289             knobs of the underlying L object.
290              
291             Also, note that the parser strictness options such as
292             B<-named_snippets> have no effect on the semantics; they merely alter
293             its response (ignore, warning or error) to the aforementioned dubious
294             constructs. In any case, the parser will soldier on until the end of
295             the file regardless of the number of errors seen; however, it will
296             disallow further processing of the snippets if there were any errors
297             (see L).
298              
299             =cut
300              
301             sub load {
302 30     30 1 7942 my ($class, $source, @opts) = @_;
303              
304 30         125 my $self = bless {}, $class;
305 30         126 $self->{start_line} = 1;
306             $self->{filename} = "$source" unless (ref($source) eq "GLOB" ||
307 30 100 66     268 eval { $source->can("getline") });
  30         342  
308 30         69 undef $@;
309              
310             # Grind the syntactic sugar to dust:
311             my %opts = (-line => 1, -filename => $self->filename,
312             -report_errors => sub {
313 0     0   0 my ($severity, $text, $file, $line) = @_;
314 0         0 warn <<"MESSAGE";
315             $severity: $text
316             in $file line $line
317             MESSAGE
318 30         155 }, -markup => "Pod::Snippets",
319             -bad_pairing => "warning");
320 30         180 while(my ($k, $v) = splice @opts, 0, 2) {
321 78 100       235 if ($k eq "-named_snippets") {
    100          
322 28 100       160 if ($v eq "strict") {
    100          
    100          
    50          
323 16         194 $opts{"-$_"} = "error" foreach
324             (qw(overlap impure multiple bad_pairing));
325             } elsif ($v =~ m|^ignore_(.*)|) {
326 4         23 $opts{"-$1"} = "ignore";
327             } elsif ($v =~ m|^error_(.*)|) {
328 4         30 $opts{"-$1"} = "error";
329             } elsif ($v =~ m|^warn(ing)?_(.*)|) {
330 4         25 $opts{"-$2"} = "warning";
331             }
332             } elsif ($k eq "-line") {
333 1         3 $self->{start_line} = $v;
334 1         5 $opts{$k} = $v;
335             } else {
336 49         268 $opts{$k} = $v;
337             }
338             }
339              
340             # Run the parser:
341 30         264 my $parser = "${class}::_Parser"->new_for_pod_snippets(%opts);
342 30 100       162 if ($self->{filename}) {
343 8         2801 $parser->parse_from_file($self->{filename}, undef);
344             } else {
345 22         2100 $parser->parse_from_filehandle($source, undef);
346             }
347 30         112 $parser->finalize_pod_snippets();
348              
349             # Extract the relevant bits from it:
350 30         126 $self->{unmerged_snippets} = $parser->pod_snippets;
351 30         104 $self->{warnings} = $parser->pod_snippets_warnings;
352 30         102 $self->{errors} = $parser->pod_snippets_errors;
353 30         506 return $self;
354             }
355              
356             =head2 parse ($string, -opt1 => $val1, ...)
357              
358             Same as L, but works from a Perl string instead of a file
359             descriptor. The named options are the same as in I, but
360             consider using C<< -filename >> as I is in no position to
361             guess it.
362              
363             =cut
364              
365             sub parse {
366 22     22 1 44505 my ($class, $string, @args) = @_;
367 22         116 return $class->load(Pod::Snippets::LineFeeder->new($string), @args);
368              
369             package Pod::Snippets::LineFeeder;
370              
371             sub new {
372 22     22   40 my ($class, $string) = @_;
373 22         53 my $nl = $/; # Foils smarter-than-thou regex parser
374 22         2544 return bless { lines => [ $string =~ m{(.*(?:$nl|$))}g ] };
375             }
376 279     279   323 sub getline { shift @{shift->{lines}} }
  279         6642  
377             }
378              
379             =head1 ACCESSORS
380              
381             =head2 filename ()
382              
383             Returns the name of the file to use for C<#line> lines in L.
384             The default behavior is to use the filename passed as the $source
385             argument, or if it was not a filename, use the string "pod snippet"
386             instead.
387              
388             =cut
389              
390 35 100   35 1 544 sub filename { shift->{filename} || "pod snippet" }
391              
392             =head2 warnings ()
393              
394             Returns the number of warnings that occured during the parsing of the
395             POD.
396              
397             =head2 errors ()
398              
399             Returns the number of errors that occured during the parsing of the
400             POD. If that number is non-zero, then all accessors described below
401             will throw an exception instead of performing.
402              
403             =cut
404              
405 16     16 1 106 sub warnings { shift->{warnings} }
406 64     64 1 53480 sub errors { shift->{errors} }
407              
408             =head2 as_data ()
409              
410             Returns the snippets in "data" format: that is, the return value is
411             ragged to the left by suppressing a constant number of space
412             characters at the beginning of each snippet. (If tabs are present in
413             the POD, they are treated as being of infinite length; that is, the
414             ragging algorithm does not eat them or replace them with spaces.)
415              
416             A snippet is defined as a series of subsequent verbatim POD paragraphs
417             with only B markup, if anything, intervening in
418             between. That is, I, given the following POD in input:
419              
420             =for metatests "as_data multiple blocks input" begin
421              
422             my $a = new The::Brain;
423              
424             =begin test
425              
426             # Just kidding. We can't do that, it's too dangerous.
427             $a = new Pinky;
428              
429             =end test
430              
431             =for test ignore
432              
433             system("/sbin/reboot");
434              
435             and all of a sudden, we have:
436              
437             =for test
438              
439             if ($a->has_enough_cookies()) {
440             $a->conquer_world();
441             }
442              
443             =for metatests "as_data multiple blocks input" end
444              
445             would return (in list context)
446              
447             =for metatests "as_data multiple blocks return" begin
448              
449             (<<'FIRST_SNIPPET', <<'SECOND_SNIPPET');
450             my $a = new The::Brain;
451              
452              
453              
454             # Just kidding. We can't do that, it's too dangerous.
455             $a = new Pinky;
456             FIRST_SNIPPET
457             if ($a->has_enough_cookies()) {
458             $a->conquer_world();
459             }
460             SECOND_SNIPPET
461              
462             =for metatests "as_data multiple blocks return" end
463              
464             Notice how the indentation is respected snippet-by-snippet; also,
465             notice that the FIRST_SNIPPET has been padded with an appropriate
466             number of carriage returns to replace the B markup, so
467             that the return value is line-synchronized with the original POD.
468             However, leading and trailing whitespace is trimmed, leaving only
469             strings that starts with a nonblank line and end with a single
470             newline.
471              
472             In scalar context, returns the blocks joined with a single newline
473             character ("\n"), thus resulting in a single piece of text where the
474             blocks are joined by exactly one empty line (and which as a whole is
475             no longer line-synchronized with the source code, of course).
476              
477             =cut
478              
479             sub as_data {
480 26     26 1 71 my ($self) = @_;
481 26         119 $self->_block_access_if_errors();
482              
483             my @retval = map {
484             # This may be a pedestrian and sub-optimal way of doing the
485             # ragging, but it sure is concise:
486 26 50       96 until (m/^\S/m) { s/^ //gm or last; };
  27         73  
  64         1031  
487 27         107 "$_";
488             } ($self->_merged_snippets);
489              
490 26 100       251 return wantarray ? @retval : join("\n", @retval);
491             }
492              
493             =head2 as_code ()
494              
495             Returns the snippets formatted as code, that is, like L,
496             except that each block is prepended with an appropriate C<#line>
497             statement that Perl can interpret to renumber lines. For instance,
498             these statements would cause Perl to Do The Right Thing if one
499             compiles the snippets as code with L and then runs it
500             under the Perl debugger.
501              
502             =cut
503              
504             sub as_code {
505 5     5 1 12 my ($self) = @_;
506 5         17 $self->_block_access_if_errors();
507 5         20 my @retval = $self->as_data;
508              
509 5         17 foreach my $i (0..$#retval) {
510 5         24 my $file = $self->filename;
511 5         21 my $line = ($self->_merged_snippets)[$i]->line() +
512             $self->{start_line} - 1;
513 5         39 $retval[$i] = <<"LINE_MARKUP" . $retval[$i];
514             #line $line "$file"
515             LINE_MARKUP
516             }
517 5 50       2539 return wantarray ? @retval : join("\n", @retval);
518             }
519              
520             =head2 named ($name)
521              
522             Returns a clone of this B object, except that it only
523             knows about the snippet (or snippets) that are named $name. In the
524             most lax settings for the parser, this means: any and all snippets
525             where an C<=for test "$name" begin> (or C<=begin test "$name">) had
526             been open, but not yet closed with C<=for test "$name" end> (or C<=end
527             test "$name">). Returns undef if no snippet named $name was seen at
528             all.
529              
530             =cut
531              
532             sub named {
533 18     18 1 2467 my ($self, $name) = @_;
534 18         70 $self->_block_access_if_errors();
535 452 100       1436 my @snippets_with_this_name = grep {
536 17         55 !defined($_) || $_->names_set->{$name}
537 17         31 } (@{$self->{unmerged_snippets}});
538 17 100       49 return if ! grep { defined } @snippets_with_this_name;
  127         236  
539 64 100       354 return bless
540             {
541             unmerged_snippets => \@snippets_with_this_name,
542 16         40 map { exists $self->{$_} ? ($_ => $self->{$_}) : () }
543             (qw(warnings errors filename start_line) )
544             # Purposefully do not transfer other fields such as
545             # ->{merged_snippets}
546             }, ref($self);
547             }
548              
549             =begin internals
550              
551             =head2 _block_access_if_errors ()
552              
553             Throws an exception if L returns a nonzero value. Called by
554             every read accessor except L and I.
555              
556             =cut
557              
558             sub _block_access_if_errors {
559 49 100   49   168 die <<"MESSAGE" if shift->errors;
560             Cannot fetch parse results from Pod::Snippets with errors.
561             MESSAGE
562             }
563              
564             =head2 _merged_snippets ()
565              
566             Returns roughly the same thing as L in
567             L, except that leading and trailing
568             whitespace is trimmed (updating the line counters appropriately),
569             names are discarded and snippets are merged together (with appropriate
570             padding using $/) according to the semantics set forth in L.
571             This method has a cache.
572              
573             =cut
574              
575             sub _merged_snippets {
576 31     31   52 my ($self) = @_;
577              
578 31   66     126 $self->{merged_snippets} ||= do {
579 26         41 my @snippets;
580 26         46 foreach my $snip (@{$self->{unmerged_snippets}}) {
  26         72  
581 142 100       382 if (! defined($snip)) {
    100          
    100          
582 59 100       175 push @snippets, undef if defined $snippets[-1];
583             } elsif (! @snippets) {
584 26         71 push @snippets, $snip;
585             } elsif (! defined($snippets[-1])) {
586 1         2 $snippets[-1] = $snip;
587             } else {
588             # The merger case.
589 56         158 my $prevstartline = $snippets[-1]->line();
590 56         5631 my $newlines_to_add = $snip->line - $prevstartline
591             - _number_of_newlines_in($snippets[-1]);
592 56 50       500 if ($newlines_to_add < 0) {
593 0         0 my $filename = $self->filename();
594 0         0 warn <<"ASSERTION_FAILED" ;
595             Pod::Snippets: problem counting newlines at $filename
596             near line $prevstartline (trying to skip $newlines_to_add lines)
597             Output will be desynchronized.
598             ASSERTION_FAILED
599 0         0 $newlines_to_add = 0;
600             }
601 56         216 $snippets[-1] = $snippets[-1] . $/ x $newlines_to_add .
602             $snip;
603             }
604             }
605              
606 26 100       97 pop @snippets if ! defined $snippets[-1];
607              
608             # Trim leading and trailing whitespace.
609 26         90 foreach my $i (0..$#snippets) {
610 27         119 my $text = "$snippets[$i]";
611 27         95 my $line = $snippets[$i]->line();
612 27         67 my $nl = $/; # Foils smarter-than-thou regex parser
613 27         3329 while($text =~ s|^\s*$nl||) { $line++ };
  0         0  
614             # This is disturbingly asymetric.
615 27         1376 $text =~ s|(^\s*$nl)*\Z||m;
616 27         134 $snippets[$i] = Pod::Snippets::_Snippet->new
617             ($line, $text, $snippets[$i]->names_set);
618             }
619              
620 26         118 \@snippets;
621             };
622              
623 31         42 return @{$self->{merged_snippets}};
  31         111  
624             }
625              
626             =head2 _number_of_newlines_in($string)
627              
628             This function (B a method) returns the number of times $/ is
629             found in $string.
630              
631             =cut
632              
633             sub _number_of_newlines_in {
634 56     56   26362 my @occurences = shift =~ m|($/)|gs;
635 56         194 return scalar @occurences;
636             }
637              
638             =head1 Pod::Snippets::_Parser
639              
640             This class is a subclass to L, that builds appropriate
641             state on behalf of a I object.
642              
643             =cut
644              
645             package Pod::Snippets::_Parser;
646              
647 7     7   67 use base "Pod::Parser";
  7         40  
  7         28914  
648              
649             =head2 new_for_pod_snippets (-opt1 => $val1, ...)
650              
651             An alternate constructor with a different syntax suited for calling
652             from I. Available named options are:
653              
654             =over
655              
656             =item B<< -markup => $string >>
657              
658             =item B<< -report_errors => $sub >>
659              
660             =item B<< -filename => $filename >>
661              
662             =item B<< -line => $line >>
663              
664             Same as in L, except that all these options are mandatory and
665             therefore caller should substitute appropriate default values if need
666             be.
667              
668             =item B<< -impure => "ignore" >>
669              
670             =item B<< -impure => "warn" >>
671              
672             =item B<< -impure => "error" >>
673              
674             =item B<< -overlap => "ignore" >> and so on
675              
676             The parse flags to use for handling errors, properly decoded from the
677             B<-named_snippets> named argument to L.
678              
679             =back
680              
681             =cut
682              
683             sub new_for_pod_snippets {
684 30     30   190 my ($class, %opts) = @_;
685              
686 30         2808 my $self = $class->new;
687 30         170 while(my ($k, $v) = each %opts) {
688 204         3814 $k =~ s/^(-?)(.*)$/$1pod_snippets_$2/;
689 204         1052 $self->{$k} = $v;
690             }
691 30         123 return $self;
692             }
693              
694             =head2 finalize_pod_snippets ()
695              
696             Called after parsing is done; must raise any and all errors that occur
697             at the end of the file (eg snippets without a closing tag).
698              
699             =cut
700              
701             sub finalize_pod_snippets {
702 30     30   47 my ($self) = @_;
703 30         78 foreach my $snipname ($self->in_named_pod_snippet) {
704 5         19 $self->maybe_raise_pod_snippets_bad_pairing($snipname);
705             }
706             }
707              
708             =head2 command ()
709              
710             Overloaded so as to catch the I markup and keep state
711             accordingly.
712              
713             =cut
714              
715             sub command {
716 759     759   1473 my ($self, $command, $paragraph, $line_num) = @_;
717              
718 759         1585 $self->pod_snippets_source_line_number($line_num);
719              
720 759 100       3458 $self->break_current_pod_snippet, return unless
721             ($command =~ m/^(for|begin|end)/);
722              
723 147 100       2069 $self->break_current_pod_snippet, return unless
724             (my ($details) = $paragraph =~
725             m/\A\s*$self->{-pod_snippets_markup}(.*)$/m);
726              
727             # Accept "=begin test" and "=end test" and do nothing...
728 135 100       447 if (! $details) {
729 3 100       10 $self->ignoring_pod_snippets(0) if ($command eq "for");
730 3         23 return;
731             }
732              
733             # ... But moan about "=begin test ignore".
734 132 100 66     2059 if ($command eq "for" && $details =~ m/\s+ignore\s*$/) {
735 1         3 $self->ignoring_pod_snippets(1);
736 1         7 return;
737             }
738              
739 131 50       963 if (my ($snipname, $subcommand) =
740             $details =~ m/^ \s+ (?: "(.*?)" ) \s* (begin|end)?/x) {
741 131 50 33     716 $command = $subcommand if ($subcommand && $command eq "for");
742 131 100       366 if ($command eq "begin") {
    50          
743 68         182 $self->in_named_pod_snippet($snipname, 1);
744 68         2190 return;
745             } elsif ($command eq "end") {
746 63         152 $self->in_named_pod_snippet($snipname, 0);
747 63         2806 return;
748             }
749             }
750              
751 0         0 my $equals = "="; # Foils smarter-than-thou Pod::Checker. Sigh.
752 0         0 $self->raise_pod_snippets_incident("warning", <<"MESSAGE");
753             Cannot interpret command, ignoring.
754              
755             $equals$command $paragraph
756              
757             MESSAGE
758             }
759              
760             =head2 verbatim ()
761              
762             Overloaded so as to catch and store the verbatim sections.
763              
764             =cut
765              
766             sub verbatim {
767 293     293   444 my ($self, $paragraph, $line_num) = @_;
768              
769 293         626 $self->pod_snippets_source_line_number($line_num);
770              
771 293 100       2557 return if $self->ignoring_pod_snippets;
772 292         327 push(@{$self->{pod_snippets}},
  292         1709  
773             Pod::Snippets::_Snippet->new($line_num, $paragraph,
774             $self->pod_snippets_names()));
775             }
776              
777             =head2 textblock ()
778              
779             =head2 interior_sequence ()
780              
781             These methods are overloaded so as discard the corresponding pieces of
782             POD and to call L instead.
783              
784             =cut
785              
786             sub textblock {
787 490     490   826 my ($self, $paragraph, $line_num) = @_;
788 490         988 $self->pod_snippets_source_line_number($line_num);
789 490         880 $self->break_current_pod_snippet;
790             }
791              
792 0     0   0 sub interior_sequence { shift->break_current_pod_snippet }
793              
794             =head2 break_current_pod_snippet ()
795              
796             Called by L, L and L
797             whenever a piece of POD that is ignored by B is seen in
798             the parse stream. Causes the parser to record the break, pursuant to
799             the snippet aggregation feature set forth in L.
800              
801             =cut
802              
803             sub break_current_pod_snippet {
804 1114     1114   1312 my ($self) = @_;
805 1114 100       7455 $self->maybe_raise_pod_snippets_impure() if
806             $self->in_named_pod_snippet;
807 1114 100       81750 push(@{$self->{pod_snippets}}, undef)
  48         2444  
808             unless (! defined $self->{pod_snippets}->[-1]);
809             }
810              
811             =head2 pod_snippets_source_line_number ()
812              
813             =head2 pod_snippets_source_line_number ($value)
814              
815             Gets or sets the line number that the parser reached, to be used in
816             error messages (after offsetting it by the appropriate amount
817             depending on the setting of the C<-line> named option to
818             L). The setter form is to be called as soon as
819             possible by parser callbacks L, L, L
820             so as to keep in sync with the POD flow.
821              
822             =cut
823              
824             sub pod_snippets_source_line_number {
825 1555     1555   2576 my ($self, @value) = @_;
826 1555 100       3974 $self->{pod_snippets_source_line_number} = $value[0] if @value;
827 1555         2868 return $self->{pod_snippets_source_line_number};
828             }
829              
830             =head3 maybe_raise_pod_snippets_multiple ($name)
831              
832             =head3 maybe_raise_pod_snippets_overlap ($name)
833              
834             =head3 maybe_raise_pod_snippets_impure ()
835              
836             =head3 maybe_raise_pod_snippets_bad_pairing ($name)
837              
838             Maybe passes an error of the respective class to the user-supplied C<<
839             -report_errors >> sub (see L), if the warning and error
840             settings so dictate (as described in the documentation for the C<<
841             -named_snippets >> constructor argument). The $name argument is the
842             name of the snippet that is in scope at the point of error.
843              
844             All these methods are implemented in terms of exactly one call to
845             L.
846              
847             =cut
848              
849             sub maybe_raise_pod_snippets_multiple {
850 5     5   13 my ($self, $name) = @_;
851 5         25 $self->maybe_raise_named_pod_snippets_incident
852             ("multiple", <<"MESSAGE");
853             Snippet "$name" is defined multiple times.
854             MESSAGE
855             }
856              
857             sub maybe_raise_pod_snippets_overlap {
858 5     5   12 my ($self, $name) = @_;
859 5         25 $self->maybe_raise_named_pod_snippets_incident
860             ("overlap", <<"MESSAGE");
861             Snippet "$name" is defined multiple times.
862             MESSAGE
863             }
864              
865             sub maybe_raise_pod_snippets_impure {
866 5     5   11 my ($self) = @_;
867 5         11 my @names_in_scope = map { qq'"$_"' }
  5         19  
868             ($self->in_named_pod_snippet);
869 5 50       18 if (@names_in_scope > 1) {
870 0         0 my $names_in_scope = join(", ", @names_in_scope);
871 0         0 $self->maybe_raise_named_pod_snippets_incident
872             ("impure", <<"MESSAGE");
873             Snippets $names_in_scope are impure (ie they
874             contain intervening non-verbatim POD)
875             MESSAGE
876             } else {
877 5         22 $self->maybe_raise_named_pod_snippets_incident
878             ("impure", <<"MESSAGE");
879             Snippet $names_in_scope[0] is impure (ie it
880             contains intervening non-verbatim POD)
881             MESSAGE
882             }
883             }
884              
885             sub maybe_raise_pod_snippets_bad_pairing {
886 5     5   51 my ($self, $name) = @_;
887 5         23 $self->maybe_raise_named_pod_snippets_incident
888             ("bad_pairing", <<"MESSAGE");
889             Snippet "$name" has mismatched or missing opening and closing markers.
890             MESSAGE
891             }
892              
893             =head3 maybe_raise_named_pod_snippets_incident ($errclass, $message)
894              
895             Calls L with $message if appropriate
896             given the parser warning and error level settings for C<$errclass>
897             (one of "impure", "overlap", "bad_pairing" or "multiple"). See the
898             C<-named_snippets> argument to L for details.
899              
900             =cut
901              
902             sub maybe_raise_named_pod_snippets_incident {
903 20     20   40 my ($self, $errclass, $message) = @_;
904              
905 20         51 my $severity = $self->{"-pod_snippets_$errclass"};
906 20 100 100     96 if ((! defined $severity) || ($severity eq "ignore")) {
907 7         18 return;
908             } else {
909 13         59 $self->raise_pod_snippets_incident($severity, $message);
910             }
911             }
912              
913             =head2 Fancy accessors
914              
915             Yes, we want them even in a totally private class: they are so helpful
916             in making the code easier to understand, debug and refactor.
917              
918             =head3 in_named_pod_snippet ($name, $boolean)
919              
920             Tells the parser state machine that we are entering ($boolean true) or
921             leaving ($boolean false) a POD snippet named $name. This operation
922             can cause L and/or
923             L to be invoked as a side effect.
924              
925             =head3 in_named_pod_snippet ($name)
926              
927             Returns true iff the parser is currently in the middle of a POD snippet
928             named $name.
929              
930             =head3 in_named_pod_snippet ()
931              
932             Returns true iff the parser is currently in the middle of any named
933             POD snippet, regardless of the name. (In array context, returns the
934             list of all snippet names the parser is in).
935              
936             =cut
937              
938             sub in_named_pod_snippet {
939 1479     1479   3563 my ($self, @args) = @_;
940 1479   100     3309 $self->{pod_snippets_names_in_scope} ||= {};
941 1479 100       3697 if (@args >= 2) {
    100          
942 131         203 my ($snipname, $bool) = @args;
943 131 100       240 if ($bool) { # Entering
944 68 100       258 $self->maybe_raise_pod_snippets_multiple($snipname) if
945             exists $self->{pod_snippets_names_in_scope}->{$snipname};
946 68 100       210 $self->maybe_raise_pod_snippets_overlap($snipname) if
947             $self->in_named_pod_snippet;
948 68 50       163 $self->maybe_raise_pod_snippets_bad_pairing($snipname) if
949             $self->in_named_pod_snippet($snipname);
950 68         480 $self->{pod_snippets_names_in_scope}->{$snipname} = 1;
951             } else { # Leaving
952 63 50       169 $self->maybe_raise_pod_snippets_bad_pairing($snipname) if
953             ! $self->in_named_pod_snippet($snipname);
954 63         233 $self->{pod_snippets_names_in_scope}->{$snipname} = 0;
955             }
956             } elsif (@args == 1) {
957 131         561 return !!$self->{pod_snippets_names_in_scope}->{$args[0]};
958             } else {
959 5039         31811 return grep { $self->{pod_snippets_names_in_scope}->{$_} }
  1217         3416  
960 1217         1479 (keys %{$self->{pod_snippets_names_in_scope}});
961             }
962             }
963              
964             =head3 pod_snippets_names ()
965              
966             Returns a reference to a newly-constructed (thus unshared) hash whose
967             keys are the POD snippet names that have been seen by the parser so
968             far, and the values are true iff we are currently inside a POD snippet
969             of the corresponding name.
970              
971             =cut
972              
973             sub pod_snippets_names {
974 292 50   292   342 return {%{shift->{pod_snippets_names_in_scope} || {}}}
  292         1993  
975             }
976              
977             =head3 ignoring_pod_snippets ()
978              
979             =head3 ignoring_pod_snippets ($value)
980              
981             Gets or sets the "ignoring snippets" flag in the parser state.
982              
983             =cut
984              
985             sub ignoring_pod_snippets {
986 295     295   5543 my ($self, @value) = @_;
987 295 100       619 $self->{ignoring_pod_snippets} = $value[0] if @value;
988 295         746 return $self->{ignoring_pod_snippets};
989             }
990              
991             =head3 pod_snippets ()
992              
993             Returns the parsed snippets as a list that contains undef values and
994             references to instances of L. The undef
995             values indicate that some non-snippet block or markup was seen at that
996             point, and that snippets should not be merged by L over such
997             a boundary.
998              
999             =cut
1000              
1001 30     30   103 sub pod_snippets { shift->{pod_snippets} }
1002              
1003             =head3 pod_snippets_warnings ()
1004              
1005             =head3 pod_snippets_errors ()
1006              
1007             Returns the number of times L
1008             (resp. L) was called during the parsing of this
1009             Perl module. These do B account for warnings and/or errors due
1010             to malformed POD that may be emitted by L.
1011              
1012             =head3 raise_pod_snippets_incident ($kind, $message)
1013              
1014             Called whenever the parser issues a warning, resp. an error; calls the
1015             user-supplied C<< -report_errors >> sub (see L) or a default
1016             surrogate thereof. Also increments the relevant warning and error
1017             counters. $kind is either "warning" or "error" (in lowercase);
1018             $message is the message to print (I18N be screwed).
1019              
1020             =cut
1021              
1022             # And now for some awesome metaprogramming goodness.
1023             foreach my $property (qw(warnings errors)) {
1024             my $fieldname = "pod_snippets_$property";
1025 60 100   60   366 my $accessor = sub { shift->{$fieldname} || 0 };
1026 7     7   61 no strict "refs";
  7         17  
  7         1557  
1027             *{$fieldname} = $accessor;
1028             }
1029              
1030             sub raise_pod_snippets_incident {
1031 13     13   19 my ($self, $incident, $message) = @_;
1032 13         59 $self->{-pod_snippets_report_errors}->
1033             (uc($incident), $message, $self->{-pod_snippets_filename},
1034             $self->pod_snippets_source_line_number +
1035             $self->{-pod_snippets_line} - 1);
1036 13         111 $self->{"pod_snippets_${incident}s"}++;
1037             }
1038              
1039             =head2 Pod::Snippets::_Snippet
1040              
1041             An instance of this class represents one snippet in the POD.
1042             Instances are immutable, and stringifiable for added goodness.
1043              
1044             =cut
1045              
1046             package Pod::Snippets::_Snippet;
1047              
1048             =head3 new ($lineno, $rawtext, $names_set)
1049              
1050             Creates and returns a B object. $lineno is
1051             the line number where the snippet starts in the original file.
1052             $rawtext is the text of the snippet without any formatting applied:
1053             there may be extraneous whitespace at the beginning and end, and the
1054             ragging is not performed. $names_set is a reference to a set (that
1055             is, a hash where only the boolean status of the values matter) of all
1056             snippet names that are in scope for this snippet.
1057              
1058             =cut
1059              
1060             sub new {
1061 319     319   551 my ($class, $lineno, $rawtext, $names_set) = @_;
1062              
1063 319         15352 return bless {
1064             line => $lineno,
1065             text => $rawtext,
1066             names => $names_set,
1067             }, $class;
1068             }
1069              
1070             =head3 stringify ()
1071              
1072             Returns the snippet text. This is also what happens when one
1073             evaluatess the snippet object as a string.
1074              
1075             =cut
1076              
1077 7     7   11505 use overload '""' => "stringify";
  7         8641  
  7         55  
1078 220     220   1528 sub stringify { shift->{text} }
1079              
1080             =head3 is_named ($name)
1081              
1082             Returns true iff $name is in scope at this snippet's text location.
1083              
1084             =cut
1085              
1086 0     0   0 sub is_named { !! shift->{names}->{shift()} }
1087              
1088             =head3 line ()
1089              
1090             Returns this snippet's line number.
1091              
1092             =cut
1093              
1094 144     144   347 sub line { shift->{line} }
1095              
1096             =head3 append_text ($text)
1097              
1098             Computes and returns a new snippet that has extra $text appended at
1099             the end. This is also what happens when one uses the L
1100             operator on a snippet.
1101              
1102             =cut
1103              
1104 7     7   1024 use overload '.' => "append_text";
  7         15  
  7         31  
1105             sub append_text {
1106 112     112   192 my ($self, $text) = @_;
1107 224         1614 return bless {
1108             text => "$self->{text}" . "$text",
1109 112         310 map { ($_ => $self->{$_}) } (qw(line names)),
1110             }, ref($self);
1111             }
1112              
1113             =head3 names_set ()
1114              
1115             Returns the $names_set parameter to L.
1116              
1117             =cut
1118              
1119 416     416   1721 sub names_set { shift->{names} }
1120              
1121             =end internals
1122              
1123             =head1 SEE ALSO
1124              
1125             L
1126              
1127             =head1 AUTHOR
1128              
1129             Dominique QUATRAVAUX, C<< >>
1130              
1131             =head1 BUGS
1132              
1133             Please report any bugs or feature requests to
1134             C, or through the web interface at
1135             L.
1136             I will be notified, and then you'll automatically be notified of progress on
1137             your bug as I make changes.
1138              
1139             =head1 ACKNOWLEDGEMENTS
1140              
1141             Yanick Champoux is the author of
1142             L which grandfathers this module.
1143              
1144             =head1 COPYRIGHT & LICENSE
1145              
1146             Copyright 2007 Dominique QUATRAVAUX, all rights reserved.
1147              
1148             This program is free software; you can redistribute it and/or modify it
1149             under the same terms as Perl itself.
1150              
1151             =cut
1152              
1153             1; # End of Pod::Snippets
1154