Perl::Critic::Policy::Modules::RequireNoMatchVarsWithUseEnglish - C<use English> must be passed a C<-no_match_vars> argument.


Perl-Critic documentation Contained in the Perl-Critic distribution.

Index


Code Index:

NAME

Top

Perl::Critic::Policy::Modules::RequireNoMatchVarsWithUseEnglish - use English must be passed a -no_match_vars argument.

AFFILIATION

Top

This Policy is part of the core Perl::Critic distribution.

DESCRIPTION

Top

Due to unfortunate history, if you use the English module but don't pass in a -no_match_vars argument, all regular expressions in the entire program, not merely the module in question, suffer a significant performance penalty, even if you only import a subset of the variables.

    use English;                              # not ok
    use English '-no_match_vars';             # ok
    use English qw< $ERRNO -no_match_vars >;  # ok
    use English qw($OS_ERROR);                # not ok

In the last example above, while the match variables aren't loaded into your namespace, they are still created in the English namespace and you still pay the cost.

CONFIGURATION

Top

This Policy is not configurable except for the standard options.

AUTHOR

Top

Elliot Shank <perl@galumph.com>

COPYRIGHT

Top


Perl-Critic documentation Contained in the Perl-Critic distribution.

##############################################################################
#      $URL: http://perlcritic.tigris.org/svn/perlcritic/trunk/distributions/Perl-Critic/lib/Perl/Critic/Policy/Modules/RequireNoMatchVarsWithUseEnglish.pm $
#     $Date: 2011-05-15 16:34:46 -0500 (Sun, 15 May 2011) $
#   $Author: clonezone $
# $Revision: 4078 $
##############################################################################

package Perl::Critic::Policy::Modules::RequireNoMatchVarsWithUseEnglish;

use 5.006001;
use strict;
use warnings;

use Readonly;

use Perl::Critic::Utils qw< :characters :severities >;
use base 'Perl::Critic::Policy';

our $VERSION = '1.116';

#-----------------------------------------------------------------------------

Readonly::Scalar my $EXPL =>
    q{"use English" without the '-no_match_vars' argument degrades performance.'};
Readonly::Scalar my $DESC => q{"use English" without '-no_match_vars' argument};

#-----------------------------------------------------------------------------

sub supported_parameters { return ()                        }
sub default_severity     { return $SEVERITY_LOW             }
sub default_themes       { return qw( core performance )    }
sub applies_to           { return 'PPI::Statement::Include' }

#-----------------------------------------------------------------------------

sub violates {
    my ( $self, $elem, $doc ) = @_;

    # "require"ing English is kind of useless.
    return if $elem->type() ne 'use';
    return if $elem->module() ne 'English';

    my @elements = $elem->schildren();
    shift @elements; # dump "use"
    shift @elements; # dump "English"

    if (not @elements) {
        return $self->violation($DESC, $EXPL, $elem);
    }

    _skip_version_number( \@elements );

    @elements = _descend_into_parenthesized_list_if_present(@elements);

    if (not @elements) {
        return $self->violation($DESC, $EXPL, $elem);
    }

    my $current_element = $elements[0];

    while ( $current_element ) {
        if ( $current_element->isa('PPI::Token::Quote') ) {
            return if $current_element->string() eq '-no_match_vars';
        }
        elsif ( $current_element->isa('PPI::Token::QuoteLike::Words') ) {
            return if $current_element->content() =~ m/-no_match_vars \b/xms;
        }
        elsif (
                not $current_element->isa('PPI::Token::Operator')
            or  $current_element->content() ne $COMMA
            and $current_element->content() ne $FATCOMMA
        ) {
            return $self->violation($DESC, $EXPL, $elem);
        }

        shift @elements;
        $current_element = $elements[0];
    }

    return $self->violation($DESC, $EXPL, $elem);
}


sub _skip_version_number {
    my ($elements_ref) = @_;

    my $current_element = $elements_ref->[0];

    if ( $current_element->isa('PPI::Token::Number') ) {
        shift @{$elements_ref};
    }
    elsif (
            @{$elements_ref} >= 2
        and $current_element->isa('PPI::Token::Word')
        and $current_element->content() =~ m/\A v \d+ \z/xms
        and $elements_ref->[1]->isa('PPI::Token::Number')
    ) {
        # The above messy conditional necessary due to PPI not handling
        # v-strings.
        shift @{$elements_ref};
        shift @{$elements_ref};
    }

    return;
}

sub _descend_into_parenthesized_list_if_present {
    my @elements = @_;

    return if not @elements;

    my $current_element = $elements[0];

    if ( $current_element->isa('PPI::Structure::List') ) {
        my @grand_children = $current_element->schildren();
        if (not @grand_children) {
            return;
        }

        my $grand_child = $grand_children[0];

        if ( $grand_child->isa('PPI::Statement::Expression') ) {
            my @great_grand_children = $grand_child->schildren();

            if (not @great_grand_children) {
                return;
            }

            return @great_grand_children;
        }
        else {
            return @grand_children;
        }
    }

    return @elements;
}

1;

__END__

#-----------------------------------------------------------------------------

# Local Variables:
#   mode: cperl
#   cperl-indent-level: 4
#   fill-column: 78
#   indent-tabs-mode: nil
#   c-indentation-style: bsd
# End:
# ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :