Skip to content

Commit

Permalink
r27598@knight: rjbs | 2006-11-06 22:14:30 -0500
Browse files Browse the repository at this point in the history
 I won't need that no critic thing with my new policy
 
 r27625@knight:  rjbs | 2006-11-06 22:28:31 -0500
 critic plugins
 r27626@knight:  rjbs | 2006-11-06 22:28:51 -0500
 more dist stuff
 r27627@knight:  rjbs | 2006-11-06 22:29:18 -0500
 structure
 r27628@knight:  rjbs | 2006-11-06 22:29:27 -0500
 tag release
  • Loading branch information
rjbs committed Nov 7, 2006
0 parents commit 9fb6657
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 0 deletions.
3 changes: 3 additions & 0 deletions Changes
@@ -0,0 +1,3 @@

0.001 2006-11-06
initial release
17 changes: 17 additions & 0 deletions MANIFEST
@@ -0,0 +1,17 @@
Changes
inc/Module/Install.pm
inc/Module/Install/Base.pm
inc/Module/Install/Can.pm
inc/Module/Install/Fetch.pm
inc/Module/Install/Makefile.pm
inc/Module/Install/Metadata.pm
inc/Module/Install/Win32.pm
inc/Module/Install/WriteAll.pm
lib/Perl/Critic/Policy/Lax/ProhibitStringyEval/ExceptForRequire.pm
Makefile.PL
MANIFEST This list of files
META.yml
README
t/basic.t
t/pod-coverage.t
t/pod.t
14 changes: 14 additions & 0 deletions Makefile.PL
@@ -0,0 +1,14 @@
use strict;
use warnings;

use inc::Module::Install;

name ('Perl-Critic-Lax');
author ('Ricardo SIGNES <rjbs@cpan.org>');
license ('perl');
version_from
'lib/Perl/Critic/Policy/Lax/ProhibitStringyEval/ExceptForRequire.pm';

requires('Perl::Critic' => 0.21);

WriteAll();
2 changes: 2 additions & 0 deletions README
@@ -0,0 +1,2 @@

This distribution includes more policies for Perl::Critic.
112 changes: 112 additions & 0 deletions lib/Perl/Critic/Policy/Lax/ProhibitStringyEval/ExceptForRequire.pm
@@ -0,0 +1,112 @@
package Perl::Critic::Policy::Lax::ProhibitStringyEval::ExceptForRequire;

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

our $VERSION = 0.001;

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"
# I should do THIS with PPI, too! -- rjbs, 2006-11-06
return if $self->_arg_is_ok($arg);

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

1;

=head1 NAME
Perl::Critic::Policy::Lax::ProhibitStringyEval::ExceptForRequire
=head1 DESCRIPTION
Sure, everybody sane agrees that stringy C<eval> is usually a bad thing, but
sometimes you need it, and you don't want to have to stick a C<no critic> on
the end, because dangit, what you are doing is I<just not wrong>!
See, C<require> is busted. You can't pass it a variable containing the name of
a module and have it look through C<@INC>. That has lead to this common idiom:
eval q{ 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;
=head1 AUTHOR
Ricardo SIGNES <rjbs@cpan.org>
Adapted from BuiltinFunctions::ProhibitStringyEval by Jeffrey Ryan Thalhammer
=head1 COPYRIGHT
This distribution is copyright 2006, Ricardo SIGNES.
This program is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
30 changes: 30 additions & 0 deletions t/basic.t
@@ -0,0 +1,30 @@

use strict;
use warnings;

use Perl::Critic::TestUtils qw(pcritique);
use Test::More tests => 6;

my @ok = (
q{ eval "require $string" },
q{ eval "require $string; 19;" },
q{ eval "use $module 1 qw(a b c); 1" },
);

my @not_ok = (
q{ eval "system 'rm -rf /'" },
q{ eval "require $string; die" },
q{ eval 'require $string' },
);

my $policy = 'Lax::ProhibitStringyEval::ExceptForRequire';

for my $test (@ok) {
my $violation_count = pcritique($policy, \$test);
is($violation_count, 0, "nothing wrong with C< $test >");
}

for my $test (@not_ok) {
my $violation_count = pcritique($policy, \$test);
is($violation_count, 1, "C< $test > is no good");
}
8 changes: 8 additions & 0 deletions t/pod-coverage.t
@@ -0,0 +1,8 @@
#!perl -T

use Test::More;
eval "use Test::Pod::Coverage 1.08";
plan skip_all => "Test::Pod::Coverage 1.08 required for testing POD coverage"
if $@;

all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::CountParents' });
6 changes: 6 additions & 0 deletions t/pod.t
@@ -0,0 +1,6 @@
use Test::More;

eval "use Test::Pod 1.00";
plan skip_all => "Test::Pod 1.00 required for testing POD" if $@;

all_pod_files_ok();

0 comments on commit 9fb6657

Please sign in to comment.