Avoid PerlCritic when interpolating variables with eval

386 Views Asked by At

perlcritic is complaining with Expression form of "eval" [BuiltinFunctions::ProhibitStringyEval] on the first eval line from the code below:

use strict;
use warnings;
use feature qw/say/;

my $hasTwitter = 1;
my $validEmail = 0;

my $rule   = '${hasTwitter} | ${validEmail}';
my $result = eval $rule;
say "Result ->  $result";

$result = eval { $rule };
say "Result -> $result";

I tried to use eval {} to fix the perlCritic but then It does not return the expected result.

The response is:

Result ->  1
Result -> ${hasTwitter} | ${validEmail}

Is there a workaround using the string interpolation? The idea is to have a set of rules on a configuration file and let the code read and eval them.

Thanks

3

There are 3 best solutions below

0
choroba On

Perlcritic is not the ultimate authority. If you know what you're doing and why, just disable the given "sin" (either globally in the configuration, or by adding ## no critic to the offending line).

In this case, you can use double quotes instead of single quotes and verify there are only zeros and ones in the resulting strings before evaluating them. Implementing a parser and evaluator of logic formulas is not that hard, either.

1
simbabque On

You can turn individual Perl::Critic rules off for specific blocks. Add a comment like this. Note the double comment ## is on purpose.

my $rule   = '${hasTwitter} | ${validEmail}';

## no critic 'ProhibitStringyEval'
my $result = eval $rule;

As this works per block, you will want to do it in the smallest possible scope, just like a use or no.

It makes sense to explain in a comment why you did that. Usually your team would have good reasons to pick the rules, and you should only turn them off if you have a better reason for your specific case.

2
ikegami On

The critic is there to make you think: Is there a reason for the expression to be there as a string? Can it be avoided given the numerous pitfalls and high security risks? Or rather, are the risks and problems worth avoiding a little work?

For starters, could you have used the following?

my $rule = sub { $hasTwitter || $validEmail };

my $result = $rule->();

Or maybe

my $rule = 'has_twitter_or_email';

my %rules = (
   has_twitter_or_email => sub { $hasTwitter || $validEmail },
);
my $result = $rules{$rule}->();