| Perl-Basics | Perl-Enhanced | ||
|---|---|---|---|
Tips und Tricks zu Perl
Hilfe zu Modulen unter Win32 finden
1. Im Perl/bin - Verzeichnis (häufig c:\perl\bin) liegt ein Script namens perldoc.bat. Wenn man das ausführt und als Parameter den Modulnamen übergibt, gibt es fast immer Hilfe zu diesem Modul aus.
z.B. perldoc File::DosGlob
gibt hilfe zum Modul File::DosGlob
2. Wer die Hilfe lieber im HTML-Format haben will, kann mal schauen, ob die HTML-Hilfe installiert ist. Wenn sie installiert ist, liegt sie fast immer im Verzeichnis c:\perl\html (ich nehme einfach mal an, daß Perl im Verzeichnis c:\perl installiert ist). Wenn man dort die Datei index.html mit einem Browser öffnet, findet eine sehr gute Hilfe zu Perl (z.B. die FAQs, die häufig gestellten Fragen, oder die Dokumentation zu sehr vielen Modulen).
Sollte das Modul, zu dem man Hilfe benötigt, dort nicht vorhanden sein, kann man im Dateisystem nachschauen, ob es eine HTML-Datei gibt. Wenn das Modul, zu dem man genaueres wissen will, File::myModule heisst, sucht man nach der Datei myModule.pm in einem Verzeichnis File, also z.B. c:\perl\html\site\lib\File\myModule.html oder c:\perl\html\lib\File\myModule.html. Falls sie dort nicht gefunden werden kann, muss man ein wenig weiter suchen. Am besten sucht man in den Unterverzeichnissen von c:\perl nach allen Dateien, die myModule.* heißen.
Sollte dabei eine Datei mit der Endung .pod (also myModule.pod) gefunden werden, verwendet man für die weiteren Schritte als Ausgangsdatei, sonst myModule.pm.
Man begebe sich in die Dos-Eingabeaufforderung in das Verzeichnis, in dem die Datei liegt. Dann gibt man ein:
pod2html myModule.pm > myModule.html (oder pod2html myModule.pod > myModule.html)
Jetzt muesste in aktuellen Verzeichnis eine Datei namens myModule.html entstanden sein, die eigentlich die Hilfe zu dem Modul myModule enthalten müßte.
Module laden
Manchmal hat man folgendes Problem: man schreibt ein größeres Perl-Programm, welches recht viele eigene Module benötigt. Man will/kann sie jedoch nicht im Standard-Perl-Lib-Verzeichnis ablegen, weil entweder die Rechte fehlen, oder weil die Module einfach beim Programm bleiben sollen. Damit die Module via 'use' oder 'require' eingebunden werden koennen, müssen sie irgendwie im Perl-Modulpfad eingetragen sein.
- Es gibt durch das Perl-Modul FindBin die Moeglichkeit, den Pfad des
ausgefuehrten Perl-Scriptes herauszufinden und ihn dann on the fly zu setzen
(vielleicht sogar in einem BEGIN-Block):
use FindBin; # stellt die Variable $FileFind::Bin zur Verfuegung use lib "$FindBin::Bin/../lib"; require ModulXY;
Die Variante zwei ist sehr flexibel, wenn der relative Pfad von Perl-Script zum Modul immer der gleiche ist.
- den Modul-Suchpfad @INC erweitern, über den Module gefunden werden
können:
my $dir = "c:/myapp/lib"; use lib ($dir); # besser als das alte: unshift (@INC, $dir); require ModulXY;
- man bringt das Verzeichnis in einer Systemvariable unter (z.B. in der Shell
SET LIBDIR=c:\myapp\lib eingeben) und erweitert dann @INC durch das, was in
dieser Systemvariable steht:
my $dir = $ENV{LIBDIR}; use lib ($dir); # besser als: unshift (@INC, $dir); require ModulXY;Diese Moeglichkeit hat unter anderem folgenden Nachteil, daß der Pfad absolut eingetragen sein muss. Bei relativen Pfadangaben muss sich das aktuelle Verzeichnis zusaetzlich immer im Scriptverzeichnis befinden. (chroot oder cd in Shell).
- Man kann die Environmentvariable PERL5LIB auf das eigene Modulverzeichnis setzen. Dann werden die Module auch über den Modulsuchpfad gefunden.
- perldoc FindBin
- perldoc lib
Autoload
Wenn man eine Sub ausführt, die es gar nicht gibt, wird das Programm mit einer Fehlermeldung wie "Undefined subroutine ..." beendet. Wenn man diesen Fehler abfangen will, kann man folgenden Code verwenden:
sub AUTOLOAD {
use vars qw($AUTOLOAD);
warn ("Sub $AUTOLOAD konnte nicht gefunden werden");
} # AUTOLOAD
Vorsicht dabei jedoch bei Klassen: AUTOLOAD möglichst nur in Basisklassen verwenden, nicht in abgeleiteten, weil bei übergeordneten Klassen ererbten Methoden dann nicht ausgeführt werden, sondern sofort AUTOLOAD, wenn im aktuellen PACKAGE keine Funktion dieses Namens existiert.
AUTOLOAD kann man recht gut dazu gebrauchen, um Schnittstellenmethoden zu Objektdaten zu implementieren. Auf Objektdaten (z.B. $self->{DATA} ) soll man ja nicht direkt zugreifen, weil dies gegen den Grundsatz der objektorientierten Programmierung verstößt, daß die Objektdaten nur via Methoden verändert werden dürfen.
Solche Methoden (ich nenne sie mal Objektinterface-Methoden) nehmen häufig folgende Namen an:
- setName, setValue, setNewName
- getName, getValue, getNewName
Da solche Objektinterface-Methoden häufig in Basisklassen implementiert werden, bietet sich deren automatische Implementierung via Autoload an.
Hier ein Beispiel, wie man das machen könnte:
#!perl -w use strict;
@main::allAllowedAttributes = qw(NAME INDEX); # Liste mit allen Objektattributen, # auf die via AUTOLOAD zugegriffen # werden darf. my $object = MyObject->new(); # erzeuge neues Objekt $object->setName("object20"); # setze $object->{NAME} auf "object20" print $object->getName(), "\n"; # print Name # das folgende Attribut "SETCOMPUTER" ist nicht gestattet $object->setComputer("strat"); # setze $object->{COMPUTER} auf "strat"
# ========================================
package MyObject;
# ----------------------------------------
sub new { # Konstruktor für ein neues Objekt
my ($proto) = shift;
my ($class) = ref($proto) || $proto;
my $self = {};
bless ($self, $class);
return $self;
} # new
# ----------------------------------------
sub AUTOLOAD { # wird ausgefuehrt, wenn eine Methode nicht gefunden wurde
my ($self, $parameter) = @_;
use vars qw($AUTOLOAD);
my $method = (split(/::/, $AUTOLOAD))[-1]; # ermittle Methodenname
my $package = ref $self; # ermittle Objektklasse
print ("...autoloading $method for package $package\n");
if ( $method =~ s/^set// ){
if( grep{ uc($method) eq uc($_) } @main::allAllowedAttributes ){
return $self->{ uc($method) } = $parameter;
}
else {
print ".....not allowed by allAllowedAttributes\n";
return;
}
}
if ( $method =~ s/^get// ){
if( grep{ uc($method) eq uc($_) } @main::allAllowedAttributes ){
return $self->{ uc($method) };
}
else {
print ".....not allowed by allAllowedAttributes\n";
return;
}
}
warn "ERROR: method $method not found\n";
} # AUTOLOAD
# ------------------------------------------------------------
DESTROY {
my ($self) = shift;
undef $self;
} # DESTROY
# ------------------------------------------------------------
Wenn eine Methode nicht gefunden werden kann, dann wird stattdessen die Methode
AUTOLOAD ausgeführt. Diese überprüft in unserem Fall, ob die
Methode, für die sie stellvertretend ausgeführt wird, mit set... oder
get... beginnt. Wenn nein, wird Fehlermeldung ausgegeben; wenn ja, dann wird
überprüft, ob der Name der Methode (ohne set... oder get...) in der
Liste der erlaubten Methoden ist (@main::allAllowedAttributes); wenn ja, wird
scheinbar diese Methode set... oder get... ausgeführt.
Beispiel 1:
Methodenname ist: setName
Das beginnt mit set und uc(Name) (= NAME) ist in @main::allAllowedAttributes,
also wird der erste Parameter $self->{NAME} zugewiesen.
Beispiel 2
Methodenname: setComputer
Das beginnt mit set, Computer ist jedoch nicht in der Liste @main::allAllowedAttributes.
Also wird ein Fehler ausgegeben.
So kann man sich eventuell einige Zeilen Quellcode sparen. Man sollte ein solches Vorgehen jedoch sorgfältig dokumentieren, weil es wohl etwas ungewöhnlich ist. Aus diesem Grund (und auch, weil bei einem Autoloading die Laufzeit leidet) kann ich nicht raten, Autoload zu verwenden. Es ist jedoch eine sehr mächtige und interessante Option.
Das Laufzeitproblem kann man unter Umständen verringern, wenn solche "Autogeloadeten" Funktionen oder Methoden sehr häufig aufgerufen werden. In diesem Fall könnte es Sinn machen, on the fly Funktionen oder Methoden zu erzeugen und diese in der Symboltabelle des laufenden Programmes verankern. Beim zweiten Aufruf einer auf diese Weise erzeugen Funktion oder Methode wird dann das eher langsame AUTOLOAD nicht mehr benötigt, z.B.
#! /usr/bin/perl
use warnings;
use strict;
my $test = Test->new();
$test->print("hello\n");
$test->print("hello2\n");
$test->print("hello3", "hello4\n");
# ============================================================
package Test;
# ------------------------------------------------------------
sub new { # any constructor
my $proto = shift;
my $class = ref($proto) || $proto;
my $parent = ref($proto) && $proto;
my $self = {}; # create a new object
return bless($self, $class);
} # new
# ------------------------------------------------------------
sub AUTOLOAD {
use vars qw($AUTOLOAD);
my ($self, @params) = @_;
my ($method) = (split(/::/, $AUTOLOAD))[-1];
print "AUTOLOAD: $AUTOLOAD\nSELF: $self\n";
print "METHOD: $method\nPARAMS: @params\n";
# create reference to sub
my $code = sub {
my ($self, @params) = @_;
print @params, "\n";
# weiterer code
# .....
};
$self->$code(@params); # execute for the first time or use
# goto &sub after the next block instead
# and add it to symbol table; besser das Modul Sub::Installer verwenden
no strict 'refs'; # use strict 'refs' kurz deaktivieren
*{$method} = $code; # Verankern in der Symboltabelle mit symbolischer Referenz
use strict 'refs'; # use strict 'refs' wieder aktivieren
# weiterer code ...
} # AUTOLOAD
# ------------------------------------------------------------
sub DESTROY { # don't autoload DESTROY :-)
# ...
} # DESTROY
# ------------------------------------------------------------
In den meisten Fällen ist es jedoch besser, die Subroutinen oder Methoden schon beim Programmstart vorzugenerieren (z.B. wenn das Modul geladen wird).
Module installieren
Siehe Perl.de-FAQ -> Module und zusätzlich http://perlmonks.thepen.com/147012.html
Wie erstelle ich ein CPAN-Modul
Siehe Wie erstelle ich ein CPAN konformes Modul?
Siehe auch Einführung in Perl
Letztes Update dieser Seite: Tuesday, 27-Jun-2006 20:37:00 CEST