Software-Engineering Martin Fabiani

Sitemap (Navigation ohne JavaScript)

Impressum: Martin Fabiani, Röderbergweg 104, D-60485 Frankfurt, Tel: +49 (69) 49084808, E-Mail: info (at) fabiani.net, USt-IdNr: DE217298609

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.

  1. 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.

  2. 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;
    
  3. 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).

  4. Man kann die Environmentvariable PERL5LIB auf das eigene Modulverzeichnis setzen. Dann werden die Module auch über den Modulsuchpfad gefunden.
Weitere Informationen:
  1. perldoc FindBin
  2. 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:

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