File Coverage

blib/lib/Perl/Critic/Policy/Subroutines/ProhibitCallsToUnexportedSubs.pm
Criterion Covered Total %
statement 90 98 91.8
branch 17 28 60.7
condition n/a
subroutine 19 21 90.4
pod 5 6 83.3
total 131 153 85.6


line stmt bran cond sub pod time code
1              
2             use strict;
3 1     1   521 use warnings;
  1         2  
  1         25  
4 1     1   4 use base 'Perl::Critic::Policy';
  1         2  
  1         22  
5 1     1   5  
  1         1  
  1         82  
6             use PPI::Document;
7 1     1   425 use File::PathList;
  1         33405  
  1         32  
8 1     1   430  
  1         564  
  1         34  
9             use Perl::Critic::Utils qw(
10 1         61 :characters
11             :severities
12             &hashify
13             &is_function_call
14             &is_perl_builtin
15             &is_qualified_name
16             &policy_short_name
17             );
18 1     1   7  
  1         2  
19             use Perl::Critic::StricterSubs::Utils qw{
20 1         974 &find_exported_subroutine_names
21             &find_subroutine_calls
22             };
23 1     1   306  
  1         2  
24             #-----------------------------------------------------------------------------
25              
26             our $VERSION = 0.06;
27              
28             #-----------------------------------------------------------------------------
29              
30             my $CONFIG_PATH_SPLIT_REGEX = qr/ \s* [|] \s* /xms;
31              
32             #-----------------------------------------------------------------------------
33              
34             return qw( at_inc_prefix use_standard_at_inc at_inc_suffix );
35             }
36 0     0 0 0  
37              
38             #-----------------------------------------------------------------------------
39 18     18 1 136  
40 0     0 1 0 my ( $class, %config ) = @_;
41 5     5 1 60106 my $self = bless {}, $class;
42              
43             my @at_inc_prefix;
44             my @at_inc_suffix;
45              
46 5     5 1 20815 if ( defined $config{at_inc_prefix} ) {
47 5         11 @at_inc_prefix =
48             split $CONFIG_PATH_SPLIT_REGEX, $config{at_inc_prefix};
49 5         11 }
50             if ( defined $config{at_inc_suffix} ) {
51             @at_inc_prefix =
52 5 50       19 split $CONFIG_PATH_SPLIT_REGEX, $config{at_inc_suffix};
53             }
54 5         26  
55             my $use_standard_at_inc = $config{use_standard_at_inc};
56 5 50       14 if (not defined $use_standard_at_inc) {
57             $use_standard_at_inc = 1;
58 0         0 }
59              
60             my @inc = @at_inc_prefix;
61 5         9 if ($use_standard_at_inc) {
62 5 50       14 push @inc, @INC;
63 5         9 }
64             push @inc, @at_inc_suffix;
65              
66 5         8 die policy_short_name(__PACKAGE__), " has no directories in its module search path.\n"
67 5 50       11 if not @inc;
68 5         24  
69              
70 5         8 $self->{_inc} = File::PathList->new( paths => \@inc, cache => 1 );
71             $self->{_exports_by_package} = {};
72 5 50       13 return $self;
73             }
74              
75             #-----------------------------------------------------------------------------
76 5         29  
77 5         235 my $self = shift;
78 5         18 return $self->{_inc};
79             }
80              
81             my $self = shift;
82             return $self->{_exports_by_package}
83             }
84 4     4   6  
85 4         7 #-----------------------------------------------------------------------------
86              
87             my ($self, undef, $doc) = @_;
88              
89 28     28   44 my @violations = ();
90             my $expl = q{Violates encapsulation};
91 28         54  
92             for my $sub_call ( find_subroutine_calls($doc) ) {
93             next if not is_qualified_name( $sub_call );
94              
95             my ($package, $sub_name) = $self->_parse_subroutine_call( $sub_call );
96 5     5 1 42 next if _is_builtin_package( $package );
97              
98 5         10 my $exports = $self->_get_exports_for_package( $package );
99 5         10 if ( not exists $exports->{ $sub_name } ){
100              
101 5         14 my $desc = qq{Subroutine "$sub_name" not exported by "$package"};
102 29 50       2076 push @violations, $self->violation( $desc, $expl, $sub_call );
103             }
104 29         270  
105 29 100       88 }
106              
107 24         45 return @violations;
108 24 100       53 }
109              
110 18         51 #-----------------------------------------------------------------------------
111 18         47  
112             my ($self, $sub_call) = @_;
113             return if not $sub_call;
114              
115             my $sub_name = $EMPTY;
116 5         421 my $package_name = $EMPTY;
117              
118             if ($sub_call =~ m/ \A &? (.*) :: ([^:]+) \z /xms) {
119             $package_name = $1;
120             $sub_name = $2;
121             }
122 29     29   56  
123 29 50       63 return ($package_name, $sub_name);
124             }
125 29         55  
126 29         37  
127             #-----------------------------------------------------------------------------
128 29 50       52  
129 29         201 my ( $self, $package_name ) = @_;
130 29         44  
131             my $exports = $self->_get_exports_by_package()->{$package_name};
132             if (not $exports) {
133 29         74 $exports = {};
134              
135             my $file_name =
136             $self->_get_file_name_for_package_name( $package_name );
137              
138             if ($file_name) {
139             $exports =
140 24     24   47 { hashify ( $self->_get_exports_from_file( $file_name ) ) };
141             }
142 24         40  
143 24 100       48 $self->_get_exports_by_package()->{$package_name} = $exports;
144 4         8 }
145              
146 4         9 return $exports;
147             }
148              
149 4 50       9 #-----------------------------------------------------------------------------
150 4         10  
151             my ($self, $file_name) = @_;
152              
153             my $doc = PPI::Document->new($file_name);
154 4         1191 if (not $doc) {
155             my $pname = policy_short_name(__PACKAGE__);
156             die "$pname: could not parse $file_name: $PPI::Document::errstr\n";
157 24         38 }
158              
159             return find_exported_subroutine_names( $doc );
160             }
161              
162             #-----------------------------------------------------------------------------
163 4     4   10  
164             my ($self, $package_name) = @_;
165 4         13  
166 4 50       22369 my $partial_path = $package_name;
167 0         0 $partial_path =~ s{::}{/}xmsg;
168 0         0 $partial_path .= '.pm';
169              
170             my $full_path = $self->_find_file_in_at_INC( $partial_path );
171 4         14 return $full_path;
172             }
173              
174             #-----------------------------------------------------------------------------
175              
176             my ($self, $partial_path) = @_;
177 4     4   6  
178             my $inc = $self->_get_inc();
179 4         8 my $full_path = $inc->find_file( $partial_path );
180 4         7  
181 4         9 if (not $full_path) {
182             #TODO reinstate Elliot's error message here.
183 4         8 my $policy_name = policy_short_name( __PACKAGE__ );
184 4         9 warn qq{$policy_name: Cannot find source file "$partial_path"\n};
185             return;
186             }
187              
188             return $full_path;
189             }
190 4     4   9  
191             #-----------------------------------------------------------------------------
192 4         8  
193 4         14 my %BUILTIN_PACKAGES = hashify( qw(CORE CORE::GLOBAL UNIVERSAL main), $EMPTY );
194              
195 4 50       322 my ($package_name) = @_;
196             return exists $BUILTIN_PACKAGES{$package_name};
197 0         0 }
198 0         0  
199 0         0 #-----------------------------------------------------------------------------
200              
201             1;
202 4         9  
203              
204             =pod
205              
206             =for stopwords callee's
207              
208             =head1 NAME
209              
210 29     29   56 Perl::Critic::Policy::Subroutines::ProhibitCallsToUnexportedSubs
211 29         69  
212             =head1 AFFILIATION
213              
214             This policy is part of L<Perl::Critic::StricterSubs|Perl::Critic::StricterSubs>.
215              
216             =head1 DESCRIPTION
217              
218             Many Perl modules define their public interface by exporting subroutines via
219             L<Exporter|Exporter>. The goal of this Policy is to enforce encapsulation by by
220             prohibiting calls to subroutines that are not listed in the callee's C<@EXPORT>
221             or C<@EXPORT_OK>.
222              
223             =head1 LIMITATIONS
224              
225             This Policy does not properly deal with the L<only|only> pragma or modules that
226             don't use L<Exporter|Exporter> for their export mechanism, such as L<CGI|CGI>. In the
227             near future, we might fix this by allowing you configure the policy with
228             a list of packages that are exempt from this policy.
229              
230             =head1 DIAGNOSTICS
231              
232             =over
233              
234             =item C<Subroutines::ProhibitCallsToUnexportedSubs: Cannot find source file>
235              
236             This warning usually indicates that the file under analysis includes modules
237             that are not installed in this perl's <@INC> paths. See L</"CONFIGURATION">
238             for controlling the C<@INC> list this Policy.
239              
240             This warning can also happen when one of the included modules contains
241             multiple packages, or if the package name doesn't match the file name.
242             L<Perl::Critic|Perl::Critic> advises against both of these conditions, and has additional
243             Policies to help enforce that.
244              
245             =back
246              
247             =head1 SEE ALSO
248              
249             L<Perl::Critic::Policy::Modules::ProhibitMultiplePackages|Perl::Critic::Policy::Modules::ProhibitMultiplePackages>
250              
251             L<Perl::Critic::Policy::Modules::RequireFilenameMatchesPackage|Perl::Critic::Policy::Modules::RequireFilenameMatchesPackage>
252              
253             =head1 AUTHOR
254              
255             Jeffrey Ryan Thalhammer <thaljef@cpan.org>
256              
257             =head1 COPYRIGHT
258              
259             Copyright (c) 2007 Jeffrey Ryan Thalhammer. All rights reserved.
260              
261             This program is free software; you can redistribute it and/or modify it under
262             the same terms as Perl itself. The full text of this license can be found in
263             the LICENSE file included with this module.
264              
265             =cut
266              
267              
268             ##############################################################################
269             # Local Variables:
270             # mode: cperl
271             # cperl-indent-level: 4
272             # fill-column: 78
273             # indent-tabs-mode: nil
274             # c-indentation-style: bsd
275             # End:
276             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab :