File Coverage

blib/lib/Perl/Critic/PolicyFactory.pm
Criterion Covered Total %
statement 145 157 92.3
branch 31 42 73.8
condition 21 31 67.7
subroutine 30 30 100.0
pod 4 4 100.0
total 231 264 87.5


line stmt bran cond sub pod time code
1             package Perl::Critic::PolicyFactory;
2              
3 40     40   554799 use 5.010001;
  40         121  
4 40     40   161 use strict;
  40         62  
  40         761  
5 40     40   138 use warnings;
  40         58  
  40         1696  
6              
7 40     40   2718 use English qw(-no_match_vars);
  40         14463  
  40         227  
8              
9 40     40   11778 use File::Spec::Unix qw();
  40         66  
  40         864  
10 40     40   3209 use List::SomeUtils qw(any);
  40         80765  
  40         2361  
11              
12 40         1614 use Perl::Critic::Utils qw{
13             :characters
14             $POLICY_NAMESPACE
15             :data_conversion
16             policy_long_name
17             policy_short_name
18             :internal_lookup
19 40     40   4521 };
  40         92  
20 40     40   27210 use Perl::Critic::PolicyConfig;
  40         103  
  40         1302  
21 40     40   203 use Perl::Critic::Exception::AggregateConfiguration;
  40         59  
  40         1500  
22 40     40   175 use Perl::Critic::Exception::Configuration;
  40         57  
  40         1217  
23 40     40   170 use Perl::Critic::Exception::Fatal::Generic qw{ throw_generic };
  40         70  
  40         1491  
24 40     40   167 use Perl::Critic::Exception::Fatal::Internal qw{ throw_internal };
  40         66  
  40         1235  
25             use Perl::Critic::Exception::Fatal::PolicyDefinition
26 40     40   14885 qw{ throw_policy_definition };
  40         95  
  40         929  
27 40     40   17297 use Perl::Critic::Exception::Configuration::NonExistentPolicy qw< >;
  40         97  
  40         1119  
28 40     40   241 use Perl::Critic::Utils::Constants qw{ :profile_strictness };
  40         60  
  40         4775  
29              
30 40     40   200 use Exception::Class; # this must come after "use P::C::Exception::*"
  40         60  
  40         314  
31              
32             our $VERSION = '1.156';
33              
34             #-----------------------------------------------------------------------------
35              
36             # Globals. Ick!
37             my @site_policy_names;
38              
39             #-----------------------------------------------------------------------------
40              
41             # Blech!!! This is ug-lee. Belongs in the constructor. And it shouldn't be
42             # called "test" mode.
43             sub import {
44              
45 134     134   1787 my ( undef, %args ) = @_;
46 134         353 my $test_mode = $args{-test};
47 134         308 my $extra_test_policies = $args{'-extra-test-policies'};
48              
49 134 100       613 if ( not @site_policy_names ) {
50 40         86 my $eval_worked = eval {
51 40         17288 require Module::Pluggable;
52 40         294698 Module::Pluggable->import(search_path => $POLICY_NAMESPACE,
53             require => 1, inner => 0);
54 40         2568 @site_policy_names = plugins(); #Exported by Module::Pluggable
55 40         1097059 1;
56             };
57              
58 40 50       222 if (not $eval_worked) {
59 0 0       0 if ( $EVAL_ERROR ) {
60 0         0 throw_generic
61             qq<Can't load Policies from namespace "$POLICY_NAMESPACE": $EVAL_ERROR>;
62             }
63              
64             throw_generic
65 0         0 qq<Can't load Policies from namespace "$POLICY_NAMESPACE" for an unknown reason.>;
66             }
67              
68 40 50       158 if ( not @site_policy_names ) {
69 0         0 throw_generic
70             qq<No Policies found in namespace "$POLICY_NAMESPACE".>;
71             }
72             }
73              
74             # In test mode, only load native policies, not third-party ones. So this
75             # filters out any policy that was loaded from within a directory called
76             # "blib". During the usual "./Build test" process this works fine,
77             # but it doesn't work if you are using prove to test against the code
78             # directly in the lib/ directory.
79              
80 134 100 66 51   1143 if ( $test_mode && any {m/\b blib \b/xms} @INC ) {
  51         596  
81 51         583 @site_policy_names = _modules_from_blib( @site_policy_names );
82              
83 51 50       273 if ($extra_test_policies) {
84             my @extra_policy_full_names =
85 0         0 map { "${POLICY_NAMESPACE}::$_" } @{$extra_test_policies};
  0         0  
  0         0  
86              
87 0         0 push @site_policy_names, @extra_policy_full_names;
88             }
89             }
90              
91 134         10563 return 1;
92             }
93              
94             #-----------------------------------------------------------------------------
95             # Some static helper subs
96              
97             sub _modules_from_blib {
98 51     51   2735 my (@modules) = @_;
99 51         169 return grep { _was_loaded_from_blib( _module2path($_) ) } @modules;
  7395         8384  
100             }
101              
102             sub _module2path {
103 7395   50 7395   9428 my $module = shift || return;
104 7395         24901 return File::Spec::Unix->catdir(split m/::/xms, $module) . '.pm';
105             }
106              
107             sub _was_loaded_from_blib {
108 7395   50 7395   9609 my $path = shift || return;
109 7395         14325 my $full_path = $INC{$path};
110 7395   33     20605 return $full_path && $full_path =~ m/ (?: \A | \b b ) lib \b /xms;
111             }
112              
113             #-----------------------------------------------------------------------------
114              
115             sub new {
116              
117 435     435 1 2216 my ( $class, %args ) = @_;
118 435         814 my $self = bless {}, $class;
119 435         1441 $self->_init( %args );
120 435         1468 return $self;
121             }
122              
123             #-----------------------------------------------------------------------------
124              
125             sub _init {
126              
127 435     435   1071 my ($self, %args) = @_;
128              
129 435         749 my $profile = $args{-profile};
130 435 50       1251 $self->{_profile} = $profile
131             or throw_internal q{The -profile argument is required};
132              
133 435         697 my $incoming_errors = $args{-errors};
134 435         800 my $profile_strictness = $args{'-profile-strictness'};
135 435   66     798 $profile_strictness ||= $PROFILE_STRICTNESS_DEFAULT;
136 435         728 $self->{_profile_strictness} = $profile_strictness;
137              
138 435 50       1084 if ( $profile_strictness ne $PROFILE_STRICTNESS_QUIET ) {
139 435         525 my $errors;
140              
141             # If we're supposed to be strict or problems have already been found...
142 435 100 100     2195 if (
      100        
143             $profile_strictness eq $PROFILE_STRICTNESS_FATAL
144 279         8142 or ( $incoming_errors and @{ $incoming_errors->exceptions() } )
145             ) {
146 147 100       598 $errors =
147             $incoming_errors
148             ? $incoming_errors
149             : Perl::Critic::Exception::AggregateConfiguration->new();
150             }
151              
152 435         73532 $self->_validate_policies_in_profile( $errors );
153              
154 435 50 100     2002 if (
      66        
155             not $incoming_errors
156             and $errors
157             and $errors->has_exceptions()
158             ) {
159 0         0 $errors->rethrow();
160             }
161             }
162              
163 435         4873 return $self;
164             }
165              
166             #-----------------------------------------------------------------------------
167              
168             sub create_policy {
169              
170 12776     12776 1 34703 my ($self, %args ) = @_;
171              
172             my $policy_name = $args{-name}
173 12776 100       28739 or throw_internal q{The -name argument is required};
174              
175             # Normalize policy name to a fully-qualified package name
176 12775         27634 $policy_name = policy_long_name( $policy_name );
177 12775         22174 my $policy_short_name = policy_short_name( $policy_name );
178              
179              
180             # Get the policy parameters from the user profile if they were
181             # not given to us directly. If none exist, use an empty hash.
182 12775         24556 my $profile = $self->_profile();
183 12775         17889 my $policy_config;
184 12775 100       22066 if ( $args{-params} ) {
185             $policy_config =
186             Perl::Critic::PolicyConfig->new(
187             $policy_short_name, $args{-params}
188 268         1289 );
189             }
190             else {
191 12507         38918 $policy_config = $profile->policy_params($policy_name);
192 12507   33     27449 $policy_config ||=
193             Perl::Critic::PolicyConfig->new( $policy_short_name );
194             }
195              
196             # Pull out base parameters.
197 12775         26135 return $self->_instantiate_policy( $policy_name, $policy_config );
198             }
199              
200             #-----------------------------------------------------------------------------
201              
202             sub create_all_policies {
203              
204 83     83 1 220 my ( $self, $incoming_errors ) = @_;
205              
206 83 100       223 my $errors =
207             $incoming_errors
208             ? $incoming_errors
209             : Perl::Critic::Exception::AggregateConfiguration->new();
210 83         1078 my @policies;
211              
212 83         213 foreach my $name ( site_policy_names() ) {
213 12035         18065 my $policy = eval { $self->create_policy( -name => $name ) };
  12035         31206  
214              
215 12035         35354 $errors->add_exception_or_rethrow( $EVAL_ERROR );
216              
217 12035 100       42842 if ( $policy ) {
218 12034         255084 push @policies, $policy;
219             }
220             }
221              
222 83 50 66     3509 if ( not $incoming_errors and $errors->has_exceptions() ) {
223 0         0 $errors->rethrow();
224             }
225              
226 83         2844 return @policies;
227             }
228              
229             #-----------------------------------------------------------------------------
230              
231             sub site_policy_names {
232 561     561 1 16232 my @sorted_policy_names = sort @site_policy_names;
233 561         10567 return @sorted_policy_names;
234             }
235              
236             #-----------------------------------------------------------------------------
237              
238             sub _profile {
239 13210     13210   18510 my ($self) = @_;
240              
241 13210         23293 return $self->{_profile};
242             }
243              
244             #-----------------------------------------------------------------------------
245              
246             # This two-phase initialization is caused by the historical lack of a
247             # requirement for Policies to invoke their super-constructor.
248             sub _instantiate_policy {
249 12775     12775   20372 my ($self, $policy_name, $policy_config) = @_;
250              
251 12775         34709 $policy_config->set_profile_strictness( $self->{_profile_strictness} );
252              
253 12775         15628 my $policy = eval { $policy_name->new( %{$policy_config} ) };
  12775         14260  
  12775         86917  
254 12775         37237 _handle_policy_instantiation_exception(
255             $policy_name,
256             $policy, # Note: being used as a boolean here.
257             $EVAL_ERROR,
258             );
259              
260 12627         35505 $policy->__set_config( $policy_config );
261              
262 12627         16735 my $eval_worked = eval { $policy->__set_base_parameters(); 1; };
  12627         42270  
  12626         21713  
263 12627         32935 _handle_policy_instantiation_exception(
264             $policy_name, $eval_worked, $EVAL_ERROR,
265             );
266              
267 12626         38178 return $policy;
268             }
269              
270             sub _handle_policy_instantiation_exception {
271 25402     25402   51386 my ($policy_name, $eval_worked, $eval_error) = @_;
272              
273 25402 100       71094 if (not $eval_worked) {
274 149 50       475 if ($eval_error) {
275 149         1199 my $exception = Exception::Class->caught();
276              
277 149 100       755 if (ref $exception) {
278 147         301 $exception->rethrow();
279             }
280              
281             throw_policy_definition
282 2         11 qq<Unable to create policy "$policy_name": $eval_error>;
283             }
284              
285             throw_policy_definition
286 0         0 qq<Unable to create policy "$policy_name" for an unknown reason.>;
287             }
288              
289 25253         287353 return;
290             }
291              
292             #-----------------------------------------------------------------------------
293              
294             sub _validate_policies_in_profile {
295 435     435   811 my ($self, $errors) = @_;
296              
297 435         959 my $profile = $self->_profile();
298 435         1004 my %known_policies = hashify( $self->site_policy_names() );
299              
300 435         6055 for my $policy_name ( $profile->listed_policies() ) {
301 1833 100       2724 if ( not exists $known_policies{$policy_name} ) {
302 2         3 my $message = qq{Policy "$policy_name" is not installed.};
303              
304 2 50       5 if ( $errors ) {
305 0         0 $errors->add_exception(
306             Perl::Critic::Exception::Configuration::NonExistentPolicy->new(
307             policy => $policy_name,
308             )
309             );
310             }
311             else {
312 2         21 warn qq{$message\n};
313             }
314             }
315             }
316              
317 435         4641 return;
318             }
319              
320             #-----------------------------------------------------------------------------
321              
322             1;
323              
324             __END__
325              
326              
327             =pod
328              
329             =for stopwords PolicyFactory -params
330              
331             =head1 NAME
332              
333             Perl::Critic::PolicyFactory - Instantiates Policy objects.
334              
335              
336             =head1 DESCRIPTION
337              
338             This is a helper class that instantiates
339             L<Perl::Critic::Policy|Perl::Critic::Policy> objects with the user's
340             preferred parameters. There are no user-serviceable parts here.
341              
342              
343             =head1 INTERFACE SUPPORT
344              
345             This is considered to be a non-public class. Its interface is subject
346             to change without notice.
347              
348              
349             =head1 CONSTRUCTOR
350              
351             =over
352              
353             =item C<< new( -profile => $profile, -errors => $config_errors ) >>
354              
355             Returns a reference to a new Perl::Critic::PolicyFactory object.
356              
357             B<-profile> is a reference to a
358             L<Perl::Critic::UserProfile|Perl::Critic::UserProfile> object. This
359             argument is required.
360              
361             B<-errors> is a reference to an instance of
362             L<Perl::Critic::ConfigErrors|Perl::Critic::ConfigErrors>. This
363             argument is optional. If specified, than any problems found will be
364             added to the object.
365              
366              
367             =back
368              
369              
370             =head1 METHODS
371              
372             =over
373              
374             =item C<< create_policy( -name => $policy_name, -params => \%param_hash ) >>
375              
376             Creates one Policy object. If the object cannot be instantiated, it
377             will throw a fatal exception. Otherwise, it returns a reference to
378             the new Policy object.
379              
380             B<-name> is the name of a L<Perl::Critic::Policy|Perl::Critic::Policy>
381             subclass module. The C<'Perl::Critic::Policy'> portion of the name
382             can be omitted for brevity. This argument is required.
383              
384             B<-params> is an optional reference to hash of parameters that will be
385             passed into the constructor of the Policy. If C<-params> is not
386             defined, we will use the appropriate Policy parameters from the
387             L<Perl::Critic::UserProfile|Perl::Critic::UserProfile>.
388              
389             Note that the Policy will not have had
390             L<Perl::Critic::Policy/"initialize_if_enabled"> invoked on it, so it
391             may not yet be usable.
392              
393              
394             =item C< create_all_policies() >
395              
396             Constructs and returns one instance of each
397             L<Perl::Critic::Policy|Perl::Critic::Policy> subclass that is
398             installed on the local system. Each Policy will be created with the
399             appropriate parameters from the user's configuration profile.
400              
401             Note that the Policies will not have had
402             L<Perl::Critic::Policy/"initialize_if_enabled"> invoked on them, so
403             they may not yet be usable.
404              
405              
406             =back
407              
408              
409             =head1 SUBROUTINES
410              
411             Perl::Critic::PolicyFactory has a few static subroutines that are used
412             internally, but may be useful to you in some way.
413              
414             =over
415              
416             =item C<site_policy_names()>
417              
418             Returns a list of all the Policy modules that are currently installed
419             in the Perl::Critic:Policy namespace. These will include modules that
420             are distributed with Perl::Critic plus any third-party modules that
421             have been installed.
422              
423              
424             =back
425              
426              
427             =head1 AUTHOR
428              
429             Jeffrey Ryan Thalhammer <jeff@imaginative-software.com>
430              
431              
432             =head1 COPYRIGHT
433              
434             Copyright (c) 2005-2011 Imaginative Software Systems
435              
436             This program is free software; you can redistribute it and/or modify
437             it under the same terms as Perl itself. The full text of this license
438             can be found in the LICENSE file included with this module.
439              
440             =cut
441              
442             # Local Variables:
443             # mode: cperl
444             # cperl-indent-level: 4
445             # fill-column: 78
446             # indent-tabs-mode: nil
447             # c-indentation-style: bsd
448             # End:
449             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :