Как мне правильно переопределить слово open в Perl?

Некоторое время назад я задаю вопрос: Как мне переопределить встроенное в Perl функции?

И ответы сослужили мне хорошую службу. У меня есть пакет, который переопределяет функцию Perl «open», позволяющую мне регистрировать доступ к файлам.

Теперь я подошел к делу, которое нарушает функциональность исходного кода.

use strict;
use warnings;
use Data::Dumper;

sub myopen (*;@) {
  my $p;
  my $retval = CORE::open($p, $_[1]);
  {
    no strict;
    *{"main::$_[0]"} = $p;
  }
  return $retval;
}

BEGIN {
  *CORE::GLOBAL::open = *myopen;
};

my @a = (1, 2, 3);

open(CHECK, ">dump") or print "UNABLE TO OPEN DUMPER FILE: $!\n";
print CHECK "test\n";
print CHECK Data::Dumper->Dump(\@a);
close CHECK

Теперь я получаю это сообщение:

Can't locate object method "CHECK" via package "Data::Dumper"

Как мне это исправить?


person mmccoo    schedule 02.05.2009    source источник
comment
Если это полная ошибка, он использует синтаксис косвенного объекта для неправильного объекта. Попробуйте ПРОВЕРИТЬ ›печать (...) и посмотрите, появится ли у вас та же ошибка.   -  person Anonymous    schedule 02.05.2009


Ответы (3)


Попробуйте использовать другое имя, кроме "ПРОВЕРИТЬ".

«ПРОВЕРКА» - это специальная функция, которая вызывается во время компиляции, и вам действительно не следует ее использовать.

$ open CHECK , '<', 'foo.txt'; 
Took 0.00224494934082031 seconds.

Runtime error: Undefined subroutine &Devel::REPL::Plugin::Packages::DefaultScratchpad::CHECK called at (eval 329) line 5.

$ open CHECKS , '<', 'foo.txt'; 
Took 0.00155806541442871 seconds.

$

Почему именно эта ошибка?

perl -MO=Deparse -e 'print CHECK Data::Dumper 1';
print 'Data::Dumper'->CHECK(1);

Кроме того, вы используете глобальные дескрипторы файлов, что проблематично.

используйте это обозначение:

open my $fh, '<' , $foo ; 
print <$fh>;
close $fh;

Они особенно полезны, так как они самозакрываются, когда выходят за пределы области видимости.

person Kent Fredric    schedule 02.05.2009
comment
+1, хороший анализ проблемы, и вы предложили правильное решение (более разумный синтаксис open () с 3 аргументами, с дескриптором файла в лексической переменной). И Я НЕНАВИЖУ PERL ЗА ТАКОЕ. - person j_random_hacker; 02.05.2009
comment
@j_random_hacker: Использование PerlCritic вернет вам любовь к Perl ;-) - person draegtun; 03.05.2009
comment
@draegtun: Perl :: Critic выглядит интересно (хотя я боюсь, что он скажет о моей большой кодовой базе старого, старого кода ... :)) - person j_random_hacker; 05.05.2009

Сравнивать:

> perl -MData::Dumper -e'local*_=*STDOUT;print _ Data::Dumper->Dump([2]);'
Can't locate object method "_" via package "Data::Dumper" at -e line 1.

to

> perl -MData::Dumper -e'local*_=*STDOUT;print _ ( Data::Dumper->Dump([2]) );'
$VAR1 = 2;

Я использовал имя, отличное от «STDOUT», потому что оно, кажется, неправильно понимает только косвенный объект, если он не является встроенным дескриптором.

person Anonymous    schedule 02.05.2009

Это будет работать и без ошибок ...

 print {*CHECK} Data::Dumper->Dump(\@a);

Это предотвращает путаницу, имеет "косвенный синтаксис объекта"

Однако я рекомендую избегать использования CHECK и других специальные именованные блоки кода в Perl и использование лексических переменных для дескрипторов файлов является предпочтительным методом. PBP

person draegtun    schedule 02.05.2009