File Coverage

blib/lib/Module/Checkstyle/Check/Package.pm
Criterion Covered Total %
statement 74 74 100.0
branch 21 26 80.7
condition 8 14 57.1
subroutine 12 12 100.0
pod 5 5 100.0
total 120 131 91.6


line stmt bran cond sub pod time code
1             package Module::Checkstyle::Check::Package;
2              
3 2     2   3428 use strict;
  2         5  
  2         95  
4 2     2   12 use warnings;
  2         5  
  2         77  
5              
6 2     2   9 use Carp qw(croak);
  2         5  
  2         137  
7 2     2   2535 use File::Spec::Functions qw(splitpath);
  2         1422  
  2         149  
8 2     2   1227 use Readonly;
  2         4207  
  2         109  
9              
10 2     2   667 use Module::Checkstyle::Util qw(:problem :args);
  2         7  
  2         371  
11              
12 2     2   10 use base qw(Module::Checkstyle::Check);
  2         12  
  2         1396  
13              
14             # The directives we provide
15             Readonly my $MATCHES_NAME => 'matches-name';
16             Readonly my $MAX_PER_FILE => 'max-per-file';
17             Readonly my $IS_FIRST_STATEMENT => 'is-first-statement';
18             Readonly my $MATCHES_FILENAME => 'has-matching-filename';
19              
20             sub register {
21 1     1 1 7 return ('enter PPI::Document' => \&begin_document,
22             'leave PPI::Document' => \&end_document,
23             'PPI::Statement::Package' => \&handle_package,
24             );
25             }
26              
27             sub new {
28 2     2 1 5 my ($class, $config) = @_;
29              
30 2         20 my $self = $class->SUPER::new($config);
31              
32 2         26 $self->{packages} = [];
33 2         6 $self->{document} = undef;
34            
35             # Keep configuration local
36 2         13 $self->{$MATCHES_NAME} = as_regexp($config->get_directive($MATCHES_NAME));
37 2   100     17 $self->{$MAX_PER_FILE} = as_numeric($config->get_directive($MAX_PER_FILE)) || 0;
38              
39 2         13 foreach ($IS_FIRST_STATEMENT, $MATCHES_FILENAME) {
40 4         29 $self->{$_} = as_true($config->get_directive($_));
41             }
42            
43 2         16 return $self;
44             }
45              
46             sub begin_document {
47 6     6 1 14637 my ($self, $document, $file) = @_;
48              
49 6         20 $self->{count} = 0;
50            
51 6         10 my @problems;
52            
53             # Check first statement ignoring whitespace, comments and pod
54 6 100 66     46 if (defined $file && $file =~ /\.pm$/) {
55 3 50       17 if ($self->{$IS_FIRST_STATEMENT}) {
56 3         37 my @children = $document->schildren();
57 3         59 my $statement = shift @children;
58 3 100 33     24 if (!defined $statement || !$statement->isa('PPI::Statement::Package')) {
59 1         9 push @problems, new_problem($self->config, $IS_FIRST_STATEMENT,
60             qq(First statement is not a package declaration),
61             $statement, $file);
62             }
63             }
64             }
65            
66 6         33 return @problems;
67             }
68              
69             sub handle_package {
70 7     7 1 8369 my ($self, $package, $file) = @_;
71            
72 7 100       48 if (!$package->isa('PPI::Statement::Package')) {
73 1         6 croak format_expected_err('PPI::Statement::Package', $package);
74             }
75            
76 6         12 my @problems;
77            
78 6         25 my $namespace = $package->namespace();
79            
80             # Check naming
81 6 50 33     231 if ($namespace && $self->{$MATCHES_NAME}) {
82 6 100       61 if ($namespace !~ $self->{$MATCHES_NAME}) {
83 1         25 push @problems, new_problem($self->config, $MATCHES_NAME,
84             qq(The package name '$namespace' does not match '$self->{$MATCHES_NAME}'),
85             $package, $file);
86             }
87             }
88            
89             # Check count
90 6 50       96 if ($self->{$MAX_PER_FILE}) {
91 6         46 $self->{count}++;
92 6 100       20 if ($self->{count} > $self->{$MAX_PER_FILE}) {
93 1         11 my $err = qq(The declration 'package $namespace;' exceeds the maximum number of ($self->{$MAX_PER_FILE}) packages per file);
94 1         12 push @problems, new_problem($self->config, $MAX_PER_FILE,
95             $err,
96             $package, $file);
97             }
98             }
99            
100 6 50       45 push @{$self->{packages}}, $namespace if $namespace;
  6         22  
101            
102 6         22 return @problems;
103             }
104              
105             sub end_document {
106 5     5 1 1218 my ($self, $document, $file) = @_;
107 5         11 my @problems;
108              
109             # Check that we have a package that matches the path if it's a module
110 5 100 66     23 if ($self->{$MATCHES_FILENAME} && $file) {
111 2 50       26 if ($file =~ /\.pm$/) {
112 2         5 my $ok_filename = 0;
113              
114 3         15 CHECK_PACKAGES:
115 2         5 while (my $package = shift @{$self->{packages}}) {
116 2         46 my $fake_file = File::Spec->catfile(split/\:\:/, $package) . ".pm";
117 2         9 my $real_file = substr($file, -length($fake_file));
118 2 100       16 if ($real_file eq $fake_file) {
119 1         2 $ok_filename = 1;
120 1         3 last CHECK_PACKAGES;
121             }
122             }
123            
124 2 100       9 if (!$ok_filename) {
125 1         5 my $err = qq(The file '$file' does not seem to contain a package matching the filename);
126 1         7 push @problems, new_problem($self->config, $MATCHES_FILENAME,
127             $err,
128             undef, $file);
129             }
130             }
131             }
132              
133              
134            
135             # Clean up
136 5         53 delete $self->{packages};
137            
138 5         25 return @problems;
139             }
140              
141             1;
142             __END__