2010-09-07 14 views
12
open $FP, '>', $outfile or die $outfile." Cannot open file for writing\n"; 
  • Mam To stwierdzenie wiele razy w moim kodzie.Pisanie makro w Perlu

  • Chcę zachować ten sam format dla wszystkich tych stwierdzeń, aby po zmianie czegoś zmienić tylko w jednym miejscu.

  • W Perlu, jak mam rozwiązać tę sytuację?

  • Czy powinienem używać makr lub funkcji?

Widziałem to SO wątku How can I use macros in Perl?, ale to nie mówi wiele o tym, jak napisać ogólny makro jak

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

Odpowiedz

25

Po pierwsze, należy napisać, że jako:

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

tym dlaczego open powiodło się.

Jeśli chcesz hermetyzacji, że można napisać:

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); 

Począwszy Perl 5.10.1, autodie jest w rdzeniu i będę drugi Chas. Polecenie Owensa, aby z niego skorzystać.

+2

Powiedziałbym "nie mógł" zamiast "nie może", ponieważ kto wie, jaki jest obecny stan tego pliku; wiemy tylko, czym był stan, kiedy próbowaliśmy go otworzyć (stąd czas przeszły). Oczywiście, to nic nie znacząca. Można równie dobrze powiedzieć "Bang dla $ filename: $!". –

+0

Aha, i 'corelist' mówi, że Perl 5.10.1 był pierwszą wersją z' autodie' w jądrze i [delta] (http://perldoc.perl.org/perl5101delta.html#New-Mule- i -Pragmata) cofa to. –

+0

@Chas - edytowane. @Sinan - +1 dla "$!". Czytelne i przydatne komunikaty o błędach są często niedocenianą sztuką w tworzeniu oprogramowania. – DVK

11

Perl 5 naprawdę nie ma makr (istnieją filtry źródłowe , ale są niebezpieczne i brzydkie, tak brzydkie, że nawet nie będę cię łączył z dokumentacją). Funkcja może być właściwym wyborem, ale przekonasz się, że utrudnia ona nowym czytelnikom odczytanie kodu. Lepszym rozwiązaniem może być użycie pragma autodie (jest to rdzeń Perla 5.10.1) i po prostu wyciąć część or die.

Inną opcją, jeśli używasz Vim, jest użycie snipMate. Wystarczy wpisać fw<tab>FP<tab>outfile<tab> i produkuje

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

Tekst snipMate jest

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

    ${3} 

Wierzę inni redaktorzy mają podobne możliwości, ale jestem użytkownikiem Vim.

7

Istnieje kilka sposobów na obejście czegoś podobnego do makra C w Perlu: filtr źródłowy, podprogram, Szablon :: Zestaw narzędzi lub funkcje użytkowe w edytorze tekstu.

Źródło Filtry

Jeśli musisz mieć C/CPP styl preprocesora makro, możliwe jest, aby napisać w Perl (lub, właściwie każdy język) przy użyciu precompile source filter. Możesz napisać dość proste do złożonych klas Perla, które działają na tekście kodu źródłowego i wykonać na nim transformacje, zanim kod przejdzie do kompilatora Perla. Możesz nawet uruchomić kod Perl bezpośrednio przez preprocessor CPP, aby uzyskać dokładny typ rozszerzenia makr, które uzyskujesz w C/CPP przy użyciu Filter::CPP.

Damian Conway's Filter::Simple jest częścią dystrybucji rdzeniowej Perla.Dzięki Filter :: Simple możesz łatwo napisać prosty moduł, aby wykonać opisywane makro. Przykład:

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; 

Następnie plik Perl:

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

wyjściowa:

Pigs Pigs Hogs Pigs 
In my opinion, Pigs are Pigs 

Jeśli przepisał filtr w celu dokonania zmiany na żądaną makro, Filter :: Proste powinien działać dobrze. Filtr :: Simple może być ograniczony do części kodu, aby utworzyć podstacje, takie jak część wykonywalna, ale nie część POD; tylko w strunach; tylko w kodzie.

Filtry źródłowe nie są szeroko używane w moim doświadczeniu. Najczęściej widziałem ich z lame próby szyfrowania kodu źródłowego Perla lub humorystyczny Perl obfuscators. Innymi słowy, wiem, że można to zrobić w ten sposób, ale ja osobiście nie wiem wystarczająco dużo o nich, aby ich polecić lub powiedzieć, że ich nie używam.

Podprogramy

Sinan Ünür openex subroutine jest dobrym sposobem, aby tego dokonać. Dodam tylko, że wspólna starsze idiom, który będzie można zobaczyć polega na przepuszczeniu odniesienie do typeglob tak:

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

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

Read perldata dlaczego to w ten sposób ...

Template Toolkit

Template::Toolkit może być użyty do przetworzenia kodu źródłowego Perla. Na przykład, można napisać szablon wzdłuż linii:

[% fw(fp, outfile) %] 

systemem, który poprzez Template :: Toolkit może doprowadzić do ekspansji i substytucji:

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

Template :: Toolkit jest najczęściej używany oddzielić bałagan HTML i inny kod prezentacji od kodu aplikacji w aplikacjach internetowych. Szablon :: Toolkit jest bardzo aktywnie rozwijany i dobrze udokumentowany. Jeśli Twoim jedynym zastosowaniem jest makro sugerowanego typu, może to być przesada.

dzwonków

Chas. Owens ma method używając Vima. Używam BBEdit i mogłem z łatwością napisać Text Factory, aby zastąpić szkielet otwartego, precyzyjnie i ewoluująco otwarty, który chcę użyć. Alternatywnie możesz umieścić szablon ukończenia w katalogu "Zasoby" w folderze "Perl". Te szkielety ukończenia są używane po naciśnięciu zdefiniowanej serii kluczy. Prawie każdy poważny edytor będzie miał podobną funkcjonalność.

Z BBEdit można nawet używać kodu Perla w logice zastępowania tekstu. Używam w ten sposób Perl::Critic. Możesz użyć Template::Toolkit wewnątrz BBEdit, aby przetworzyć makra z pewną inteligencją. Można go ustawić, aby kod źródłowy nie został zmieniony przez szablon, dopóki nie wypiszesz wersji do testowania lub kompilacji; edytor zasadniczo działa jako preprocesor.

Dwa potencjalne problemy z używaniem edytora tekstu. Po pierwsze jest to transformacja jednokierunkowa/jednorazowa.Jeśli chcesz zmienić to, co robi twoje "makro", nie możesz tego zrobić, ponieważ poprzedni tekst "makro" był już użyty. Musisz ręcznie je zmienić. Drugi potencjalny problem polega na tym, że jeśli używasz formularza szablonu, nie możesz wysłać makro wersji kodu źródłowego do kogoś innego, ponieważ wstępne przetwarzanie odbywa się w edytorze.

Nie rób tego!

Jeśli wpiszesz perl -h dostać przełączniki ważne poleceniu jedna opcja może pojawić się:

-P    run program through C preprocessor before compilation 

Kuszące! Tak, możesz uruchomić kod Perl za pomocą preprocesora C i rozwinąć makra w stylu C i mieć #defines. Odłóż ten pistolet; odchodzić; nie rób tego. Istnieje wiele niezgodności platform i niezgodności językowych.

Masz problemy tak:

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

Wydruki:

BIG 
small 

W Perl 5.12 przełącznik -P został usunięty ...

Wnioski

The najbardziej elastyczne rozwiązanie tutaj jest po prostu napisanie podprogramu. Cały twój kod jest widoczny w podprogramie, łatwo się zmienia i ma krótsze połączenie. Nie ma prawdziwych minusów innych niż potencjalna czytelność twojego kodu.

Szablon :: Toolkit jest szeroko stosowany. Możesz pisać złożone zamienniki, które działają jak makra lub nawet bardziej złożone niż makra C. Jeśli Twoja potrzeba makr jest warta krzywej uczenia się, skorzystaj z Template :: Toolkit.

W bardzo prostych przypadkach można użyć transformacji w jedną stronę w edytorze.

Jeśli naprawdę potrzebujesz makr w stylu C, możesz użyć Filter::CPP. Może to mieć tę samą niezgodność co przełącznik perl -P. Nie mogę tego polecić; po prostu poznaj sposób Perla.

Jeśli chcesz uruchomić Perl, jeden linijek i wyrażeń regularnych Perla, przed kompilacją, użyj opcji Filtr: Prosty.

I nie używaj przełącznika -P. W każdym razie nie możesz używać nowszych wersji Perla.

0

Jeśli chodzi o coś podobnego, to myślę, że warto uwzględnić je w swoim rutynowym schemacie. Oto podejście, które wygląda nieco dziwnie, ale zawiera typowy idiom typu "otwórz/zamknij".

 
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; 

Mając otwarte params podanych na końcu jest nieco dziwny, ale pozwala uniknąć konieczności określić sub słowa kluczowego.