File Coverage

blib/lib/Test/Inline/Extract.pm
Criterion Covered Total %
statement 38 38 100.0
branch 9 14 64.2
condition n/a
subroutine 13 13 100.0
pod 2 2 100.0
total 62 67 92.5


line stmt bran cond sub pod time code
1             package Test::Inline::Extract;
2              
3             =pod
4              
5             =head1 NAME
6              
7             Test::Inline::Extract - Extract relevant Pod sections from source
8             code.
9              
10             =head1 DESCRIPTION
11              
12             The Test::Inline::Extract package extracts content interesting to
13             L from source files.
14              
15             =head1 METHODS
16              
17             =cut
18              
19 13     13   52986 use strict;
  13         24  
  13         418  
20 13     13   74 use List::Util ();
  13         23  
  13         180  
21 13     13   64 use File::Slurp ();
  13         21  
  13         266  
22 13     13   1073 use Params::Util qw{_CLASS _INSTANCE _SCALAR};
  13         7631  
  13         806  
23              
24 13     13   67 use vars qw{$VERSION};
  13         20  
  13         589  
25             BEGIN {
26 13     13   2838 $VERSION = '2.213';
27             }
28              
29              
30              
31              
32              
33             #####################################################################
34             # Constructor
35              
36             =pod
37              
38             =head2 new $file | \$source
39              
40             The C constructor creates a new Extract object. It is passed either a
41             file name from which the source code would be loaded, or a reference to a
42             string that directly contains source code.
43              
44             Returns a new C object or C on error.
45              
46             =cut
47              
48             sub new {
49 22 50   22 1 2065 my $class = _CLASS(shift) or die '->new is a static method';
50              
51             # Get the source code to process, and clean it up
52 22 50       360 my $source = $class->_source(shift) or return undef;
53 22         215 $source = $$source;
54 22         1614 $source =~ s/(?:\015{1,2}\012|\015|\012)/\n/g;
55              
56             # Create the object
57 22         133 my $self = bless {
58             source => $source,
59             elements => undef,
60             }, $class;
61              
62 22         167 $self;
63             }
64              
65             sub _source {
66 22     22   43 my $self = shift;
67 22 50       74 return undef unless defined $_[0];
68 22 100       178 return shift if _SCALAR($_[0]);
69 1 50       5 return undef if ref $_[0];
70 1         7 File::Slurp::read_file( shift, scalar_ref => 1 );
71             }
72              
73             =pod
74              
75             =head2 elements
76              
77             my $elements = $Extract->elements;
78              
79             The C method extracts from the Pod any parts of the file that are
80             relevant to the extraction and generation process of C.
81              
82             The elements will be either a package statements, or a section of inline
83             unit tests. They will only be returned if there is at least one section
84             of inline unit tests.
85              
86             Returns a reference to an array of package strings and sections of inline
87             unit tests. Returns false if there are no sections containing inline
88             unit tests.
89              
90             =cut
91              
92             # Define the search pattern we will use
93 13     13   70 use vars qw{$search};
  13         23  
  13         3240  
94             BEGIN {
95 13     13   2187 $search = qr/
96             (?:^|\n) # After the beginning of the string, or a newline
97             ( # ... start capturing
98             # EITHER
99             package\s+ # A package
100             [^\W\d]\w*(?:(?:\'|::)[^\W\d]\w*)* # ... with a name
101             \s*; # And a statement terminator
102             | # OR
103             =for[ \t]+example[ \t]+begin\n # ... when we find a =for example begin
104             .*? # ... and keep capturing
105             \n=for[ \t]+example[ \t]+end\s*? # ... until the =for example end
106             (?:\n|$) # ... at the end of file or a newline
107             | # OR
108             =begin[ \t]+(?:test|testing)\b # ... when we find a =begin test or testing
109             .*? # ... and keep capturing
110             \n=end[ \t]+(?:test|testing)\s*? # ... until an =end tag
111             (?:\n|$) # ... at the end of file or a newline
112             ) # ... and stop capturing
113             /isx;
114             }
115              
116             sub elements {
117 22 50   22 1 1290 $_[0]->{elements} or
118             $_[0]->{elements} = $_[0]->_elements;
119             }
120              
121             sub _elements {
122 22     22   38 my $self = shift;
123 22         49 my @elements = ();
124 22         293 while ( $self->{source} =~ m/$search/go ) {
125 83         956 push @elements, $1;
126             }
127 22 100   41   193 (List::Util::first { /^=/ } @elements) ? \@elements : '';
  41         343  
128             }
129              
130             1;
131              
132             =pod
133              
134             =head1 TO DO
135              
136             - For certain very complex cases, add a more intensive alternative parser
137             based on PPI
138              
139             =head1 SUPPORT
140              
141             See the main L section.
142              
143             =head1 AUTHOR
144              
145             Adam Kennedy Eadamk@cpan.orgE, L
146              
147             =head1 COPYRIGHT
148              
149             Copyright 2004 - 2013 Adam Kennedy.
150              
151             This program is free software; you can redistribute
152             it and/or modify it under the same terms as Perl itself.
153              
154             The full text of the license can be found in the
155             LICENSE file included with this module.
156              
157             =cut