File Coverage

blib/lib/Test/Requires/Scanner.pm
Criterion Covered Total %
statement 74 92 80.4
branch 42 48 87.5
condition 21 27 77.7
subroutine 11 13 84.6
pod 3 4 75.0
total 151 184 82.0


line stmt bran cond sub pod time code
1             package Test::Requires::Scanner;
2 3     3   63682 use 5.008001;
  3         12  
  3         130  
3 3     3   18 use strict;
  3         5  
  3         111  
4 3     3   27 use warnings;
  3         6  
  3         169  
5              
6             our $VERSION = "0.01";
7              
8 3     3   11529 use Compiler::Lexer;
  3         27155  
  3         289  
9              
10 3     3   2773 use Test::Requires::Scanner::Constants;
  3         14  
  3         424  
11 3     3   2751 use Test::Requires::Scanner::Walker;
  3         11  
  3         141  
12 3     3   2256 use Test::Requires::Scanner::Result;
  3         9  
  3         3080  
13              
14             sub scan_file {
15 0     0 1 0 my ($class, $file) = @_;
16              
17 0         0 my $content = do {
18 0         0 local $/;
19 0 0       0 open my $fh, '<', $file or die $!;
20 0         0 <$fh>;
21             };
22              
23 0         0 $class->scan_string($content);
24             }
25              
26             sub scan_files {
27 0     0 1 0 my ($class, @files) = @_;
28              
29 0         0 my $result = Test::Requires::Scanner::Result->new;
30              
31 0         0 for my $file (@files) {
32 0         0 my $ret = Test::Requires::Scanner->scan_file($file);
33 0         0 $result->save_module($_, $ret->{$_}) for keys %$ret;
34             }
35              
36 0         0 $result->modules;
37             }
38              
39             sub scan_string {
40 7     7 1 4212 my ($class, $string) = @_;
41              
42 7         36 my $lexer = Compiler::Lexer->new;
43 7         1704 my $tokens = $lexer->tokenize($string);
44              
45 7         34 $class->scan_tokens($tokens);
46             }
47              
48             sub scan_tokens {
49 7     7 0 14 my ($class, $tokens) = @_;
50              
51 7         38 my $walker = Test::Requires::Scanner::Walker->new;
52 7         79 my $result = Test::Requires::Scanner::Result->new;
53 7         47 for my $token (@$tokens) {
54 128         225 my $token_type = $token->{type};
55              
56             # For use statement
57 128 100       220 if ($token_type == USE_DECL) {
58 15         39 $walker->is_in_usedecl(1);
59 15         100 $walker->is_prev_module_name(1);
60 15         83 next;
61             }
62 113 100       247 if ($walker->is_in_usedecl) {
63             # e.g.
64             # use Foo;
65 98 100 100     681 if (
66             $token_type == USED_NAME || # e.g. use Foo
67             $token_type == SEMI_COLON # End of declare of use statement
68             ) {
69 10         30 $walker->reset;
70 10         65 next;
71             }
72              
73             # e.g.
74             # use Foo::Bar;
75 88 100 100     355 if ( ($token_type == NAMESPACE || $token_type == NAMESPACE_RESOLVER) && $walker->is_prev_module_name) {
      66        
76 40         246 $walker->{module_name} .= $token->{data};
77 40 100       90 if ($walker->module_name =~ /^Test(?:\:\:(?:Requires)?)?$/) {
78 37         289 $walker->is_prev_module_name(1);
79 37         242 $walker->is_in_test_requires($walker->module_name eq 'Test::Requires');
80             }
81             else {
82 3         23 $walker->reset;
83             }
84 40         313 next;
85             }
86              
87 48 50 33     113 if (!$walker->module_name && !$walker->does_garbage_exist && _looks_like_version($token_type)) {
      33        
88             # For perl version
89             # e.g.
90             # use 5.012;
91 0         0 $walker->reset;
92 0         0 next;
93             }
94              
95             # Section for Test::Requires
96 48 50       318 if ($walker->is_in_test_requires) {
97 48         268 $walker->is_prev_module_name(0);
98              
99             # For qw() notation
100             # e.g.
101             # use Test::Requires qw/Foo Bar/;
102 48 100       273 if ($token_type == REG_LIST) {
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
103 1         3 $walker->is_in_reglist(1);
104             }
105             elsif ($walker->is_in_reglist) {
106             # skip regdelim
107 2 100       11 if ($token_type == REG_EXP) {
108 1         6 for my $_module_name (split /\s+/, $token->{data}) {
109 2         6 $result->save_module($_module_name);
110             }
111 1         5 $walker->is_in_reglist(0);
112             }
113             }
114              
115             # For simply list
116             # e.g.
117             # use Test::Requires ('Foo', 'Bar');
118             elsif ($token_type == LEFT_PAREN) {
119 3         18 $walker->is_in_list(1);
120             }
121             elsif ($token_type == RIGHT_PAREN) {
122 3         34 $walker->is_in_list(0);
123             }
124             elsif ($walker->is_in_list) {
125 7 100 100     75 if ($token_type == STRING || $token_type == RAW_STRING) {
126 5         16 $result->save_module($token->{data});
127             }
128             }
129              
130             # For braced list
131             # e.g.
132             # use Test::Requires {'Foo' => 1, 'Bar' => 2};
133             elsif ($token_type == LEFT_BRACE ) {
134 3         39 $walker->is_in_hash(1);
135 3         17 $walker->hash_count(0);
136             }
137             elsif ($token_type == RIGHT_BRACE ) {
138 3         35 $walker->is_in_hash(0);
139             }
140             elsif ($walker->is_in_hash) {
141 14 100 100     187 if ( _is_string($token_type) || $token_type == KEY || _looks_like_version($token_type) ) {
      100        
142 8         16 $walker->{hash_count}++;
143              
144 8 100       22 if ($walker->hash_count % 2) {
145 4         30 $walker->stashed_module($token->{data});
146             }
147             else {
148             # store version
149 4         26 $result->save_module($walker->stashed_module, $token->{data});
150 4         13 $walker->stashed_module('');
151             }
152             }
153             }
154              
155             # For string
156             # e.g.
157             # use Test::Requires "Foo"
158             elsif (_is_string($token_type)) {
159 5         21 $result->save_module($token->{data});
160             }
161 48         183 next;
162             }
163              
164 0 0       0 if ($token_type != WHITESPACE) {
165 0         0 $walker->does_garbage_exist(1);
166 0         0 $walker->is_prev_module_name(0);
167             }
168 0         0 next;
169             }
170             }
171              
172 7         30 $result->modules;
173             }
174              
175              
176             sub _is_string {
177 26     26   211 my $token_type = shift;
178 26 100       152 $token_type == STRING || $token_type == RAW_STRING;
179             }
180              
181             sub _looks_like_version {
182 7     7   9 my $token_type = shift;
183 7 100 66     82 $token_type == DOUBLE || $token_type == INT || $token_type == VERSION_STRING;
184             }
185              
186             1;
187             __END__