File Coverage

blib/lib/Perl/Critic/UserProfile.pm
Criterion Covered Total %
statement 120 128 93.7
branch 16 26 61.5
condition 18 30 60.0
subroutine 29 30 96.6
pod 8 8 100.0
total 191 222 86.0


line stmt bran cond sub pod time code
1             package Perl::Critic::UserProfile;
2              
3 40     40   40442 use 5.010001;
  40         129  
4 40     40   178 use strict;
  40         72  
  40         828  
5 40     40   137 use warnings;
  40         70  
  40         1452  
6              
7 40     40   3812 use Readonly;
  40         22294  
  40         1749  
8              
9 40     40   16811 use Config::Tiny qw();
  40         49434  
  40         981  
10 40     40   242 use File::Spec qw();
  40         70  
  40         541  
11              
12 40     40   15421 use Perl::Critic::OptionsProcessor qw();
  40         123  
  40         1187  
13 40     40   249 use Perl::Critic::Utils qw{ $EMPTY policy_long_name policy_short_name };
  40         68  
  40         3810  
14 40     40   224 use Perl::Critic::Exception::Fatal::Internal qw{ throw_internal };
  40         75  
  40         1524  
15 40     40   3439 use Perl::Critic::Exception::Configuration::Generic qw{ throw_generic };
  40         100  
  40         796  
16 40     40   3919 use Perl::Critic::PolicyConfig;
  40         75  
  40         46963  
17              
18             our $VERSION = '1.156';
19              
20             #-----------------------------------------------------------------------------
21              
22             sub new {
23              
24 444     444 1 63678 my ( $class, %args ) = @_;
25 444         1034 my $self = bless {}, $class;
26 444         1682 $self->_init( %args );
27 440         1308 return $self;
28             }
29              
30             #-----------------------------------------------------------------------------
31              
32             sub _init {
33              
34 444     444   987 my ( $self, %args ) = @_;
35             # The profile can be defined, undefined, or an empty string.
36 444   66     1515 my $profile = $args{-profile} // _find_profile_path();
37 444         1451 $self->_load_profile( $profile );
38 440         1224 $self->_set_options_processor();
39 440         837 return $self;
40             }
41              
42             #-----------------------------------------------------------------------------
43              
44             sub options_processor {
45              
46 2118     2118 1 2684 my ($self) = @_;
47 2118         5288 return $self->{_options_processor};
48             }
49              
50             #-----------------------------------------------------------------------------
51              
52             sub policy_params {
53              
54 12507     12507 1 20538 my ( $self, $policy ) = @_;
55              
56 12507         20789 my $short_name = policy_short_name($policy);
57              
58 12507         32286 return Perl::Critic::PolicyConfig->new(
59             $short_name,
60             $self->raw_policy_params($policy),
61             );
62             }
63              
64             #-----------------------------------------------------------------------------
65              
66             sub raw_policy_params {
67              
68 12519     12519 1 17308 my ( $self, $policy ) = @_;
69 12519         19658 my $profile = $self->{_profile};
70 12519   33     31213 my $long_name = ref $policy || policy_long_name( $policy );
71 12519         18925 my $short_name = policy_short_name( $long_name );
72              
73             return
74             $profile->{$short_name}
75             || $profile->{$long_name}
76             || $profile->{"-$short_name"}
77 12519   100     114995 || $profile->{"-$long_name"}
78             || {};
79             }
80              
81             #-----------------------------------------------------------------------------
82              
83             sub policy_is_disabled {
84              
85 11031     11031 1 16067 my ( $self, $policy ) = @_;
86 11031         16232 my $profile = $self->{_profile};
87 11031   66     23185 my $long_name = ref $policy || policy_long_name( $policy );
88 11031         22231 my $short_name = policy_short_name( $long_name );
89              
90             return exists $profile->{"-$short_name"}
91 11031   100     58689 || exists $profile->{"-$long_name"};
92             }
93              
94             #-----------------------------------------------------------------------------
95              
96             sub policy_is_enabled {
97              
98 11031     11031 1 15973 my ( $self, $policy ) = @_;
99 11031         14316 my $profile = $self->{_profile};
100 11031   66     20035 my $long_name = ref $policy || policy_long_name( $policy );
101 11031         17602 my $short_name = policy_short_name( $long_name );
102              
103             return exists $profile->{$short_name}
104 11031   66     38655 || exists $profile->{$long_name};
105             }
106              
107             #-----------------------------------------------------------------------------
108              
109             sub listed_policies {
110              
111 435     435 1 874 my ( $self, $policy ) = @_;
112 435         549 my @normalized_policy_names;
113              
114 435         679 for my $policy_name ( sort keys %{$self->{_profile}} ) {
  435         2483  
115 1833         2318 $policy_name =~ s/\A - //xmso; #Chomp leading "-"
116 1833         2333 my $policy_long_name = policy_long_name( $policy_name );
117 1833         2345 push @normalized_policy_names, $policy_long_name;
118             }
119              
120 435         1429 return @normalized_policy_names;
121             }
122              
123             #-----------------------------------------------------------------------------
124              
125             sub source {
126 3505     3505 1 4207 my ( $self ) = @_;
127              
128 3505         4926 return $self->{_source};
129             }
130              
131             sub _set_source {
132 3     3   7 my ( $self, $source ) = @_;
133              
134 3         9 $self->{_source} = $source;
135              
136 3         6 return;
137             }
138              
139             #-----------------------------------------------------------------------------
140             # Begin PRIVATE methods
141              
142             Readonly::Hash my %LOADER_FOR => (
143             ARRAY => \&_load_profile_from_array,
144             DEFAULT => \&_load_profile_from_file,
145             HASH => \&_load_profile_from_hash,
146             SCALAR => \&_load_profile_from_string,
147             );
148              
149             sub _load_profile {
150              
151 444     444   986 my ( $self, $profile ) = @_;
152              
153 444   100     1654 my $ref_type = ref $profile || 'DEFAULT';
154 444         2825 my $loader = $LOADER_FOR{$ref_type};
155              
156 444 100       3689 if (not $loader) {
157 1         6 throw_internal qq{Can't load UserProfile from type "$ref_type"};
158             }
159              
160 443         1070 $self->{_profile} = $loader->($self, $profile);
161 440         782 return $self;
162             }
163              
164             #-----------------------------------------------------------------------------
165              
166             sub _set_options_processor {
167              
168 440     440   850 my ($self) = @_;
169 440         737 my $profile = $self->{_profile};
170 440   100     1511 my $defaults = delete $profile->{__defaults__} || {};
171             $self->{_options_processor} =
172 440         645 Perl::Critic::OptionsProcessor->new( %{ $defaults } );
  440         2305  
173 440         1063 return $self;
174             }
175              
176             #-----------------------------------------------------------------------------
177              
178             sub _load_profile_from_file {
179 386     386   740 my ( $self, $file ) = @_;
180              
181             # Handle special cases.
182 386 100       895 return {} if not defined $file;
183 354 100       940 return {} if $file eq $EMPTY;
184 351 100       1202 return {} if $file eq 'NONE';
185              
186 3         13 $self->_set_source( $file );
187              
188 3         21 my $profile = Config::Tiny->read( $file );
189 3 100       3809 if (not defined $profile) {
190 1         4 my $errstr = Config::Tiny::errstr();
191 1         6 throw_generic
192             message => qq{Could not parse profile "$file": $errstr},
193             source => $file;
194             }
195              
196 2         11 _fix_defaults_key( $profile );
197              
198 2         7 return $profile;
199             }
200              
201             #-----------------------------------------------------------------------------
202              
203             sub _load_profile_from_array {
204 1     1   3 my ( $self, $array_ref ) = @_;
205 1         3 my $joined = join qq{\n}, @{ $array_ref };
  1         3  
206 1         11 my $profile = Config::Tiny->read_string( $joined );
207              
208 1 50       89 if (not defined $profile) {
209 0         0 throw_generic 'Profile error: ' . Config::Tiny::errstr();
210             }
211              
212 1         4 _fix_defaults_key( $profile );
213              
214 1         3 return $profile;
215             }
216              
217             #-----------------------------------------------------------------------------
218              
219             sub _load_profile_from_string {
220 5     5   10 my ( $self, $string ) = @_;
221 5         8 my $profile = Config::Tiny->read_string( ${ $string } );
  5         36  
222              
223 5 100       19996 if (not defined $profile) {
224 2         4 throw_generic 'Profile error: ' . Config::Tiny::errstr();
225             }
226              
227 3         12 _fix_defaults_key( $profile );
228              
229 3         9 return $profile;
230             }
231              
232             #-----------------------------------------------------------------------------
233              
234             sub _load_profile_from_hash {
235 51     51   122 my ( $self, $hash_ref ) = @_;
236 51         154 return $hash_ref;
237             }
238              
239             #-----------------------------------------------------------------------------
240              
241             sub _find_profile_path {
242              
243             #Check explicit environment setting
244 1 50   1   1017 return $ENV{PERLCRITIC} if exists $ENV{PERLCRITIC};
245              
246             #Define default filename
247 0         0 my $rc_file = '.perlcriticrc';
248              
249             #Check current directory
250 0 0       0 return $rc_file if -f $rc_file;
251              
252             #Check home directory
253 0 0       0 if ( my $home_dir = _find_home_dir() ) {
254 0         0 my $path = File::Spec->catfile( $home_dir, $rc_file );
255 0 0       0 return $path if -f $path;
256             }
257              
258             #No profile defined
259 0         0 return;
260             }
261              
262             #-----------------------------------------------------------------------------
263              
264             sub _find_home_dir {
265             # This logic is taken from File::HomeDir::Tiny.
266             return
267             ($^O eq 'MSWin32') && ("$]" < 5.016) ## no critic ( Variables::ProhibitPunctuationVars ValuesAndExpressions::ProhibitMagicNumbers ValuesAndExpressions::ProhibitMismatchedOperators )
268             ? ($ENV{HOME} || $ENV{USERPROFILE})
269 0 0 0 0   0 : (<~>)[0];
      0        
270             }
271              
272             #-----------------------------------------------------------------------------
273              
274             # !$%@$%^ Config::Tiny uses a completely non-descriptive name for global
275             # values.
276             sub _fix_defaults_key {
277 6     6   14 my ( $profile ) = @_;
278              
279 6         12 my $defaults = delete $profile->{_};
280 6 100       75 if ($defaults) {
281 3         11 $profile->{__defaults__} = $defaults;
282             }
283              
284 6         12 return;
285             }
286              
287             1;
288              
289             __END__
290              
291             #-----------------------------------------------------------------------------
292              
293             =pod
294              
295             =for stopwords UserProfile
296              
297             =head1 NAME
298              
299             Perl::Critic::UserProfile - The contents of the user's profile, often F<.perlcriticrc>.
300              
301              
302             =head1 DESCRIPTION
303              
304             This is a helper class that encapsulates the contents of the user's
305             profile, which is usually stored in a F<.perlcriticrc> file. There are
306             no user-serviceable parts here.
307              
308              
309             =head1 INTERFACE SUPPORT
310              
311             This is considered to be a non-public class. Its interface is subject
312             to change without notice.
313              
314              
315             =head1 CONSTRUCTOR
316              
317             =over
318              
319             =item C<< new( -profile => $p ) >>
320              
321             B<-profile> is the path to the user's profile. If -profile is not
322             defined, then it looks for the profile at F<./.perlcriticrc> and then
323             F<$HOME/.perlcriticrc>. If neither of those files exists, then the
324             UserProfile is created with default values.
325              
326             This object does not take into account any command-line overrides;
327             L<Perl::Critic::Config|Perl::Critic::Config> does that.
328              
329              
330             =back
331              
332              
333             =head1 METHODS
334              
335             =over
336              
337             =item C< options_processor() >
338              
339             Returns the
340             L<Perl::Critic::OptionsProcessor|Perl::Critic::OptionsProcessor>
341             object for this UserProfile.
342              
343              
344             =item C< policy_is_disabled( $policy ) >
345              
346             Given a reference to a L<Perl::Critic::Policy|Perl::Critic::Policy>
347             object or the name of one, returns true if the user has disabled that
348             policy in their profile.
349              
350              
351             =item C< policy_is_enabled( $policy ) >
352              
353             Given a reference to a L<Perl::Critic::Policy|Perl::Critic::Policy>
354             object or the name of one, returns true if the user has explicitly
355             enabled that policy in their user profile.
356              
357              
358             =item C< policy_params( $policy ) >
359              
360             Given a reference to a L<Perl::Critic::Policy|Perl::Critic::Policy>
361             object or the name of one, returns a
362             L<Perl::Critic::PolicyConfig|Perl::Critic::PolicyConfig> for the
363             user's configuration parameters for that policy.
364              
365              
366             =item C< raw_policy_params( $policy ) >
367              
368             Given a reference to a L<Perl::Critic::Policy|Perl::Critic::Policy>
369             object or the name of one, returns a reference to a hash of the user's
370             configuration parameters for that policy.
371              
372              
373             =item C< listed_policies() >
374              
375             Returns a list of the names of all the Policies that are mentioned in
376             the profile. The Policy names will be fully qualified (e.g.
377             Perl::Critic::Foo).
378              
379              
380             =item C< source() >
381              
382             The place where the profile information came from, if available.
383             Usually the path to a F<.perlcriticrc>.
384              
385              
386             =back
387              
388              
389             =head1 SEE ALSO
390              
391             L<Perl::Critic::Config|Perl::Critic::Config>,
392             L<Perl::Critic::OptionsProcessor|Perl::Critic::OptionsProcessor>
393              
394              
395             =head1 AUTHOR
396              
397             Jeffrey Ryan Thalhammer <jeff@imaginative-software.com>
398              
399              
400             =head1 COPYRIGHT
401              
402             Copyright (c) 2005-2023 Imaginative Software Systems.
403              
404             This program is free software; you can redistribute it and/or modify
405             it under the same terms as Perl itself. The full text of this license
406             can be found in the LICENSE file included with this module.
407              
408             =cut
409              
410             # Local Variables:
411             # mode: cperl
412             # cperl-indent-level: 4
413             # fill-column: 78
414             # indent-tabs-mode: nil
415             # c-indentation-style: bsd
416             # End:
417             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :