File Coverage

blib/lib/Pod/Tests.pm
Criterion Covered Total %
statement 114 137 83.2
branch 35 44 79.5
condition 17 25 68.0
subroutine 16 19 84.2
pod 8 8 100.0
total 190 233 81.5


line stmt bran cond sub pod time code
1             package Pod::Tests;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Pod::Tests - Extracts embedded tests and code examples from POD
8              
9             =head1 SYNOPSIS
10              
11             use Pod::Tests;
12             $p = Pod::Tests->new;
13              
14             $p->parse_file($file);
15             $p->parse_fh($fh);
16             $p->parse(@code);
17              
18             my @examples = $p->examples;
19             my @tests = $p->tests;
20              
21             foreach my $example (@examples) {
22             print "The example: '$example->{code}' was on line ".
23             "$example->{line}\n";
24             }
25              
26             my @test_code = $p->build_tests(@tests);
27             my @example_test_code = $p->build_examples(@examples);
28              
29             =head1 DESCRIPTION
30              
31             This is a specialized POD viewer to extract embedded tests and code
32             examples from POD. It doesn't do much more than that. pod2test does
33             the useful work.
34              
35             =head2 Parsing
36              
37             After creating a Pod::Tests object, you parse the POD by calling one
38             of the available parsing methods documented below. You can call parse
39             as many times as you'd like, all examples and tests found will stack
40             up inside the object.
41              
42             =head2 Testing
43              
44             Once extracted, the tests can be built into stand-alone testing code
45             using the build_tests() and build_examples() methods. However, it is
46             recommended that you first look at the pod2test program before
47             embarking on this.
48              
49             =head2 Methods
50              
51             =cut
52              
53 2     2   25989 use 5.005;
  2         7  
  2         78  
54 2     2   14 use strict;
  2         3  
  2         77  
55 2     2   20 use vars qw($VERSION);
  2         4  
  2         148  
56             BEGIN {
57 2     2   3391 $VERSION = '1.19';
58             }
59              
60              
61              
62              
63              
64             #####################################################################
65             # Constructor
66              
67             =pod
68              
69             =head2 new
70              
71             $parser = Pod::Tests->new;
72              
73             Returns a new Pod::Tests object which lets you read tests and examples
74             out of a POD document.
75              
76             =cut
77              
78             sub new {
79 1     1 1 15 my ($proto) = shift;
80 1   33     8 my ($class) = ref $proto || $proto;
81              
82 1         4 my $self = bless {}, $class;
83 1         7 $self->_init;
84 1         2 $self->{example} = [];
85 1         4 $self->{testing} = [];
86              
87 1         4 return $self;
88             }
89              
90              
91              
92              
93              
94             #####################################################################
95             # Pod::Tests Methods
96              
97             =pod
98              
99             =head2 parse
100              
101             $parser->parse(@code);
102              
103             Finds the examples and tests in a bunch of lines of Perl @code. Once
104             run they're available via examples() and testing().
105              
106             =cut
107              
108             sub parse {
109 2     2 1 5 my ($self) = shift;
110              
111 2         5 $self->_init;
112 2         11 foreach (@_) {
113 236 100 66     981 if ( /^=(\w.*)/ and $self->{_sawblank} and !$self->{_inblock}) {
    100 100        
114 42         57 $self->{_inpod} = 1;
115              
116 42         110 my ($tag, $for, $pod) = split /\s+/, $1, 3;
117              
118 42 100       125 if ( $tag eq 'also' ) {
119 4         5 $tag = $for;
120 4         8 ($for, $pod) = split /\s+/, $pod, 2;
121             }
122              
123 42 100       85 if ( $tag eq 'for' ) {
    100          
    100          
124 28         52 $self->_beginfor($for, $pod);
125             } elsif ( $tag eq 'begin' ) {
126 6         12 $self->_beginblock($for);
127             } elsif ( $tag eq 'cut' ) {
128 4         5 $self->{_inpod} = 0;
129             }
130              
131 42         58 $self->{_sawblank} = 0;
132             } elsif ( $self->{_inpod} ) {
133 184 100 100     773 if (
      66        
134             (/^=(?:also )?end (\S+)/ or /^=for (\S+) end\b/)
135             and
136             $self->{_inblock} eq $1
137             ) {
138 16         35 $self->_endblock;
139 16         21 $self->{_sawblank} = 0;
140             } else {
141 168 100 100     562 if ( /^\s*$/ ) {
    100          
142 86 100       173 $self->_endfor() if $self->{_infor};
143 86         101 $self->{_sawblank} = 1;
144             } elsif ( !$self->{_inblock} and !$self->{_infor} ) {
145 18         34 $self->_sawsomethingelse;
146 18         21 $self->{_sawblank} = 0;
147             }
148 168         243 $self->{_currpod} .= $_;
149             }
150             } else {
151 10 100       27 if ( /^\s*$/ ) {
152 6         11 $self->{_sawblank} = 1;
153             } else {
154 4         11 $self->_sawsomethingelse;
155             }
156             }
157              
158 236         318 $self->{_linenum}++;
159             }
160              
161 2         5 $self->_endfor;
162              
163 2         2 push @{$self->{example}}, @{$self->{_for}{example}};
  2         4  
  2         7  
164 2         3 push @{$self->{testing}}, @{$self->{_for}{testing}};
  2         4  
  2         5  
165 2         3 push @{$self->{example_testing}}, @{$self->{_for}{example_testing}};
  2         4  
  2         7  
166             }
167              
168             #=head2 _init
169             #
170             # $parser->_init;
171             #
172             #Initializes the state of the parser, but not the rest of the object.
173             #Should be called before each parse of new POD.
174             sub _init {
175 3     3   6 my ($self) = shift;
176 3         12 $self->{_sawblank} = 1;
177 3         5 $self->{_inblock} = 0;
178 3         7 $self->{_infor} = 0;
179 3         5 $self->{_inpod} = 0;
180 3         6 $self->{_linenum} = 1;
181 3         15 $self->{_for} = {
182             example => [],
183             testing => [],
184             example_testing => [],
185             };
186             }
187              
188             sub _sawsomethingelse {
189 22     22   28 my ($self) = shift;
190 22         33 $self->{_lasttype} = 0;
191             }
192              
193             #=head2 _beginfor
194             #
195             # $parser->_beginfor($format, $pod);
196             #
197             #Indicates that a =for tag has been seen. $format (what immediately
198             #follows '=for'), and $pod is the rest of the POD on that line.
199             sub _beginfor {
200 28     28   47 my ($self, $for, $pod) = @_;
201            
202 28 100 100     77 if ( $for eq 'example' and defined $pod ) {
203 10 50       18 if ( $pod eq 'begin' ) {
    0          
204 10         21 return $self->_beginblock($for);
205             } elsif ( $pod eq 'end' ) {
206 0         0 return $self->_endlblock;
207             }
208             }
209            
210 18         24 $self->{_infor} = $for;
211 18         23 $self->{_currpod} = $pod;
212 18         32 $self->{_forstart} = $self->{_linenum};
213             }
214              
215             #=head2 _endfor
216             #
217             # $parser->endfor;
218             #
219             #Indicates that the current =for block has ended.
220             sub _endfor {
221 20     20   29 my ($self) = shift;
222              
223 20         64 my $pod = {
224             code => $self->{_currpod},
225             # Skip over the "=for" line
226             line => $self->{_forstart} + 1,
227             };
228              
229 20 100       67 if ( $self->{_infor} ) {
230 18 100       35 if ( $self->{_infor} eq 'example_testing' ) {
231 4         10 $self->_example_testing($pod);
232             }
233              
234 18 100       34 if ( $self->{_infor} eq $self->{_lasttype}) {
235 4         5 my $last_for = ${$self->{_for}{$self->{_infor}}}[-1];
  4         9  
236 4         15 $last_for->{code} .= "\n" x ($pod->{line} -
237             ($last_for->{line} +
238             $last_for->{code} =~ tr/\n//)
239             );
240 4         9 $last_for->{code} .= $self->{_currpod};
241            
242             } else {
243 14         14 push @{$self->{_for}{$self->{_infor}}}, $pod;
  14         53  
244             }
245             }
246            
247 20         29 $self->{_lasttype} = $self->{_infor};
248 20         35 $self->{_infor} = 0;
249             }
250              
251             #=head2 _beginblock
252             #
253             # $parser->_beginblock($format);
254             #
255             #Indicates that the parser saw a =begin tag. $format is the word
256             #immediately following =begin.
257             sub _beginblock {
258 16     16   21 my ($self, $for) = @_;
259              
260 16         19 $self->{_inblock} = $for;
261 16         25 $self->{_currpod} = '';
262 16         35 $self->{_blockstart} = $self->{_linenum};
263             }
264              
265             #=head2 _endblock
266             #
267             # $parser->_endblock
268             #
269             #Indicates that the parser saw an =end tag for the current block.
270             sub _endblock {
271 16     16   21 my ($self) = shift;
272              
273 16         57 my $pod = {
274             code => $self->{_currpod},
275             # Skip over the "=begin"
276             line => $self->{_blockstart} + 1,
277             };
278              
279 16 50       39 if ( $self->{_inblock} ) {
280 16 50       30 if ( $self->{_inblock} eq 'example_testing' ) {
281 0         0 $self->_example_testing($self->{_currpod});
282             }
283              
284 16 100       29 if ( $self->{_inblock} eq $self->{_lasttype}) {
285 2         3 my $last_for = ${$self->{_for}{$self->{_inblock}}}[-1];
  2         5  
286 2         7 $last_for->{code} .= "\n" x ($pod->{line} -
287             ($last_for->{line} +
288             $last_for->{code} =~ tr/\n//)
289             );
290 2         6 $last_for->{code} .= $self->{_currpod};
291            
292             } else {
293 14         14 push @{$self->{_for}{$self->{_inblock}}}, $pod;
  14         31  
294             }
295             }
296              
297 16         26 $self->{_lasttype} = $self->{_inblock};
298 16         26 $self->{_inblock} = 0;
299             }
300              
301             sub _example_testing {
302 4     4   5 my ($self, $test) = @_;
303              
304 4         5 my $last_example = ${$self->{_for}{example}}[-1];
  4         9  
305 4         14 $last_example->{code} .= "\n" x ($test->{line} -
306             ($last_example->{line} +
307             $last_example->{code} =~ tr/\n//)
308             );
309              
310 4         10 $last_example->{testing} = $test->{code};
311             }
312              
313             =pod
314              
315             =head2 parse_file $file
316              
317             $parser->parse_file($filename);
318              
319             Just like parse() except it works on a file.
320              
321             =cut
322              
323             sub parse_file {
324 0     0 1 0 my ($self, $file) = @_;
325              
326 0 0       0 unless( open(POD, $file) ) {
327 0         0 warn "Couldn't open POD file $file: $!\n";
328 0         0 return;
329             }
330              
331 0         0 return $self->parse_fh(\*POD);
332             }
333              
334             =pod
335              
336             =head2 parse_fh $fh
337              
338             $parser->parse_fh($fh);
339              
340             Just like parse() except it works on a filehandle.
341              
342             =cut
343              
344             sub parse_fh {
345 2     2 1 3540 my ($self, $fh) = @_;
346              
347             # Yeah, this is inefficient. Sue me.
348 2         112 return $self->parse(<$fh>);
349             }
350              
351             =pod
352              
353             =head2 tests
354              
355             @testing = $parser->tests;
356              
357             Returns the tests found in the parsed POD documents. Each element of
358             @testing is a hash representing an individual testing block and contains
359             information about that block.
360              
361             $test->{code} actual testing code
362             $test->{line} line from where the test was taken
363              
364             =cut
365              
366             sub tests {
367 2     2 1 21 my ($self) = shift;
368 2         2 return @{$self->{testing}};
  2         8  
369             }
370              
371             =pod
372              
373             =head2 examples
374              
375             @examples = $parser->examples;
376              
377             Returns the examples found in the parsed POD documents. Each element of
378             @examples is a hash representing an individual testing block and contains
379             information about that block.
380              
381             $test->{code} actual testing code
382             $test->{line} line from where the test was taken
383              
384             =cut
385              
386             sub examples {
387 2     2 1 5 my ($self) = shift;
388 2         4 return @{$self->{example}};
  2         6  
389             }
390              
391             =pod
392              
393             =head2 build_tests
394              
395             my @code = $p->build_tests(@tests);
396              
397             Returns a code fragment based on the given embedded @tests. This
398             fragment is expected to print the usual "ok/not ok" (or something
399             Test::Harness can read) or nothing at all.
400              
401             Typical usage might be:
402              
403             my @code = $p->build_tests($p->tests);
404              
405             This fragment is suitable for placing into a larger test script.
406              
407             B Look at pod2test before embarking on your own test building.
408              
409             =cut
410              
411             sub build_tests {
412 0     0 1   my ($self, @tests) = @_;
413              
414 0           my @code = ();
415              
416 0           foreach my $test (@tests) {
417 0   0       my $file = $self->{file} || '';
418 0           push @code, <
419             {
420             undef \$main::_STDOUT_;
421             undef \$main::_STDERR_;
422             #line $test->{line} $file
423             $test->{code}
424             undef \$main::_STDOUT_;
425             undef \$main::_STDERR_;
426             }
427             CODE
428              
429             }
430              
431 0           return @code;
432             }
433              
434             =pod
435              
436             =head2 build_examples
437              
438             my @code = $p->build_examples(@examples);
439              
440             Similar to build_tests(), it creates a code fragment which tests the
441             basic validity of your example code. Essentially, it just makes sure
442             it compiles.
443              
444             If your example has an "example testing" block associated with it it
445             will run the the example code and the example testing block.
446              
447             =cut
448              
449             sub build_examples {
450 0     0 1   my ($self, @examples) = @_;
451              
452 0           my @code = ();
453 0           foreach my $example (@examples) {
454 0   0       my $file = $self->{file} || '';
455 0           push @code, <
456             undef \$main::_STDOUT_;
457             undef \$main::_STDERR_;
458             eval q{
459             my \$example = sub {
460             local \$^W = 0;
461              
462             #line $example->{line} $file
463             $example->{code};
464              
465             }
466             };
467             is(\$@, '', "example from line $example->{line}");
468             CODE
469              
470 0 0         if ( $example->{testing} ) {
471 0           $example->{code} .= $example->{testing};
472 0           push @code, $self->build_tests($example);
473             }
474              
475 0           push @code, <
476             undef \$main::_STDOUT_;
477             undef \$main::_STDERR_;
478             CODE
479             }
480              
481 0           return @code;
482             }
483              
484             1;
485              
486             =pod
487              
488             =head1 EXAMPLES
489              
490             Here's the simplest example, just finding the tests and examples in a
491             single module.
492              
493             my $p = Pod::Tests->new;
494             $p->parse_file("path/to/Some.pm");
495              
496             And one to find all the tests and examples in a directory of files. This
497             illustrates building a set of examples and tests through multiple calls
498             to parse_file().
499              
500             my $p = Pod::Tests->new;
501             opendir(PODS, "path/to/some/lib/") || die $!;
502             while( my $file = readdir PODS ) {
503             $p->parse_file($file);
504             }
505             printf "Found %d examples and %d tests in path/to/some/lib\n",
506             scalar $p->examples, scalar $p->tests;
507              
508             Finally, an example of parsing your own POD using the DATA filehandle.
509              
510             use Fcntl qw(:seek);
511             my $p = Pod::Tests->new;
512              
513             # Seek to the beginning of the current code.
514             seek(DATA, 0, SEEK_SET) || die $!;
515             $p->parse_fh(\*DATA);
516              
517             =head2 SUPPORT
518              
519             This module has been replaced by the newer L 2. Most testing
520             code that currently works with C should continue to work with
521             the new version. The most notable exceptions are C<=for begin> and
522             C<=for end>, which are deprecated.
523              
524             After upgrading, Pod::Tests and C were split out to provide
525             a compatibility package for legacy code.
526              
527             C will stay in CPAN, but should remain unchanged indefinately,
528             with the exception of any minor bugs that will require squishing.
529              
530             Bugs in this dist should be reported via the following URL. Feature requests
531             should not be submitted, as further development is now occuring in
532             L.
533              
534             L
535              
536             =head1 AUTHOR
537              
538             Michael G Schwern Eschwern@pobox.comE
539              
540             Adam Kennedy Eadamk@cpan.orgE
541              
542             =head1 SEE ALSO
543              
544             L
545              
546             L, Perl 6 RFC 183 http://dev.perl.org/rfc183.pod
547              
548             Short set of slides on Pod::Tests
549             http://www.pobox.com/~schwern/talks/Embedded_Testing/
550              
551             Similar schemes can be found in L and L.
552              
553             =head1 COPYRIGHT
554              
555             Copyright 2005 - 2008 Adam Kennedy.
556              
557             Copyright 2001 - 2003 Michael G Schwern.
558              
559             This program is free software; you can redistribute
560             it and/or modify it under the same terms as Perl itself.
561              
562             The full text of the license can be found in the
563             LICENSE file included with this module.
564              
565             =cut