Написание макроса на Perl - PullRequest
       10

Написание макроса на Perl

13 голосов
/ 07 сентября 2010
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";

Ответы [ 4 ]

25 голосов
/ 07 сентября 2010

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

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 находится в ядре, и я буду второй Час. Рекомендация Оуэнса использовать его.

10 голосов
/ 07 сентября 2010

В Perl 5 действительно нет макросов (есть исходные фильтры, но они опасны и уродливы, так что даже безобразно, я не буду связывать вас с документацией).Функция может быть правильным выбором, но вы обнаружите, что новым людям становится сложнее читать ваш код.Лучшим вариантом может быть использование прагмы autodie (это ядро ​​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.

7 голосов
/ 08 сентября 2010

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

Фильтры исходного кода

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

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

package myopinion;
# save in your Perl's @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 :: Simple должен работать нормально.Filter :: Simple может быть ограничен частями вашего кода для создания подстанций, такими как исполняемая часть, но не часть POD;только в строках;только в коде.

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

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

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

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

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

Считайте perldata , почему это так ...

Template Toolkit

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 очень активно разрабатывается и хорошо документируется.Если вы используете только макрос, который вы предлагаете, это может быть излишним.

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

Час.У Оуэнса есть метод с использованием Vim.Я использую BBEdit и могу легко написать текстовую фабрику, чтобы заменить скелет открытия на точное и развивающееся открытие, которое я хочу использовать.Кроме того, вы можете поместить шаблон завершения в папку «Ресурсы» в папке «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 one и регулярные выражения Perl для своего кода перед его компиляцией, используйте Filter :: Simple.

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

0 голосов
/ 21 сентября 2010

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

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 ключевое слово.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...