2012-12-03 5 views
11

Abbiamo utilizzato Perl::Critic qui al lavoro per applicare le convenzioni del codice. Recentemente ci siamo imbattuti in problemi con la directory /tmp riempirsi a causa della funzione Temp::File::tempdir. tempdir pulisce quando termina il processo Perl, ma poiché l'intero backend è un processo Perl, questo si verifica solo quando il server stesso viene riavviato (non molto spesso). Vogliamo incoraggiare gli sviluppatori a utilizzare il metodo degli oggetti newdir in futuro, che si ripulisce da solo non appena l'oggetto esce dall'ambito.Perl :: Critico "Non utilizzare questo metodo" - tipo di regola

Fondamentalmente, stiamo cercando di contrassegnare Temp::File::tempdir come violazione della convenzione di codice, ma non riesco a trovare alcuna regola che sarebbe simile su CPAN. Capisco che questo sia difficile da applicare in un linguaggio tipizzato dinamicamente senza introdurre falsi positivi, ma mi aspetterei che qualcuno si sia imbattuto in problemi simili in passato con un'altra funzione deprecata. Non ci aspettiamo di prendere tutti i casi complicati, solo gli usi più ovvi di Temp::File::tempdir. L'idea è di scoraggiare l'uso accidentale di tempdir quando newdir potrebbe fare il lavoro, non per cogliere tutti i tentativi di ingannare il critico (lo sviluppatore potrebbe sempre usare solo ## no critic). Probabilmente sarebbe sufficiente lamentarsi quando si utilizza tempdir se è stato definito use Temp::File (preferibilmente controllando che nient'altro ridefinisce tempdir) e quando viene utilizzato Temp::File::tempdir.

C'è già qualcosa di simile o dovrei ricominciare da capo? Grazie

+2

curioso. Sono disponibili le politiche configurabili 'ProhibitEvilModules' e' ProhibitEvilVariables', ma non 'ProhibitEvilMethods'? – mob

risposta

9

Al momento non c'è nulla in Perl::Critic per fornire quello che ti serve, ma è abbastanza possibile aggiungere una politica per fare qualcosa di simile. Sfortunatamente lo PPI non è abbastanza completo per identificare correttamente cosa fa ogni token nel programma, quindi richiede più codice di quanto potrebbe.

Questo programma verifica la presenza di una dichiarazione use File::Temp che cerca di importare tempdir utilizzando uno qualsiasi dei

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

(con qualsiasi delimitatore per le q, qq, e qw forme). Verifica inoltre la presenza di un nodo PPI::Token::Word simile a una chiamata di funzione ed è uguale a File::Temp::tempdir.

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; 

con questo codice

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; 

genera questo output 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

Grazie, questo fa quasi esattamente ciò di cui abbiamo bisogno, non cattura ancora le linee 8 e 9, ma lo aggiusterò per farlo, e probabilmente lo renderò più generico, così i metodi possono essere specificati per modulo per renderlo un un po 'più generico. –

+0

Ho usato l'approccio che hai descritto nella tua domanda. Chiamate come quelle delle righe 8 e 9 verranno compilate solo se esiste un'istanza precedente delle righe 4, 5 o 6. vale a dire che la subroutine deve essere importata prima di poter essere richiamata. Il problema con l'identificazione delle chiamate a 'tempdir' che non sono pienamente qualificate con il nome del modulo è che' PPI' non è molto utile per il contesto dell'aspetto della bareword. Il classificatore 'is_function_call' fornito da' Perl :: Critic :: Utils' è molto vago, e significa semplicemente che la parola chiave non sembra essere una delle altre nove possibilità che controlla. – Borodin

Problemi correlati