2012-12-03 1 views
11

Wir haben Perl::Critic hier bei der Arbeit verwendet, um unsere Code-Konventionen durchzusetzen. Vor kurzem traten Probleme mit /tmp Verzeichnis auf, das wegen der Temp::File::tempdir Funktion gefüllt wurde. tempdir räumt auf, wenn der Perl-Prozess beendet wird, aber da unser gesamtes Backend ein Perl-Prozess ist, tritt dies nur auf, wenn der Server selbst neu gestartet wird (nicht sehr oft). Wir möchten die Entwickler dazu ermutigen, in Zukunft die newdir Objektmethode zu verwenden, die nach sich selbst aufräumt, sobald das Objekt den Gültigkeitsbereich verlässt.Perl :: Kritiker "Verwenden Sie diese Methode nicht" Typ Regel

Grundsätzlich versuchen wir, Temp::File::tempdir als eine Verletzung der Code-Konvention zu markieren, aber ich kann keine Regel finden, die auf CPAN ähnlich wäre. Ich verstehe, dass dies in einer dynamisch typisierten Sprache schwer zu erzwingen ist, ohne falsche Positive einzuführen, aber ich würde erwarten, dass jemand in der Vergangenheit mit einer anderen veralteten Funktion auf ein ähnliches Problem gestoßen ist. Wir erwarten auch nicht, alle komplizierten Fälle zu erfassen, nur die offensichtlichsten Anwendungen von Temp::File::tempdir. Die Idee ist, die versehentliche Verwendung von tempdir zu verhindern, wenn newdir den Job machen könnte, nicht alle Versuche zu fangen, den Kritiker zu täuschen (Entwickler könnte immer einfach ## no critic verwenden). Es würde wahrscheinlich reichen, wenn tempdir verwendet wird, wenn use Temp::File definiert ist (vorzugsweise überprüft, dass nichts anderes tempdir neu definiert) und wenn Temp::File::tempdir verwendet wird.

Gibt es schon etwas ähnliches, oder sollte ich von vorne anfangen? Danke

+2

Curious. Es gibt konfigurierbare 'ProhibitEvilModules' und' ProhibitEvilVariables' Policies, aber keine 'ProhibitEvilMethods'? – mob

Antwort

9

Es gibt nichts in Perl::Critic zur Zeit zu bieten, was Sie brauchen, aber es ist durchaus möglich, eine Richtlinie hinzuzufügen, um so etwas zu tun. Leider ist PPI nicht umfassend genug, um die einzelnen Token im Programm richtig zu identifizieren, also braucht es mehr Code als möglich.

Dieses Programm prüft für eine use File::Temp Anweisung, die tempdir mit einem

use File::Temp 'tempdir'; 
use File::Temp q(tempdir); 
use File::Temp "tempdir"; 
use File::Temp qq(tempdir); 
use File::Temp qw/ tempdir /; 

(mit jedem Begrenzer für die q, qq und qw Formulare) zu importieren versucht. Es prüft auch auf einen PPI::Token::Word Knoten, der wie ein Funktionsaufruf aussieht und gleich File::Temp::tempdir ist.

package Perl::Critic::Policy::Prohibit_tempdir; 

use strict; 
use warnings; 

use Perl::Critic::Utils qw{ is_function_call :severities }; 
use Scalar::Util 'blessed'; 

use base 'Perl::Critic::Policy'; 

my $DESC = 'Temp::File::tempdir function'; 
my $EXPL = 'The tempdir function from Temp::File is deprecated. Use newdir method instead'; 

sub default_severity { $SEVERITY_HIGH }; 

sub applies_to{ qw/ PPI::Statement::Include PPI::Token::Word/} 

sub violates { 

    my ($self, $elem) = @_; 

    if ($elem->isa('PPI::Statement::Include')) { 

    return unless $elem->type eq 'use'; 

    my $module = $elem->module; 
    return unless $module and $module eq 'File::Temp'; 

    for my $kid ($elem->children) { 

     next unless blessed($kid) =~ /^PPI::Token::Quote/; 

     if ($kid->can('string') and $kid->string eq 'tempdir' 
      or $kid->can('literal') and grep $_ eq 'tempdir', $kid->literal) { 
     return $self->violation($DESC, $EXPL, $elem); 
     } 
    } 
    } 
    else { 
    if (is_function_call($elem) and $elem eq 'File::Temp::tempdir') { 
     return $self->violation($DESC, $EXPL, $elem); 
    } 
    } 

    return; 
} 

1; 

mit diesem Code

use strict; 
use warnings; 

use File::Temp 'tempdir'; 
use File::Temp "tempdir"; 
use File::Temp qw/ tempdir /; 

my $dir = tempdir(); 
$dir = tempdir; 
$dir = File::Temp::tempdir; 

my $ft = File::Temp->new; 
$dir = $ft->newdir; 

generiert diese Ausgabe von perlcritic -4 test.pl

Code not contained in explicit package at line 1, column 1. Violates encapsulation. (Severity: 4) 
Temp::File::tempdir function at line 4, column 1. The tempdir function from Temp::File is deprecated. Use newdir method instead. (Severity: 4) 
Temp::File::tempdir function at line 5, column 1. The tempdir function from Temp::File is deprecated. Use newdir method instead. (Severity: 4) 
Temp::File::tempdir function at line 6, column 1. The tempdir function from Temp::File is deprecated. Use newdir method instead. (Severity: 4) 
Temp::File::tempdir function at line 10, column 8. The tempdir function from Temp::File is deprecated. Use newdir method instead. (Severity: 4) 
Module does not end with "1;" at line 13, column 1. Must end with a recognizable true value. (Severity: 4) 
+0

Danke, das tut fast genau das, was wir brauchen, es fängt die Zeilen 8 und 9 noch nicht ein, aber ich werde es anpassen, um es zu tun, und es wahrscheinlich generischer machen, damit die Methoden pro Modul spezifiziert werden können, um es zu machen etwas generischer. –

+0

Ich habe den Ansatz verwendet, den Sie in Ihrer Frage beschrieben haben. Aufrufe wie die in den Zeilen 8 und 9 werden nur dann kompiliert, wenn es eine vorangehende Instanz der Zeilen 4, 5 oder 6 gibt. Das heißt, die Unterroutine muss importiert werden, bevor sie aufgerufen werden kann. Das Problem beim Identifizieren von Aufrufen zu "tempdir", die nicht vollständig mit dem Modulnamen qualifiziert sind, ist, dass "PPI" nicht sehr hilfreich bezüglich des Aussehens des Barewords ist. Der 'is_function_call' Klassifikator, der von' Perl :: Critic :: Utils' bereitgestellt wird, ist sehr vage und bedeutet einfach, dass das Bareword keine der anderen neun Möglichkeiten zu sein scheint, nach denen es sucht. – Borodin

Verwandte Themen