Подтвердить что ты не робот

Запись макроса в Perl

open $FP, '>', $outfile or die $outfile." Cannot open file for writing\n";
  • У меня в этом коде много раз.

  • Я хочу, чтобы формат был одинаковым для всех этих утверждений, так что, когда что-то изменилось, оно изменяется только в одном месте.

  • В Perl, как мне решить эту ситуацию?

  • Должен ли я использовать макросы или функции?

Я видел этот SO-поток Как использовать макросы в Perl?, но он не говорит о том, как написать общий макрос, например

#define fw(FP, outfile) open $FP, '>', \
        $outfile or die $outfile." Cannot open file for writing\n";
4b9b3361

Ответ 1

Во-первых, вы должны написать это как:

open my $FP, '>', $outfile or die "Could not open '$outfile' for writing:$!";

включая причину неудачи open.

Если вы хотите инкапсулировать это, вы можете написать:

use Carp;

sub openex {
    my ($mode, $filename) = @_; 
    open my $h, $mode, $filename
        or croak "Could not open '$filename': $!";
    return $h;
}

# later

my $FP = openex('>', $outfile);

Начиная с Perl 5.10.1, autodie находится в ядре, и я буду второй Час. Owens рекомендует использовать его.

Ответ 2

Perl 5 действительно не имеет макросов (есть фильтры источников, но они опасны и уродливы, поэтому уродливые даже я не буду связывать вас с документацией). Функция может быть правильным выбором, но вы обнаружите, что это затрудняет чтение новых людей. Лучшим вариантом может быть использование autodie pragma (это ядро ​​с Perl 5.10.1) и просто вырезать or die часть.

Другой вариант, если вы используете Vim, следует использовать snipMate. Вы просто набираете fw<tab>FP<tab>outfile<tab> и генерируете

open my $FP, '>', $outfile
    or die "Couldn't open $outfile for writing: $!\n";

Текст snipMate

snippet fw
    open my $${1:filehandle}, ">", $${2:filename variable}
        or die "Couldn't open $$2 for writing: $!\n";

    ${3}

Я считаю, что другие редакторы имеют схожие возможности, но я пользователь Vim.

Ответ 3

Существует несколько способов обработки чего-то, подобного макросу C в Perl: исходный фильтр, подпрограмма, Template:: Toolkit или использование функций в вашем текстовом редакторе.

Фильтры источника

Если у вас есть макрос препроцессора стиля C/CPP, можно записать его на Perl (или, фактически, на любом языке), используя прекомпиляцию исходный фильтр. Вы можете написать довольно простые сложные классы Perl, которые работают с текстом исходного кода и выполняют преобразования на нем до того, как код перейдет к компилятору Perl. Вы даже можете запустить свой Perl-код непосредственно через препроцессор CPP, чтобы получить точный тип расширений макросов, которые вы получаете в C/CPP, используя Filter:: CPP.

Дамиан Конвей Фильтр:: Простой является частью дистрибутива ядра Perl. С Filter:: Simple вы можете легко написать простой модуль для выполнения макроса, который вы описываете. Пример:

package myopinion;
# save in your Perl @INC path as "myopinion.pm"...
use Filter::Simple;
FILTER { 
    s/Hogs/Pigs/g; 
    s/Hawgs/Hogs/g;
    }
1; 

Затем файл Perl:

use myopinion;
print join(' ',"Hogs", 'Hogs', qq/Hawgs/, q/Hogs/, "\n");
print "In my opinion, Hogs are Hogs\n\n";

Вывод:

Pigs Pigs Hogs Pigs 
In my opinion, Pigs are Pigs

Если вы переписали FILTER, чтобы сделать замену для нужного вам макроса, Filter:: Simple должен работать нормально. Фильтр:: Простой может быть ограничен частями вашего кода для подстанций, таких как исполняемая часть, но не часть POD; только в строках; только в коде.

Исходные фильтры в моем опыте широко не используются. Я в основном видел их с хромыми попытками зашифровать исходный код Perl или юмористический Perl obfuscators. Другими словами, я знаю, что это можно сделать таким образом, но я лично не знаю достаточно о них, чтобы рекомендовать их или сказать, что не использовать их.

Подпрограммы

Sinan Ünür подпрограмма openex - это хороший способ сделать это. Я только добавлю, что общая устаревшая идиома, которую вы увидите, включает передачу ссылки на типglob следующим образом:

sub opensesame {
   my $fn=shift;
   local *FH;
   return open(FH,$fn) ? *FH : undef;
}

$fh=opensesame('> /tmp/file');

Прочитайте perldata, почему именно так...

Инструментарий шаблонов

Template:: Toolkit можно использовать для обработки исходного кода Perl. Например, вы можете написать шаблон по строкам:

[% fw(fp, outfile) %] 

выполняемый через Template:: Toolkit, может привести к расширению и замене на:

open my $FP, '>', $outfile or die "$outfile could not be opened for writing:$!"; 

Template:: Toolkit чаще всего используется для ветки беспорядочного HTML и другого кода презентации от кода приложения в веб-приложениях. Template:: Toolkit очень активно развивается и хорошо документируется. Если ваше единственное использование - это макрос типа, который вы предлагаете, это может быть излишним.

Текстовые редакторы

Чес. Owens использует метод с помощью Vim. Я использую BBEdit и могу легко написать Text Factory, чтобы заменить скелет открытого с точным и развивающимся открытым, который я хочу использовать. В качестве альтернативы вы можете поместить шаблон завершения в свой каталог "Ресурсы" в папке "Perl". Эти скелеты завершения используются, когда вы нажимаете серию ключей, которые вы определяете. Почти любой серьезный редактор будет иметь аналогичную функциональность.

С BBEdit вы даже можете использовать код Perl в логике замены текста. Я использую Perl:: Critic таким образом. Вы можете использовать Template::Toolkit внутри BBEdit для обработки макросов с помощью некоторого интеллекта. Его можно настроить таким образом, чтобы исходный код не изменялся шаблоном, пока вы не выведете версию для проверки или компиляции; редактор, по сути, выступает в качестве препроцессора.

Две потенциальные проблемы с использованием текстового редактора. Во-первых, это одностороннее/однократное преобразование. Если вы хотите изменить то, что делает ваш "макрос", вы не можете этого сделать, поскольку предыдущий текст "макрос" уже использовался. Вы должны вручную изменить их. Вторая потенциальная проблема заключается в том, что если вы используете форму шаблона, вы не можете отправить макрокоманду исходного кода кому-то другому, поскольку предварительная обработка выполняется внутри редактора.

Не делай этого!

Если вы введете perl -h, чтобы получить допустимые командные переключатели, выберите один из следующих вариантов:

-P                run program through C preprocessor before compilation

Заманчиво! Да, вы можете запустить свой Perl-код через препроцессор C и развернуть макросы стиля C и иметь #defines. Положите это оружие; уходи; не делай этого. Существует много несовместимости с платформой и языковая несовместимость.

У вас возникают такие проблемы:

#!/usr/bin/perl -P
#define BIG small
print "BIG\n";
print qq(BIG\n);

Отпечатки:

BIG
small

В Perl 5.12 переключатель -P удален...

Заключение

Самое гибкое решение здесь - это просто написать подпрограмму. Весь ваш код отображается в подпрограмме, легко изменяется и короче. Никакой реальный недостаток, отличный от читаемости вашего кода, возможно.

Template:: Toolkit широко используется. Вы можете написать сложные замены, которые действуют как макросы или даже более сложные, чем макросы C. Если ваша потребность в макросах стоит кривая обучения, используйте Template:: Toolkit.

Для очень простых случаев используйте односторонние преобразования в редакторе.

Если вам действительно нужны макросы стиля C, вы можете использовать Filter:: CPP. Это может иметь ту же несовместимость, что и переключатель perl -P. Я не могу рекомендовать это; просто изучите способ Perl.

Если вы хотите запустить Perl один лайнер и регулярные выражения Perl против вашего кода перед компиляцией, используйте Filter:: Simple.

И не используйте переключатель -P. В любом случае вы не можете использовать новые версии Perl.

Ответ 4

Для чего-то вроде open я считаю полезным включить закрытие в вашей факторизованной рутине. Здесь подход, который выглядит немного странным, но инкапсулирует типичную открытую/закрытую идиому.

sub with_file_do(&$$) {
  my ($code, $mode, $file) = @_;
  open my $fp, '>', $file or die "Could not open '$file' for writing:$!";
  local $FP = $fp;
  $code->(); # perhaps wrap in an eval
  close $fp;
}

# usage
with_file_do {
  print $FP "whatever\n";
  # other output things with $FP
} '>', $outfile;

Наличие открытых параметров, указанных в конце, немного немного, но это позволяет вам не указывать ключевое слово sub.