2010-09-07 3 views
12
open $FP, '>', $outfile or die $outfile." Cannot open file for writing\n"; 
  • У меня это заявление, много раз в моем коде.Запись макроса в Perl

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

  • В Perl, как я должен решить эту ситуацию?

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

Я видел это SO нить How can I use macros in Perl?, но ничего не говорит о том, как написать общий макрос как

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

ответ

25

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

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

Я бы сказал «не мог», а не «не может», потому что кто знает, что такое текущее состояние этого файла; мы знаем только то, что было у государства, когда мы пытались его открыть (отсюда и прошедшее время). Конечно, это бессмысленная тонкость. Вы могли бы так же легко сказать «Bang for $ filename: $!». –

+0

О, и 'corelist' говорит, что Perl 5.10.1 была первой версией с' autodie' в ядре и [delta] (http://perldoc.perl.org/perl5101delta.html#New-Modules-and-Pragmata) поддерживает это. –

+0

@Chas - отредактировано. @Sinan - +1 для «$!». Считываемые сообщения и сообщения об ошибках часто недооцениваются в разработке программного обеспечения. – DVK

11

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

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

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

Если вам нужно иметь C/CPP стиль препроцессора макросов, можно написать один в Perl (или, на самом деле, любой язык), используя PreCompile source filter. Вы можете написать довольно простые сложные классы 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 

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

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

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

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

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

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

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

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

Chas. У Owens есть method с помощью 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.

0

Для чего-то вроде 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; 

Имея открытый Params, указанный в конце немного странно, но это позволяет избежать необходимости указывать суб ключевым слова.

Смежные вопросы