1 ##############################################################################
2 # $URL: http://perlcritic.tigris.org/svn/perlcritic/trunk/Perl-Critic/lib/Perl/Critic/PolicyFactory.pm $
3 # $Date: 2008-07-03 10:19:10 -0500 (Thu, 03 Jul 2008) $
6 ##############################################################################
8 package Perl::Critic::PolicyFactory;
14 use English qw(-no_match_vars);
16 use File::Spec::Unix qw();
17 use List::MoreUtils qw(any);
19 use Perl::Critic::Utils qw{
27 use Perl::Critic::PolicyConfig;
28 use Perl::Critic::Exception::AggregateConfiguration;
29 use Perl::Critic::Exception::Configuration;
30 use Perl::Critic::Exception::Fatal::Generic qw{ throw_generic };
31 use Perl::Critic::Exception::Fatal::Internal qw{ throw_internal };
32 use Perl::Critic::Exception::Fatal::PolicyDefinition
33 qw{ throw_policy_definition };
34 use Perl::Critic::Utils::Constants qw{ :profile_strictness };
36 use Exception::Class; # this must come after "use P::C::Exception::*"
38 our $VERSION = '1.088';
40 #-----------------------------------------------------------------------------
43 my @SITE_POLICY_NAMES = ();
45 #-----------------------------------------------------------------------------
47 # Blech!!! This is ug-lee. Belongs in the constructor. And it shouldn't be
51 my ( $class, %args ) = @_;
52 my $test_mode = $args{-test};
53 my $extra_test_policies = $args{'-extra-test-policies'};
55 if ( not @SITE_POLICY_NAMES ) {
56 my $eval_worked = eval {
57 require Module::Pluggable;
58 Module::Pluggable->import(search_path => $POLICY_NAMESPACE,
59 require => 1, inner => 0);
60 @SITE_POLICY_NAMES = plugins(); #Exported by Module::Pluggable
64 if (not $eval_worked) {
67 qq<Can't load Policies from namespace "$POLICY_NAMESPACE": $EVAL_ERROR>;
71 qq<Can't load Policies from namespace "$POLICY_NAMESPACE" for an unknown reason.>;
74 if ( not @SITE_POLICY_NAMES ) {
76 qq<No Policies found in namespace "$POLICY_NAMESPACE".>;
80 # In test mode, only load native policies, not third-party ones
81 if ( $test_mode && any {m/\b blib \b/xms} @INC ) {
82 @SITE_POLICY_NAMES = _modules_from_blib( @SITE_POLICY_NAMES );
84 if ($extra_test_policies) {
85 my @extra_policy_full_names =
86 map { "${POLICY_NAMESPACE}::$_" } @{$extra_test_policies};
88 push @SITE_POLICY_NAMES, @extra_policy_full_names;
95 #-----------------------------------------------------------------------------
96 # Some static helper subs
98 sub _modules_from_blib {
100 return grep { _was_loaded_from_blib( _module2path($_) ) } @modules;
104 my $module = shift || return;
105 return File::Spec::Unix->catdir(split m/::/xms, $module) . '.pm';
108 sub _was_loaded_from_blib {
109 my $path = shift || return;
110 my $full_path = $INC{$path};
111 return $full_path && $full_path =~ m/ (?: \A | \b b ) lib \b /xms;
114 #-----------------------------------------------------------------------------
118 my ( $class, %args ) = @_;
119 my $self = bless {}, $class;
120 $self->_init( %args );
124 #-----------------------------------------------------------------------------
128 my ($self, %args) = @_;
130 my $profile = $args{-profile};
131 $self->{_profile} = $profile
132 or throw_internal q{The -profile argument is required};
134 my $incoming_errors = $args{-errors};
135 my $profile_strictness = $args{'-profile-strictness'};
136 $profile_strictness ||= $PROFILE_STRICTNESS_DEFAULT;
138 if ( $profile_strictness ne $PROFILE_STRICTNESS_QUIET ) {
141 # If we're supposed to be strict or problems have already been found...
143 $profile_strictness eq $PROFILE_STRICTNESS_FATAL
144 or ( $incoming_errors and @{ $incoming_errors->exceptions() } )
149 : Perl::Critic::Exception::AggregateConfiguration->new();
152 $self->_validate_policies_in_profile( $errors );
157 and $errors->has_exceptions()
166 #-----------------------------------------------------------------------------
170 my ($self, %args ) = @_;
172 my $policy_name = $args{-name}
173 or throw_internal q{The -name argument is required};
175 # Normalize policy name to a fully-qualified package name
176 $policy_name = policy_long_name( $policy_name );
177 my $policy_short_name = policy_short_name( $policy_name );
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 my $profile = $self->_profile();
184 if ( $args{-params} ) {
186 Perl::Critic::PolicyConfig->new(
187 $policy_short_name, $args{-params}
191 $policy_config = $profile->policy_params($policy_name);
193 Perl::Critic::PolicyConfig->new( $policy_short_name );
196 # Pull out base parameters.
197 return _instantiate_policy( $policy_name, $policy_config );
200 #-----------------------------------------------------------------------------
202 sub create_all_policies {
204 my ( $self, $incoming_errors ) = @_;
209 : Perl::Critic::Exception::AggregateConfiguration->new();
212 foreach my $name ( site_policy_names() ) {
213 my $policy = eval { $self->create_policy( -name => $name ) };
215 $errors->add_exception_or_rethrow( $EVAL_ERROR );
218 push @policies, $policy;
222 if ( not $incoming_errors and $errors->has_exceptions() ) {
229 #-----------------------------------------------------------------------------
231 sub site_policy_names {
232 return sort @SITE_POLICY_NAMES;
235 #-----------------------------------------------------------------------------
240 return $self->{_profile};
243 #-----------------------------------------------------------------------------
245 # This two-phase initialization is caused by the historical lack of a
246 # requirement for Policies to invoke their super-constructor.
247 sub _instantiate_policy {
248 my ($policy_name, $policy_config) = @_;
250 my $policy = eval { $policy_name->new( %{$policy_config} ) };
251 _handle_policy_instantiation_exception(
253 $policy, # Note: being used as a boolean here.
257 $policy->__set_config( $policy_config );
259 my $eval_worked = eval { $policy->__set_base_parameters(); 1; };
260 _handle_policy_instantiation_exception(
261 $policy_name, $eval_worked, $EVAL_ERROR,
267 sub _handle_policy_instantiation_exception {
268 my ($policy_name, $eval_worked, $eval_error) = @_;
270 if (not $eval_worked) {
272 my $exception = Exception::Class->caught();
274 if (ref $exception) {
275 $exception->rethrow();
278 throw_policy_definition
279 qq<Unable to create policy "$policy_name": $eval_error>;
282 throw_policy_definition
283 qq<Unable to create policy "$policy_name" for an unknown reason.>;
289 #-----------------------------------------------------------------------------
291 sub _validate_policies_in_profile {
292 my ($self, $errors) = @_;
294 my $profile = $self->_profile();
295 my %known_policies = hashify( $self->site_policy_names() );
297 for my $policy_name ( $profile->listed_policies() ) {
298 if ( not exists $known_policies{$policy_name} ) {
299 my $message = qq{Policy "$policy_name" is not installed.};
302 $errors->add_message( $message );
313 #-----------------------------------------------------------------------------
322 =for stopwords PolicyFactory -params
326 Perl::Critic::PolicyFactory - Instantiates Policy objects.
330 This is a helper class that instantiates L<Perl::Critic::Policy> objects with
331 the user's preferred parameters. There are no user-serviceable parts here.
337 =item C<< new( -profile => $profile, -errors => $config_errors ) >>
339 Returns a reference to a new Perl::Critic::PolicyFactory object.
341 B<-profile> is a reference to a L<Perl::Critic::UserProfile> object. This
342 argument is required.
344 B<-errors> is a reference to an instance of L<Perl::Critic::ConfigErrors>.
345 This argument is optional. If specified, than any problems found will be
354 =item C<< create_policy( -name => $policy_name, -params => \%param_hash ) >>
356 Creates one Policy object. If the object cannot be instantiated, it will
357 throw a fatal exception. Otherwise, it returns a reference to the new Policy
360 B<-name> is the name of a L<Perl::Critic::Policy> subclass module. The
361 C<'Perl::Critic::Policy'> portion of the name can be omitted for brevity.
362 This argument is required.
364 B<-params> is an optional reference to hash of parameters that will be passed
365 into the constructor of the Policy. If C<-params> is not defined, we will use
366 the appropriate Policy parameters from the L<Perl::Critic::UserProfile>.
368 Note that the Policy will not have had
369 L<Perl::Critic::Policy/"initialize_if_enabled"> invoked on it, so it may not
372 =item C< create_all_policies() >
374 Constructs and returns one instance of each L<Perl::Critic::Policy> subclass
375 that is installed on the local system. Each Policy will be created with the
376 appropriate parameters from the user's configuration profile.
378 Note that the Policies will not have had
379 L<Perl::Critic::Policy/"initialize_if_enabled"> invoked on them, so they may
386 Perl::Critic::PolicyFactory has a few static subroutines that are used
387 internally, but may be useful to you in some way.
391 =item C<site_policy_names()>
393 Returns a list of all the Policy modules that are currently installed in the
394 Perl::Critic:Policy namespace. These will include modules that are
395 distributed with Perl::Critic plus any third-party modules that have been
402 Jeffrey Ryan Thalhammer <thaljef@cpan.org>
406 Copyright (c) 2005-2008 Jeffrey Ryan Thalhammer. All rights reserved.
408 This program is free software; you can redistribute it and/or modify it under
409 the same terms as Perl itself. The full text of this license can be found in
410 the LICENSE file included with this module.
416 # cperl-indent-level: 4
418 # indent-tabs-mode: nil
419 # c-indentation-style: bsd
421 # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :