Perl:: Критика "Не использовать этот метод" - правило типа

Мы использовали Perl::Critic здесь, чтобы обеспечить соблюдение наших условных кодов. Недавно мы столкнулись с проблемами с заполнением каталога /tmp из-за функции Temp::File::tempdir. tempdir очищается, когда процесс Perl завершается, но поскольку весь наш сервер является процессом Perl, это происходит только тогда, когда сервер сам перезагружается (не очень часто). Мы хотим, чтобы разработчики в будущем использовали метод объекта newdir, который очищается после себя, как только объект выходит из области видимости.

В принципе, мы пытаемся пометить Temp::File::tempdir как нарушение правил кода, но я не могу найти никакого правила, которое было бы похоже на CPAN. Я понимаю, что это трудно обеспечить на динамически типизированном языке без введения ложных срабатываний, но я ожидаю, что кто-то столкнулся с аналогичной проблемой в прошлом с другой устаревшей функцией. Мы не ожидаем, что поймаем все сложные случаи, только самые очевидные применения Temp::File::tempdir. Идея состоит в том, чтобы препятствовать случайному использованию tempdir, когда newdir мог выполнять работу, а не улавливать все попытки обмануть критика (разработчик всегда мог просто использовать ## no critic). Вероятно, было бы достаточно, чтобы жаловаться, когда tempdir используется, если use Temp::File определен (предпочтительно, проверяя, что ничто иное не переопределяет tempdir), и когда используется Temp::File::tempdir.

Есть ли что-то подобное, или я должен начать с нуля? Благодаря

Ответ 1

В настоящее время ничего нет в Perl::Critic, чтобы обеспечить то, что вам нужно, но вполне возможно добавить политику, чтобы сделать что-то вроде этого. К сожалению, PPI недостаточно полно, чтобы правильно определить, что делает каждый токен в программе, поэтому требуется больше кодирования, чем это могло бы быть.

Эта программа проверяет оператор use File::Temp, который пытается импортировать tempdir, используя любой из

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

(с любым разделителем для форм q, qq и qw). Он также проверяет наличие PPI::Token::Word node, который выглядит как вызов функции и равен 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;

с этим кодом

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;

генерирует этот вывод из 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)