1 ##############################################################################
2 # $URL: http://perlcritic.tigris.org/svn/perlcritic/trunk/Perl-Critic/lib/Perl/Critic/Violation.pm $
3 # $Date: 2008-07-03 10:19:10 -0500 (Thu, 03 Jul 2008) $
6 ##############################################################################
8 package Perl::Critic::Violation;
13 use English qw(-no_match_vars);
16 use File::Basename qw(basename);
18 use Pod::PlainText qw();
19 use String::Format qw(stringf);
21 use overload ( q{""} => 'to_string', cmp => '_compare' );
23 use Perl::Critic::Utils qw< :characters :internal_lookup >;
24 use Perl::Critic::Utils::POD qw<
25 get_pod_section_for_module
28 use Perl::Critic::Exception::Fatal::Internal qw< &throw_internal >;
30 our $VERSION = '1.088';
33 our $FORMAT = "%m at line %l, column %c. %e.\n"; #Default stringy format
34 my %DIAGNOSTICS = (); #Cache of diagnostic messages
36 #-----------------------------------------------------------------------------
38 Readonly::Scalar my $CONSTRUCTOR_ARG_COUNT => 5;
41 my ( $class, $desc, $expl, $elem, $sev ) = @_;
43 #Check arguments to help out developers who might
44 #be creating new Perl::Critic::Policy modules.
46 if ( @_ != $CONSTRUCTOR_ARG_COUNT ) {
47 throw_internal 'Wrong number of args to Violation->new()';
50 if ( ! eval { $elem->isa( 'PPI::Element' ) } ) {
52 if ( eval { $elem->isa( 'Perl::Critic::Document' ) } ) {
53 # break the facade, return the real PPI::Document
54 $elem = $elem->{_doc};
58 '3rd arg to Violation->new() must be a PPI::Element';
63 my $self = bless {}, $class;
64 $self->{_description} = $desc;
65 $self->{_explanation} = $expl;
66 $self->{_severity} = $sev;
67 $self->{_policy} = caller;
68 $self->{_elem} = $elem;
70 # Do these now before the weakened $doc gets garbage collected
71 my $top = $elem->top();
72 $self->{_filename} = $top->can('filename') ? $top->filename() : undef;
73 $self->{_source} = _first_line_of_source( $elem );
78 #-----------------------------------------------------------------------------
80 sub set_format { return $FORMAT = verbosity_to_format( $_[0] ); } ##no critic(ArgUnpacking)
81 sub get_format { return $FORMAT; }
83 #-----------------------------------------------------------------------------
85 sub sort_by_location { ##no critic(ArgUnpacking)
87 ref $_[0] || shift; #Can call as object or class method
88 return scalar @_ if ! wantarray; #In case we are called in scalar context
90 ## no critic qw(RequireSimpleSort);
91 ## TODO: What if $a and $b are not Violation objects?
94 sort { ($a->[1] <=> $b->[1]) || ($a->[2] <=> $b->[2]) }
95 map {[$_, $_->location->[0] || 0, $_->location->[1] || 0]}
99 #-----------------------------------------------------------------------------
101 sub sort_by_severity { ##no critic(ArgUnpacking)
103 ref $_[0] || shift; #Can call as object or class method
104 return scalar @_ if ! wantarray; #In case we are called in scalar context
106 ## no critic qw(RequireSimpleSort);
107 ## TODO: What if $a and $b are not Violation objects?
110 sort { $a->[1] <=> $b->[1] }
111 map {[$_, $_->severity() || 0]}
115 #-----------------------------------------------------------------------------
120 return $self->{_location} ||= $self->{_elem}->location() || [0,0,0];
123 #-----------------------------------------------------------------------------
127 my $policy = $self->policy();
129 if ( not $DIAGNOSTICS{$policy} ) {
130 eval { ## no critic (RequireCheckingReturnValueOfEval)
131 my $module_name = ref $policy || $policy;
132 $DIAGNOSTICS{$policy} =
134 get_pod_section_for_module( $module_name, 'DESCRIPTION' )
137 $DIAGNOSTICS{$policy} ||= " No diagnostics available\n";
139 return $DIAGNOSTICS{$policy};
142 #-----------------------------------------------------------------------------
146 return $self->{_description};
149 #-----------------------------------------------------------------------------
153 my $expl = $self->{_explanation};
155 $expl = '(no explanation)';
157 if ( ref $expl eq 'ARRAY' ) {
158 my $page = @{$expl} > 1 ? 'pages' : 'page';
159 $page .= $SPACE . join $COMMA, @{$expl};
160 $expl = "See $page of PBP";
165 #-----------------------------------------------------------------------------
169 return $self->{_severity};
172 #-----------------------------------------------------------------------------
176 return $self->{_policy};
179 #-----------------------------------------------------------------------------
183 return $self->{_filename};
186 #-----------------------------------------------------------------------------
191 return $self->{_source};
194 #-----------------------------------------------------------------------------
199 my $long_policy = $self->policy();
200 (my $short_policy = $long_policy) =~ s/ \A Perl::Critic::Policy:: //xms;
202 # Wrap the more expensive ones in sub{} to postpone evaluation
204 'f' => sub { $self->filename() },
205 'F' => sub { basename( $self->filename()) },
206 'l' => sub { $self->location->[0] },
207 'c' => sub { $self->location->[1] },
208 'm' => $self->description(),
209 'e' => $self->explanation(),
210 's' => $self->severity(),
211 'd' => sub { $self->diagnostics() },
212 'r' => sub { $self->source() },
214 'p' => $short_policy,
216 return stringf($FORMAT, %fspec);
219 #-----------------------------------------------------------------------------
220 # Apparently, some perls do not implicitly stringify overloading
221 # objects before doing a comparison. This causes a couple of our
222 # sorting tests to fail. To work around this, we overload C<cmp> to
225 # 20060503 - More information: This problem has been traced to
226 # Test::Simple versions <= 0.60, not perl itself. Upgrading to
227 # Test::Simple v0.62 will fix the problem. But rather than forcing
228 # everyone to upgrade, I have decided to leave this workaround in
231 sub _compare { return "$_[0]" cmp "$_[1]" }
233 #-----------------------------------------------------------------------------
235 sub _first_line_of_source {
238 my $stmnt = $elem->statement() || $elem;
239 my $code_string = $stmnt->content() || $EMPTY;
241 #Chop everything but the first line (without newline);
242 $code_string =~ s{ \n.* }{}smx;
249 #-----------------------------------------------------------------------------
255 Perl::Critic::Violation - A violation of a Policy found in some source code.
260 use Perl::Critic::Violation;
262 my $elem = $doc->child(0); #$doc is a PPI::Document object
263 my $desc = 'Offending code'; #Describe the violation
264 my $expl = [1,45,67]; #Page numbers from PBP
265 my $sev = 5; #Severity level of this violation
267 my $vio = Perl::Critic::Violation->new($desc, $expl, $node, $sev);
271 Perl::Critic::Violation is the generic representation of an individual
272 Policy violation. Its primary purpose is to provide an abstraction
273 layer so that clients of L<Perl::Critic> don't have to know anything
274 about L<PPI>. The C<violations> method of all L<Perl::Critic::Policy>
275 subclasses must return a list of these Perl::Critic::Violation
282 =item C<new( $description, $explanation, $element, $severity )>
284 Returns a reference to a new C<Perl::Critic::Violation> object. The
285 arguments are a description of the violation (as string), an
286 explanation for the policy (as string) or a series of page numbers in
287 PBP (as an ARRAY ref), a reference to the L<PPI> element that caused
288 the violation, and the severity of the violation (as an integer).
296 =item C<description()>
298 Returns a brief description of the specific violation. In other
299 words, this value may change on a per violation basis.
301 =item C<explanation()>
303 Returns an explanation of the policy as a string or as reference to
304 an array of page numbers in PBP. This value will generally not change
305 based upon the specific code violating the policy.
309 Returns a three-element array reference containing the line and real
310 & virtual column numbers where this Violation occurred, as in
315 Returns the path to the file where this Violation occurred. In some
316 cases, the path may be undefined because the source code was not read
317 directly from a file.
321 Returns the severity of this Violation as an integer ranging from 1 to
322 5, where 5 is the "most" severe.
324 =item C<sort_by_severity( @violation_objects )>
326 If you need to sort Violations by severity, use this handy routine:
328 @sorted = Perl::Critic::Violation::sort_by_severity(@violations);
330 =item C<sort_by_location( @violation_objects )>
332 If you need to sort Violations by location, use this handy routine:
334 @sorted = Perl::Critic::Violation::sort_by_location(@violations);
336 =item C<diagnostics()>
338 Returns a formatted string containing a full discussion of the
339 motivation for and details of the Policy module that created this
340 Violation. This information is automatically extracted from the
341 C<DESCRIPTION> section of the Policy module's POD.
345 Returns the name of the L<Perl::Critic::Policy> that created this
350 Returns the string of source code that caused this exception. If the
351 code spans multiple lines (e.g. multi-line statements, subroutines or
352 other blocks), then only the first line will be returned.
354 =item C<set_format( $FORMAT )>
356 Class method. Sets the format for all Violation objects when they are
357 evaluated in string context. The default is C<'%d at line %l, column
358 %c. %e'>. See L<"OVERLOADS"> for formatting options.
360 =item C<get_format()>
362 Class method. Returns the current format for all Violation objects
363 when they are evaluated in string context.
367 Returns a string representation of this violation. The content of the
368 string depends on the current value of the C<$FORMAT> package
369 variable. See L<"OVERLOADS"> for the details.
377 =item C<$Perl::Critic::Violation::FORMAT>
379 B<DEPRECATED:> Use the C<set_format> and C<get_format> methods instead.
381 Sets the format for all Violation objects when they are evaluated in string
382 context. The default is C<'%d at line %l, column %c. %e'>. See
383 L<"OVERLOADS"> for formatting options. If you want to change C<$FORMAT>, you
384 should probably localize it first.
390 Perl::Critic::Violation overloads the C<""> operator to produce neat
391 little messages when evaluated in string context. The format depends
392 on the current value of the C<$FORMAT> package variable.
394 Formats are a combination of literal and escape characters similar to
395 the way C<sprintf> works. If you want to know the specific formatting
396 capabilities, look at L<String::Format>. Valid escape characters are:
399 ------- ----------------------------------------------------------------
400 %c Column number where the violation occurred
401 %d Full diagnostic discussion of the violation
402 %e Explanation of violation or page numbers in PBP
403 %F Just the name of the file where the violation occurred.
404 %f Path to the file where the violation occurred.
405 %l Line number where the violation occurred
406 %m Brief description of the violation
407 %P Full name of the Policy module that created the violation
408 %p Name of the Policy without the Perl::Critic::Policy:: prefix
409 %r The string of source code that caused the violation
410 %s The severity level of the violation
412 Here are some examples:
414 $Perl::Critic::Violation::FORMAT = "%m at line %l, column %c.\n";
415 #looks like "Mixed case variable name at line 6, column 23."
417 $Perl::Critic::Violation::FORMAT = "%m near '%r'\n";
418 #looks like "Mixed case variable name near 'my $theGreatAnswer = 42;'"
420 $Perl::Critic::Violation::FORMAT = "%l:%c:%p\n";
421 #looks like "6:23:NamingConventions::ProhibitMixedCaseVars"
423 $Perl::Critic::Violation::FORMAT = "%m at line %l. %e. \n%d\n";
424 #looks like "Mixed case variable name at line 6. See page 44 of PBP.
425 Conway's recommended naming convention is to use lower-case words
426 separated by underscores. Well-recognized acronyms can be in ALL
427 CAPS, but must be separated by underscores from other parts of the
432 Jeffrey Ryan Thalhammer <thaljef@cpan.org>
436 Copyright (c) 2005-2008 Jeffrey Ryan Thalhammer. All rights reserved.
438 This program is free software; you can redistribute it and/or modify
439 it under the same terms as Perl itself. The full text of this license
440 can be found in the LICENSE file included with this module.
446 # cperl-indent-level: 4
448 # indent-tabs-mode: nil
449 # c-indentation-style: bsd
451 # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :