." />

Perl::Critic::Policy::BuiltinFunctions::ProhibitStringyEval - Write C<eval { my $foo; bar($foo) }> instead of C<eval "my $foo; bar($foo);">.


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

Index


Code Index:

NAME

Top

Perl::Critic::Policy::BuiltinFunctions::ProhibitStringyEval - Write eval { my $foo; bar($foo) } instead of eval "my $foo; bar($foo);".

AFFILIATION

Top

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

DESCRIPTION

Top

The string form of eval is recompiled every time it is executed, whereas the block form is only compiled once. Also, the string form doesn't give compile-time warnings.

    eval "print $foo";        # not ok
    eval {print $foo};        # ok




CONFIGURATION

Top

There is an allow_includes boolean option for this Policy. If set, then strings that look like they only include a single "use" or "require" statement (with the possible following statement that consists of a single number) are allowed. With this option set, the following are flagged as indicated:

    eval 'use Foo';             # ok
    eval 'require Foo';         # ok
    eval "use $thingy;";        # ok
    eval "require $thingy;";    # ok
    eval "use $thingy; 1;";     # ok
    eval "require $thingy; 1;"; # ok

    eval 'use Foo; blah;';      # still not ok
    eval 'require Foo; 2; 1;';  # still not ok
    eval 'use $thingy;';        # still not ok
    eval 'no Foo';              # still not ok

If you don't understand why the number is allowed, see Perl::Critic::Policy::ErrorHandling::RequireCheckingReturnValueOfEval.

This option inspired by Ricardo SIGNES' Perl::Critic::Policy::Lax::ProhibitStringyEval::ExceptForRequire.

SEE ALSO

Top

Perl::Critic::Policy::ControlStrucutres::RequireBlockGrep (Perl::Critic::Policy::ControlStrucutres::RequireBlockGrep)

Perl::Critic::Policy::ControlStrucutres::RequireBlockMap (Perl::Critic::Policy::ControlStrucutres::RequireBlockMap)

AUTHOR

Top

Jeffrey Ryan Thalhammer <jeff@imaginative-software.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/BuiltinFunctions/ProhibitStringyEval.pm $
#     $Date: 2011-05-15 16:34:46 -0500 (Sun, 15 May 2011) $
#   $Author: clonezone $
# $Revision: 4078 $
##############################################################################

package Perl::Critic::Policy::BuiltinFunctions::ProhibitStringyEval;

use 5.006001;
use strict;
use warnings;

use Readonly;

use PPI::Document;

use Perl::Critic::Utils qw{ :booleans :severities :classification :ppi $SCOLON };
use base 'Perl::Critic::Policy';

our $VERSION = '1.116';

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

Readonly::Scalar my $DESC => q{Expression form of "eval"};
Readonly::Scalar my $EXPL => [ 161 ];

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

sub supported_parameters {
    return (
        {
            name           => 'allow_includes',
            description    => q<Allow eval of "use" and "require" strings.>,
            default_string => '0',
            behavior       => 'boolean',
        },
    );
}
sub default_severity     { return $SEVERITY_HIGHEST   }
sub default_themes       { return qw( core pbp bugs ) }
sub applies_to           { return 'PPI::Token::Word'  }

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

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

    return if $elem ne 'eval';
    return if not is_function_call($elem);

    my $argument = first_arg($elem);
    return if not $argument;
    return if $argument->isa('PPI::Structure::Block');
    return if
        $self->{_allow_includes} and _string_eval_is_an_include($argument);

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

sub _string_eval_is_an_include {
    my ($eval_argument) = @_;

    return if not $eval_argument->isa('PPI::Token::Quote');

    my $string = $eval_argument->string();
    my $document;

    eval { $document = PPI::Document->new(\$string); 1 }
        or return;

    my @statements = $document->schildren;

    return if @statements > 2;
    my $include = $statements[0];
    return if not defined $include; # RT 60179
    return if not $include->isa('PPI::Statement::Include');
    return if $include->type() eq 'no';

    if (
            $eval_argument->isa('PPI::Token::Quote::Single')
        or  $eval_argument->isa('PPI::Token::Quote::Literal')
    ) {
        # Don't allow funky inclusion of arbitrary code (note we do allow
        # interpolated values in interpolating strings because they can't
        # entirely screw with the syntax).
        return if $include->find('PPI::Token::Symbol');
    }

    return $TRUE if @statements == 1;

    my $follow_on = $statements[1];
    return if not $follow_on->isa('PPI::Statement');

    my @follow_on_components = $follow_on->schildren();

    return if @follow_on_components > 2;
    return if not $follow_on_components[0]->isa('PPI::Token::Number');
    return $TRUE if @follow_on_components == 1;

    return $follow_on_components[1]->content() eq $SCOLON;
}


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 :