File Coverage

blib/lib/Perl/Critic/Policy/Modules/ProhibitAutomaticExportation.pm
Criterion Covered Total %
statement 51 51 100.0
branch 17 18 94.4
condition 3 3 100.0
subroutine 20 20 100.0
pod 4 5 80.0
total 95 97 97.9


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::Modules::ProhibitAutomaticExportation;
2              
3 40     40   27218 use 5.010001;
  40         180  
4 40     40   248 use strict;
  40         133  
  40         857  
5 40     40   221 use warnings;
  40         100  
  40         1037  
6 40     40   270 use Readonly;
  40         106  
  40         2615  
7              
8 40     40   338 use Perl::Critic::Utils qw{ :severities };
  40         109  
  40         2624  
9 40     40   5464 use List::SomeUtils qw(any);
  40         105  
  40         2224  
10 40     40   272 use parent 'Perl::Critic::Policy';
  40         102  
  40         216  
11              
12             our $VERSION = '1.148';
13              
14             #-----------------------------------------------------------------------------
15              
16             Readonly::Scalar my $DESC => q{Symbols are exported by default};
17             Readonly::Scalar my $EXPL => q{Use '@EXPORT_OK' or '%EXPORT_TAGS' instead}; ## no critic (RequireInterpolation)
18              
19             #-----------------------------------------------------------------------------
20              
21 98     98 0 2018 sub supported_parameters { return () }
22 77     77 1 360 sub default_severity { return $SEVERITY_HIGH }
23 74     74 1 348 sub default_themes { return qw( core bugs ) }
24 41     41 1 122 sub applies_to { return 'PPI::Document' }
25              
26             #-----------------------------------------------------------------------------
27              
28             sub violates {
29 41     41 1 137 my ( $self, $elem, $doc ) = @_;
30              
31 41 100       228 if ( _uses_exporter($doc) ) {
32 8 100       232 if ( my $exp = _has_exports($doc) ) {
33 3         92 return $self->violation( $DESC, $EXPL, $exp );
34             }
35             }
36 38         1037 return; #ok
37             }
38              
39             #-----------------------------------------------------------------------------
40              
41             sub _uses_exporter {
42 41     41   143 my ($doc) = @_;
43              
44 41         143 my $includes_ref = $doc->find('PPI::Statement::Include');
45 41 100       201 return if not $includes_ref;
46              
47             # This covers both C<use Exporter;> and C<use parent 'Exporter';>
48 38     69   237 return any { m/ \b Exporter \b/xms } @{ $includes_ref };
  69         1061  
  38         205  
49             }
50              
51             #------------------
52              
53             sub _has_exports {
54 8     8   19 my ($doc) = @_;
55              
56             my $wanted =
57 8 100 100 171   31 sub { _our_export(@_) or _vars_export(@_) or _package_export(@_) };
  171         1846  
58              
59 8         30 return $doc->find_first( $wanted );
60             }
61              
62             #------------------
63              
64             sub _our_export {
65 171     171   266 my (undef, $elem) = @_;
66              
67 171 100       709 $elem->isa('PPI::Statement::Variable') or return 0;
68 2 50       10 $elem->type() eq 'our' or return 0;
69              
70 2     2   111 return any { $_ eq '@EXPORT' } $elem->variables(); ## no critic(RequireInterpolationOfMetachars)
  2         117  
71             }
72              
73             #------------------
74              
75             sub _vars_export {
76 170     170   320 my (undef, $elem) = @_;
77              
78 170 100       695 $elem->isa('PPI::Statement::Include') or return 0;
79 12 100       38 $elem->pragma() eq 'vars' or return 0;
80              
81 4         130 return $elem =~ m{ \@EXPORT \b }xms; #Crude, but usually works
82             }
83              
84             #------------------
85              
86             sub _package_export {
87 169     169   702 my (undef, $elem) = @_;
88              
89 169 100       642 $elem->isa('PPI::Token::Symbol') or return 0;
90              
91 6         19 return $elem =~ m{ \A \@ \S+ ::EXPORT \z }xms;
92             #TODO: ensure that it is in _this_ package!
93             }
94              
95             1;
96              
97             __END__
98              
99             #-----------------------------------------------------------------------------
100              
101             =pod
102              
103             =head1 NAME
104              
105             Perl::Critic::Policy::Modules::ProhibitAutomaticExportation - Export symbols via C<@EXPORT_OK> or C<%EXPORT_TAGS> instead of C<@EXPORT>.
106              
107              
108             =head1 AFFILIATION
109              
110             This Policy is part of the core L<Perl::Critic|Perl::Critic>
111             distribution.
112              
113              
114             =head1 DESCRIPTION
115              
116             When using L<Exporter|Exporter>, symbols placed in the C<@EXPORT>
117             variable are automatically exported into the caller's namespace.
118             Although convenient, this practice is not polite, and may cause
119             serious problems if the caller declares the same symbols. The best
120             practice is to place your symbols in C<@EXPORT_OK> or C<%EXPORT_TAGS>
121             and let the caller choose exactly which symbols to export.
122              
123             package Foo;
124              
125             use Exporter 'import';
126             our @EXPORT = qw(foo $bar @baz); # not ok
127             our @EXPORT_OK = qw(foo $bar @baz); # ok
128             our %EXPORT_TAGS = ( all => [ qw(foo $bar @baz) ] ); # ok
129              
130              
131             =head1 CONFIGURATION
132              
133             This Policy is not configurable except for the standard options.
134              
135              
136             =head1 AUTHOR
137              
138             Jeffrey Ryan Thalhammer <jeff@imaginative-software.com>
139              
140              
141             =head1 COPYRIGHT
142              
143             Copyright (c) 2005-2023 Imaginative Software Systems. All rights reserved.
144              
145             This program is free software; you can redistribute it and/or modify
146             it under the same terms as Perl itself. The full text of this license
147             can be found in the LICENSE file included with this module.
148              
149             =cut
150              
151             # Local Variables:
152             # mode: cperl
153             # cperl-indent-level: 4
154             # fill-column: 78
155             # indent-tabs-mode: nil
156             # c-indentation-style: bsd
157             # End:
158             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :