Perl::Critic::Policy::Lax::ProhibitStringyEval::ExceptForRequire - Perl::Critic::Policy::Lax::ProhibitStringyEval::ExceptForRequire documentation


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

Index


Code Index:

NAME

Top

Perl::Critic::Policy::Lax::ProhibitStringyEval::ExceptForRequire

VERSION

Top

version 0.008

DESCRIPTION

Top

Sure, everybody sane agrees that stringy eval is usually a bad thing, but sometimes you need it, and you don't want to have to stick a no critic on the end, because dangit, what you are doing is just not wrong!

See, require is busted. You can't pass it a variable containing the name of a module and have it look through @INC. That has lead to this common idiom:

  eval qq{ require $module } or die $@;

This policy acts just like BuiltinFunctions::ProhibitStringyEval, but makes an exception when the content of the string is PPI-parseable Perl that looks something like this:

  require $module
  require $module[2];
  use $module (); 1;

AUTHOR

Top

Ricardo SIGNES <rjbs@cpan.org>

Adapted from BuiltinFunctions::ProhibitStringyEval by Jeffrey Ryan Thalhammer

COPYRIGHT

Top


Perl-Critic-Lax documentation Contained in the Perl-Critic-Lax distribution.
use strict;
use warnings;

package Perl::Critic::Policy::Lax::ProhibitStringyEval::ExceptForRequire;

use Perl::Critic::Utils;
use base qw(Perl::Critic::Policy);

our $VERSION = '0.008';

my $DESCRIPTION = 'Expression form of "eval" for something other than require';
my $EXPLANATION = <<'END_EXPLANATION';
It's okay to use stringy eval to require a module by name, but otherwise it's
probably a mistake.
END_EXPLANATION

sub default_severity { return $SEVERITY_HIGHEST  }
sub default_themes   { return qw( danger )       }
sub applies_to       { return 'PPI::Token::Word' }

sub _arg_is_ok {
  my ($self, $arg) = @_;

  return unless $arg->isa('PPI::Token::Quote::Double')
             or $arg->isa('PPI::Token::Quote::Interpolate');

  my $string = $arg->string;

  return unless my $doc = eval { PPI::Document->new(\$string) };

  my @children = $doc->schildren;

  # We only allow {require} and {require;number}
  return if @children > 2;
  return unless $children[0]->isa('PPI::Statement::Include');

  # We could give up if the Include's second child isn't a Symbol, but... eh!

  # So, we know it's got a require first.  If that's all, great.
  return 1 if @children == 1;

  # Otherwise, it must end in something like {1} or {1;}
  return unless $children[1]->isa('PPI::Statement');

  my @tail_bits = $children[1]->schildren;

  return if @tail_bits > 2
         or ! $tail_bits[0]->isa('PPI::Token::Number')
         or ($tail_bits[1] && $tail_bits[1] ne ';');

  return 1;
}

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

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

  my $sib = $elem->snext_sibling();
  return unless $sib;
  my $arg = $sib->isa('PPI::Structure::List') ? $sib->schild(0) : $sib;

  # Blocks are always just fine!
  return if not($arg) or $arg->isa('PPI::Structure::Block');

  # It's OK if the string we're evaluating is just "require $var"
  return if $self->_arg_is_ok($arg);

  # Otherwise, you are in trouble.
  return $self->violation($DESCRIPTION, $EXPLANATION, $elem);
}

1;