[Chicago-talk] A Perl::Critic question

Elliot Shank chicago.pm at galumph.com
Sat Apr 10 09:35:52 PDT 2010


On 4/9/10 4:33 PM, Mike Fragassi wrote:
> According to the docs, both of these should turn off Perl::Critic within
> foo():
>
> 1) sub foo { ## no critic
> 2) sub foo {
> ## no critic
>
> But I'm finding that only the former works. Is there something about the
> #2 form that I'm missing? (This is with the most recent Perl::Critic and
> perl 5.8.5.)

It depends upon what you mean by "within".

P::C directives come in two flavors: ones that affect everything from that point forward in the document and ones that affect the current statement.  It helps to remember that P::C is based upon PPI, which affects the way it looks at things.  PPI does not parse Perl code, it parses Perl documents and multi-line elements are considered to be located at the line that their first character is on.

The first form of P::C directive is one that is located on a line by itself.  It is then in effect to the end of the document or to the next "## use critic" directive.

     sub foo {
         ...
         for (...) {
             ...
             if (...) {
                 ## no critic (ProhibitMagicNumbers)
                 ...
             }
             ...
         }
         ...
     }

     sub bar {
         ...
         while (...) {
             ...
             ## use critic
             ...
         }
         ...
     }

Assuming that there aren't any other P::C directives, ProhibitMagicNumbers is disabled for all elements with positions between the two directives; that the directives are nested within various levels of and cross between blocks doesn't mean anything.

The second form of P::C directive is one that is on the same line as some other element.   It only affects things one the same line as the directive.

     $x = 1249.34 * 20995.392333e27  ## no critic (ProhibitMagicNumbers)


So, given your original question, let's look at what happens with a policy like Subroutines::RequireFinalReturn.  The following code will result in a violation of this policy:

     sub foo {
         for (1..5) {
             say 'whatever';
         }
     }

But, doing this:

     sub foo {
         ## no critic (RequireFinalReturn)
         for (1..5) {
             say 'whatever';
         }
     }

won't suppress the violation, despite the directive occurring prior to the end of the subroutine.  This is because the element in question is the subroutine itself, which is considered to be located on the line prior to the directive.  Changing this to

     ## no critic (RequireFinalReturn)
     sub foo {
         for (1..5) {
             say 'whatever';
         }
     }

or

     sub foo { ## no critic (RequireFinalReturn)
         for (1..5) {
             say 'whatever';
         }
     }

will work.

When trying to suppress a violation, make sure you're using a P::C verbosity that causes messages to include the line number and pay strict attention to that line number when placing the suppressing directive.


More information about the Chicago-talk mailing list