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   416834 use 5.010001;
  40         189  
4 40     40   229 use strict;
  40         86  
  40         803  
5 40     40   203 use warnings;
  40         88  
  40         1056  
6              
7 40     40   3451 use English qw(-no_match_vars);
  40         23416  
  40         345  
8              
9 40     40   14212 use File::Spec::Unix qw();
  40         99  
  40         773  
10 40     40   4135 use List::SomeUtils qw(any);
  40         92503  
  40         2358  
11              
12 40         1667 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   5266 };
  40         132  
20 40     40   29479 use Perl::Critic::PolicyConfig;
  40         111  
  40         1290  
21 40     40   283 use Perl::Critic::Exception::AggregateConfiguration;
  40         81  
  40         1583  
22 40     40   229 use Perl::Critic::Exception::Configuration;
  40         89  
  40         1415  
23 40     40   258 use Perl::Critic::Exception::Fatal::Generic qw{ throw_generic };
  40         110  
  40         1864  
24 40     40   251 use Perl::Critic::Exception::Fatal::Internal qw{ throw_internal };
  40         96  
  40         1501  
25             use Perl::Critic::Exception::Fatal::PolicyDefinition
26 40     40   15628 qw{ throw_policy_definition };
  40         108  
  40         925  
27 40     40   18348 use Perl::Critic::Exception::Configuration::NonExistentPolicy qw< >;
  40         118  
  40         1000  
28 40     40   276 use Perl::Critic::Utils::Constants qw{ :profile_strictness };
  40         77  
  40         4680  
29              
30 40     40   276 use Exception::Class; # this must come after "use P::C::Exception::*"
  40         103  
  40         212  
31              
32             our $VERSION = '1.150';
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   1909 my ( $class, %args ) = @_;
46 134         369 my $test_mode = $args{-test};
47 134         298 my $extra_test_policies = $args{'-extra-test-policies'};
48              
49 134 100       712 if ( not @site_policy_names ) {
50 40         92 my $eval_worked = eval {
51 40         20402 require Module::Pluggable;
52 40         325706 Module::Pluggable->import(search_path => $POLICY_NAMESPACE,
53             require => 1, inner => 0);
54 40         2881 @site_policy_names = plugins(); #Exported by Module::Pluggable
55 40         1618880 1;
56             };
57              
58 40 50       261 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       225 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   1186 if ( $test_mode && any {m/\b blib \b/xms} @INC ) {
  51         747  
81 51         564 @site_policy_names = _modules_from_blib( @site_policy_names );
82              
83 51 50       403 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         11117 return 1;
92             }
93              
94             #-----------------------------------------------------------------------------
95             # Some static helper subs
96              
97             sub _modules_from_blib {
98 51     51   1903 my (@modules) = @_;
99 51         279 return grep { _was_loaded_from_blib( _module2path($_) ) } @modules;
  7395         13624  
100             }
101              
102             sub _module2path {
103 7395   50 7395   13277 my $module = shift || return;
104 7395         38109 return File::Spec::Unix->catdir(split m/::/xms, $module) . '.pm';
105             }
106              
107             sub _was_loaded_from_blib {
108 7395   50 7395   15251 my $path = shift || return;
109 7395         21578 my $full_path = $INC{$path};
110 7395   33     35123 return $full_path && $full_path =~ m/ (?: \A | \b b ) lib \b /xms;
111             }
112              
113             #-----------------------------------------------------------------------------
114              
115             sub new {
116              
117 434     434 1 2394 my ( $class, %args ) = @_;
118 434         1174 my $self = bless {}, $class;
119 434         1689 $self->_init( %args );
120 434         1556 return $self;
121             }
122              
123             #-----------------------------------------------------------------------------
124              
125             sub _init {
126              
127 434     434   1232 my ($self, %args) = @_;
128              
129 434         814 my $profile = $args{-profile};
130 434 50       1443 $self->{_profile} = $profile
131             or throw_internal q{The -profile argument is required};
132              
133 434         880 my $incoming_errors = $args{-errors};
134 434         870 my $profile_strictness = $args{'-profile-strictness'};
135 434   66     1053 $profile_strictness ||= $PROFILE_STRICTNESS_DEFAULT;
136 434         925 $self->{_profile_strictness} = $profile_strictness;
137              
138 434 50       1292 if ( $profile_strictness ne $PROFILE_STRICTNESS_QUIET ) {
139 434         681 my $errors;
140              
141             # If we're supposed to be strict or problems have already been found...
142 434 100 100     2032 if (
      100        
143             $profile_strictness eq $PROFILE_STRICTNESS_FATAL
144 278         8331 or ( $incoming_errors and @{ $incoming_errors->exceptions() } )
145             ) {
146 147 100       640 $errors =
147             $incoming_errors
148             ? $incoming_errors
149             : Perl::Critic::Exception::AggregateConfiguration->new();
150             }
151              
152 434         94610 $self->_validate_policies_in_profile( $errors );
153              
154 434 50 100     2096 if (
      66        
155             not $incoming_errors
156             and $errors
157             and $errors->has_exceptions()
158             ) {
159 0         0 $errors->rethrow();
160             }
161             }
162              
163 434         5363 return $self;
164             }
165              
166             #-----------------------------------------------------------------------------
167              
168             sub create_policy {
169              
170 12631     12631 1 43103 my ($self, %args ) = @_;
171              
172             my $policy_name = $args{-name}
173 12631 100       33405 or throw_internal q{The -name argument is required};
174              
175             # Normalize policy name to a fully-qualified package name
176 12630         32366 $policy_name = policy_long_name( $policy_name );
177 12630         28058 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 12630         28118 my $profile = $self->_profile();
183 12630         19376 my $policy_config;
184 12630 100       24909 if ( $args{-params} ) {
185             $policy_config =
186             Perl::Critic::PolicyConfig->new(
187             $policy_short_name, $args{-params}
188 268         1143 );
189             }
190             else {
191 12362         37376 $policy_config = $profile->policy_params($policy_name);
192 12362   33     35241 $policy_config ||=
193             Perl::Critic::PolicyConfig->new( $policy_short_name );
194             }
195              
196             # Pull out base parameters.
197 12630         29316 return $self->_instantiate_policy( $policy_name, $policy_config );
198             }
199              
200             #-----------------------------------------------------------------------------
201              
202             sub create_all_policies {
203              
204 82     82 1 254 my ( $self, $incoming_errors ) = @_;
205              
206 82 100       270 my $errors =
207             $incoming_errors
208             ? $incoming_errors
209             : Perl::Critic::Exception::AggregateConfiguration->new();
210 82         1198 my @policies;
211              
212 82         339 foreach my $name ( site_policy_names() ) {
213 11890         21042 my $policy = eval { $self->create_policy( -name => $name ) };
  11890         34331  
214              
215 11890         43832 $errors->add_exception_or_rethrow( $EVAL_ERROR );
216              
217 11890 100       43075 if ( $policy ) {
218 11889         302392 push @policies, $policy;
219             }
220             }
221              
222 82 50 66     3082 if ( not $incoming_errors and $errors->has_exceptions() ) {
223 0         0 $errors->rethrow();
224             }
225              
226 82         2741 return @policies;
227             }
228              
229             #-----------------------------------------------------------------------------
230              
231             sub site_policy_names {
232 559     559 1 15182 my @sorted_policy_names = sort @site_policy_names;
233 559         10750 return @sorted_policy_names;
234             }
235              
236             #-----------------------------------------------------------------------------
237              
238             sub _profile {
239 13064     13064   22087 my ($self) = @_;
240              
241 13064         24250 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 12630     12630   25239 my ($self, $policy_name, $policy_config) = @_;
250              
251 12630         37906 $policy_config->set_profile_strictness( $self->{_profile_strictness} );
252              
253 12630         19125 my $policy = eval { $policy_name->new( %{$policy_config} ) };
  12630         18498  
  12630         110571  
254 12630         43376 _handle_policy_instantiation_exception(
255             $policy_name,
256             $policy, # Note: being used as a boolean here.
257             $EVAL_ERROR,
258             );
259              
260 12482         38681 $policy->__set_config( $policy_config );
261              
262 12482         19195 my $eval_worked = eval { $policy->__set_base_parameters(); 1; };
  12482         51274  
  12481         26094  
263 12482         34947 _handle_policy_instantiation_exception(
264             $policy_name, $eval_worked, $EVAL_ERROR,
265             );
266              
267 12481         37323 return $policy;
268             }
269              
270             sub _handle_policy_instantiation_exception {
271 25112     25112   55407 my ($policy_name, $eval_worked, $eval_error) = @_;
272              
273 25112 100       81509 if (not $eval_worked) {
274 149 50       479 if ($eval_error) {
275 149         1182 my $exception = Exception::Class->caught();
276              
277 149 100       952 if (ref $exception) {
278 147         319 $exception->rethrow();
279             }
280              
281             throw_policy_definition
282 2         17 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 24963         328943 return;
290             }
291              
292             #-----------------------------------------------------------------------------
293              
294             sub _validate_policies_in_profile {
295 434     434   1067 my ($self, $errors) = @_;
296              
297 434         1214 my $profile = $self->_profile();
298 434         1180 my %known_policies = hashify( $self->site_policy_names() );
299              
300 434         6109 for my $policy_name ( $profile->listed_policies() ) {
301 1833 100       3301 if ( not exists $known_policies{$policy_name} ) {
302 2         8 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         26 warn qq{$message\n};
313             }
314             }
315             }
316              
317 434         4517 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 :