1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
# Copyright 2008, 2009, 2010 Kevin Ryde
# Perl-Critic-Pulp is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3, or (at your option) any later
# version.
#
# Perl-Critic-Pulp is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with Perl-Critic-Pulp. If not, see <http://www.gnu.org/licenses/>.
package Perl::Critic::Policy::Compatibility::TestMoreLikeModifiers;
use strict;
use warnings;
use base 'Perl::Critic::Policy';
use Perl::Critic::Utils qw(:severities parse_arg_list);
use Perl::Critic::Utils::PPIRegexp qw(:all);
use version;
our $VERSION = 0;
use constant DEBUG => 0;
sub supported_parameters { return; }
sub default_severity { return $SEVERITY_MEDIUM; }
sub default_themes { return qw(pulp bugs); }
sub applies_to { return 'PPI::Token::Word'; }
my $perl_ok_version = version->new('5.10.0');
sub violates {
my ($self, $elem, $document) = @_;
my $word = $elem->content;
$word eq 'Test::More::like'
|| ($word eq 'like' && _document_uses_Test_More($document))
|| return;
if (DEBUG) { print "word $word\n"; }
if (my $version = $document->highest_explicit_perl_version) {
if ($version >= $perl_ok_version) {
return; # $document is demanding new enough perl
}
}
my @args_arefs = parse_arg_list ($elem);
my @re_elems = @{$args_arefs[1]};
@re_elems = grep {$_->significant} @re_elems;
@re_elems == 1 || return;
my $re_elem = $re_elems[0];
if (DEBUG) { print "re_elem ",ref($re_elem),": $re_elem\n"; }
my ($subdoc, $ext_elem) = _string_elem_to_regexp ($re_elem);
$ext_elem->isa('PPI::Token::QuoteLike::Regexp')
|| $ext_elem->isa('PPI::Token::Regexp')
|| return; # not a regexp (maybe a variable containing a regexp ...)
my $mhash = $ext_elem->{'modifiers'}
|| return; # no modifiers
if (DEBUG) {
require Data::Dumper;
print "mhash ",Data::Dumper::Dumper($mhash),"\n";
}
my %modifiers = %$mhash; # copy;
delete $modifiers{'x'}; # /x is ok
if (%modifiers) { return; } # no other modifiers is good
my $modifiers = join ('', sort keys %modifiers);
return $self->violation
("Modifiers /$modifiers don't work with like() until Perl $perl_ok_version",
'',
$re_elem);
}
sub _string_elem_to_regexp {
my ($elem) = @_;
if ($elem->isa('PPI::Token::Quote')) {
# literal() from Single, string() from Double
# the latter is only really an approximation, but is often good enough
my $str = ($elem->can('literal')
? $elem->literal : $elem->string);
if (DEBUG) { print "sub-parse: $str\n"; }
# Eg. parses to
# PPI::Document
# PPI::Statement
# PPI::Token::Regexp::Match '/pattern/i'
#
if (my $subdoc = PPI::Document->new (\$str)) {
my $subelem = $subdoc->schild(0);
if ($subelem && $subelem->isa('PPI::Statement')) {
$subelem = $subelem->schild(0);
if ($subelem->isa('PPI::Token::Regexp::Match')) {
if (DEBUG) { print " got: ",ref($subelem),": $subelem\n"; }
return ($subdoc, $subelem);
}
}
}
}
# otherwise given elem
return (undef, $elem);
}
sub _document_uses_Test_More {
my ($document) = @_;
my $key = __PACKAGE__ . '--using-Test::More';
if (exists $document->{$key}) { return $document->{$key}; }
my $ret = $document->find_any
(sub {
my ($document, $elem) = @_;
return ($elem->isa ('PPI::Statement::Include')
&& $elem ne 'no'
&& (($elem->module || '') eq 'Test::More'));
});
if (DEBUG) { print "using Test::More -- ", ($ret?"yes":"no"), "\n"; }
return ($document->{$key} = $ret);
}
1;
__END__
=head1 NAME
Perl::Critic::Policy::Compatibility::TestMoreLikeModifiers - don't use regexp modifiers with like() tests
=head1 DESCRIPTION
This policy is part of the Perl::Critic::Pulp addon. It warns about regexp
modifiers like C</i> and C</m> passed to C<like> tests with C<Test::More>,
because such modifiers don't end up propagated to the test until Perl 5.10.
For example,
use Test::More tests => 1;
like ('My String', qr/str/i); # bad
like ("abc\ndef\n", '/^abc$/m'); # bad
If you've got an explicit C<use 5.010> or similar then you'll only be
running and this check is not applied.
As always if you don't care about C<__END__> you can always disable
C<TestMoreLikeModifiers> from your F<.perlcriticrc> in the usual way,
[-Compatibility::TestMoreLikeModifiers]
=head1 SEE ALSO
L<Perl::Critic::Pulp>, L<Perl::Critic>
=head1 HOME PAGE
L<http://user42.tuxfamily.org/perl-critic-pulp/index.html>
=head1 COPYRIGHT
Copyright 2008, 2009, 2010 Kevin Ryde
Perl-Critic-Pulp is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
Perl-Critic-Pulp is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along with
Perl-Critic-Pulp. If not, see L<http://www.gnu.org/licenses>.
=cut
|