File Coverage

blib/lib/Pod/Tests.pm
Criterion Covered Total %
statement 109 132 82.5
branch 35 44 79.5
condition 16 25 64.0
subroutine 14 17 82.3
pod 8 8 100.0
total 182 226 80.5


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