Chrisi: Perl eigene Module (use,require)

Hi zusammen,

ich habe mir ein kleines Perlscript gebaut, dass ich jetzt gern in Teilbereiche zerlegen möchte. Dazu habe ich mir die Funktionen use & require angeschaut, kriege es aber nicht hin die Variablen vom Hauptscript in das Modul zu exportieren.

Mein Hauptscript:

#!/usr/bin/perl -w

use myclient;

%CNF( ... );
%BIN( ... );

myclient->myFunc();

Mein Modul:

#!/usr/bin/perl -w

package myclient;
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(%CNF %BIN);

sub myfunc {
   print %CNF;
   print %BIN;
}

1;

Ich möchte damit eigentlich nur die Funktionen die ich vorher in der Hauptdatei hatte in eine externe Datei auslagern. In dem Modul sollen dann die beiden HASHES CNF,BIN verfügbar sein.

Kann mir jemand sagen wie ich es hinbeommen kann?

Wenn ich schon beim Fragen bin, @INC enthält ja die Pfade für die Module. Kann ich an diese Variable einfach manuell Änderungen vornehmen? Ich möchte meine Module gern relative zum Script (Hauptprogram) ablegen dazu muss ich aktuell allerdings im Verzeichnis sein wo das Script liegt, was ich irgendwie blöd finde. Oder kann man den Scriptpfad auslesen, dann könnte ich diesen dynamisch @INC mitgeben?

Danke mal wieder und Viele Grüße
Chrisi

  1. ich habe mir ein kleines Perlscript gebaut, dass ich jetzt gern in Teilbereiche zerlegen möchte. Dazu habe ich mir die Funktionen use & require angeschaut, kriege es aber nicht hin die Variablen vom Hauptscript in das Modul zu exportieren.

    Das geht zwar, aber du solltest dir aber überlegen ob du das wirklich machen willst, wenn du viele Module hast die etwas exportieren kann es schnell passieren das du den gleichen Namen für Variabeln oder Funktionen verwendest. Besser sind Zugriffsmethoden im Modul.

    Mein Hauptscript:

    #!/usr/bin/perl -w

    use myclient;

    Du solltest auf jeden Fall use strict verwenden, es erleichtert dir die Arbeit und vor allem die Fehlersuche bzw. Vermeidung.

    Mein Modul:

    #!/usr/bin/perl -w

    das ist in einem Modul überflüssig.

    package myclient;
    require Exporter;
    @ISA = qw(Exporter);
    @EXPORT = qw(%CNF %BIN);

    Das ist eigentlich ok, aber wie gesagt use strict wäre besser. Dann musst du %NCF und %BIN mit our deklarieren.

    Wenn ich schon beim Fragen bin, @INC enthält ja die Pfade für die Module. Kann ich an diese Variable einfach manuell Änderungen vornehmen? Ich möchte meine Module gern relative zum Script (Hauptprogram) ablegen dazu muss ich aktuell allerdings im Verzeichnis sein wo das Script liegt, was ich irgendwie blöd finde. Oder kann man den Scriptpfad auslesen, dann könnte ich diesen dynamisch @INC mitgeben?

    Du suchst use lib

    Struppi.

    1. Hallo Struppi!

      @EXPORT = qw(%CNF %BIN);

      Das ist eigentlich ok, aber wie gesagt use strict wäre besser. Dann musst du %NCF und %BIN mit our deklarieren.

      Was ich aber nicht verstehe, ist dass Chrisi die beiden Hashs im Hauptskript deklariert. Warum sollen sie dann vom Modul exportiert werden?

      require Exporter;
      @ISA = qw(Exporter);

      Ist hier:

      use base qw(Exporter);

      nicht besser?

      Viele Grüße aus Frankfurt/Main,
      Patrick

      --

      _ - jenseits vom delirium - _
      [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
      Nichts ist unmöglich? Doch!
      Heute schon gegökt?
  2. wenn du exportierst, musst du im Script auch importieren:

    use myclient qw(...);

    1. Hallo Kuno!

      wenn du exportierst, musst du im Script auch importieren:

      use myclient qw(...);

      Nein. Beachte den Unterschied zw. EXPORT und EXPORT_OK.

      Viele Grüße aus Frankfurt/Main,
      Patrick

      --

      _ - jenseits vom delirium - _
      [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
      Nichts ist unmöglich? Doch!
      Heute schon gegökt?
    2. Hi,

      wenn du exportierst, musst du im Script auch importieren:

      Ich bin verwirrt :) Ich möchte eigentlich nur 2 Werte an das Modul übergeben, weil ich diese im Modul für die Sub Routinen benötige. Kann es sein das ich versuche aus dem Modul zu exportieren, anstatt zu importieren?

      Grüße, Chrisi

      1. Hallo Chrisi!

        Kann es sein das ich versuche aus dem Modul zu exportieren, anstatt zu importieren?

        Das habe ich bereits gefragt. Warum nicht gleich die Hashs im Modul packen?

        Viele Grüße aus Frankfurt/Main,
        Patrick

        --

        _ - jenseits vom delirium - _
        [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
        Nichts ist unmöglich? Doch!
        Heute schon gegökt?
        1. Hi,

          Das habe ich bereits gefragt. Warum nicht gleich die Hashs im Modul packen?

          Ja das ist richtig, habe ich auch gelesen. Ich kann aber die HASHES nicht ins Modul packen, weil im  Hauptscript der HASH zum prüfen benötigt wird. Der HASH ist eigentlich nur die Config für das ganze Script. Wenn ich jetzt in den Modulen nochmal extra Werte setze dann lasse ich lieber alles in einer Datei :-)

          Daher ein neuer Versuch, ich möchte im Modul keine festen Variablen haben, also ganz ohne ex- & import sondern mache jetzt folgendes:

          use strict;

          package myClient;

          sub TEST {
           print $_[0];
          }

          1;

          Allerdings kommt $_[0] auch auf diesem Weg nicht im Modul an wenn ich aus dem Hauptprogram folgendes Aufrufe:

          ...
          use myClient;

          myClient->TEST(123);
          ...

          Vermutlich bin ich zu blöd :)

          Viele Grüße
          Chrisi ...

          1. Ja das ist richtig, habe ich auch gelesen. Ich kann aber die HASHES nicht ins Modul packen, weil im  Hauptscript der HASH zum prüfen benötigt wird. Der HASH ist eigentlich nur die Config für das ganze Script. Wenn ich jetzt in den Modulen nochmal extra Werte setze dann lasse ich lieber alles in einer Datei :-)

            Ich hatte dir auch bereits gesagt, dass dein Ansatz im Prinzip richtig ist, du hast im Hauptmodul natürlich zugriff auf exportierte Variabeln, es ist aber nicht empfehlemnswert was du machst.

            Für Konfigurationswerte nutze ich z.b. Config::IniFiles
            Es gibt aber noch eine Reihe anderer Module für diesen Zweck.

            Struppi.

          2. Hallo Chrisi!

            Ja das ist richtig, habe ich auch gelesen. Ich kann aber die HASHES nicht ins Modul packen, weil im  Hauptscript der HASH zum prüfen benötigt wird. Der HASH ist eigentlich nur die Config für das ganze Script.

            Ein Grund mehr, den auszulagern. Warum muss er im Hauptskript bleiben?

            use strict;

            package myClient;

            sub TEST {
            print $_[0];
            }

            1;

            Allerdings kommt $_[0] auch auf diesem Weg nicht im Modul an wenn ich aus dem Hauptprogram folgendes Aufrufe:

            ...
            use myClient;

            myClient->TEST(123);
            ...

            Ich verstehe das nicht:

            C:>perl -w
            use modul;
            modul::TEST(123);
            ^Z
            123

            in modul.pm:

            package modul;

            sub TEST {
             print $_[0];
            }

            1;

            Vermutlich bin ich zu blöd :)

            Glaube ich nicht. Eher blind ;)

            Viele Grüße aus Frankfurt/Main,
            Patrick

            --

            _ - jenseits vom delirium - _
            [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
            Nichts ist unmöglich? Doch!
            Heute schon gegökt?
            1. Hi Patrick,

              Vermutlich bin ich zu blöd :)

              Glaube ich nicht. Eher blind ;)

              myClient->TEST(1111); # <- mein Fehler
              myClient::TEST(1111); # klappt

              Wäre etwas in dieser Art auch evtl. möglich? Ich drücke mich mal ala PHP aus :)

              class myClient {
                 __construct($wert){
                    // lese wert ...
                 }
                 public TEST() {
                    print $this->wert;
                 }
                 ...
              }

              Dann könnte ich vermutlich per Perl einen solchen Aufruf starten:

              use myClient(1234);
              myClient->TEST();

              Ergebnis = 1234

              Dann müsste ich nicht bei jedem Aufruf von TEST die Werte mit übergeben, weil die sind eh immer in jeder sub Funktion gleich :)

              Grüße
              Chrisi

              1. Hallo Chrisi!

                Wäre etwas in dieser Art auch evtl. möglich? Ich drücke mich mal ala PHP aus :)

                class myClient {
                   __construct($wert){
                      // lese wert ...
                   }
                   public TEST() {
                      print $this->wert;
                   }
                   ...
                }

                Da muss ich leider passen.

                Viele Grüße aus Frankfurt/Main,
                Patrick

                --

                _ - jenseits vom delirium - _
                [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
                Nichts ist unmöglich? Doch!
                Heute schon gegökt?
              2. myClient->TEST(1111); # <- mein Fehler
                myClient::TEST(1111); # klappt

                Das erste übergibt als ersten Parameter das Objekt myClient, d.h. der wert ist in $_[1]

                Dann könnte ich vermutlich per Perl einen solchen Aufruf starten:

                use myClient(1234);

                Das ginge, aber willst du nicht lieber vernüftig OOP Programmieren?
                Und dann das Objekt beim Initialisieren mit den Werten füttern?

                Dann müsste ich nicht bei jedem Aufruf von TEST die Werte mit übergeben, weil die sind eh immer in jeder sub Funktion gleich :)

                Irgendwie dachte ich du machst so was eine Konfigurationsmodul?
                Was hälst du von dem Tipp mit Config::IniFiles?

                Struppi.

              3. Wäre etwas in dieser Art auch evtl. möglich?

                Ich kenne mich in OOP mit PHP nicht aus, aber in Perl wäre sowas denkbar:

                package myClient;  
                use strict;  
                  
                sub new {  
                  my $pkg = shift;  
                  my $wert = shift || 42;  
                  my $self = { Wert => $Wert };  
                  bless $self, $pkg;  
                  return $self;  
                }  
                  
                sub TEST {  
                  my $obj = shift;  
                  return $obj->{Wert};  
                }  
                  
                1
                

                Und im Script dann:

                my $Client = myClient->new(100);  
                print $Client->Test;
                

                Dann müsste ich nicht bei jedem Aufruf von TEST die Werte mit übergeben, weil die sind eh immer in jeder sub Funktion gleich :)

                Dann handelt es sich offenbar um Objekteigenschaften, die Du in Perl so manipulieren kannst, wie ich es beschrieben habe.

                Siechfred

                --
                Hinter den Kulissen passiert viel mehr, als man denkt, aber meistens nicht das, was man denkt.
                1. Hallo Siechfred!

                  Darf ich diesmal? ;)

                  package myClient;

                  use strict;

                  sub new {
                    my $pkg = shift;
                    my $wert = shift || 42;
                    my $self = { Wert => $Wert };

                  #                          ^ $wert

                  bless $self, $pkg;
                    return $self;
                  }

                  sub TEST {
                    my $obj = shift;
                    return $obj->{Wert};
                  }

                  1

                  
                  >   
                  > Und im Script dann:  
                  >   
                  > ~~~perl
                  
                  my $Client = myClient->new(100);  
                  
                  > print $Client->Test;  
                  
                  #                  ^^^^ TEST
                  

                  Die falsche Großschreibung beim print ist mir sofort aufgefallen. Das mit $wert habe ich durchs Testen erst erfahren müssen ;)

                  Kannst Du noch kurz erklären, was new() macht?

                  Viele Grüße aus Frankfurt/Main,
                  Patrick

                  --

                  _ - jenseits vom delirium - _
                  [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
                  Nichts ist unmöglich? Doch!
                  Heute schon gegökt?
                  1. Kannst Du noch kurz erklären, was new() macht?

                    Was ist dabei konkret unklar?
                    Es erzeugt ein Objekt das an das package gebunden ist und setzt eine Eigenschaft.

                    Struppi.

                    1. Hallo Struppi!

                      Was ist dabei konkret unklar?

                      Der OOP-Ansatz im Allgemeinen ist mir noch unklar, viel zu abstrakt für mein konkretes Verständnis ;)

                      Deswegen, wenn es an einem Beispiel erläutert wird, hoffe ich mir, dass es bis in die hintersten Windungen meins Hirns durchdringt.

                      Nehmen wir also Siechfreds Beispiel:

                        
                      package myClient;  
                      use strict;  
                        
                      sub new {  
                        my $pkg = shift;  
                        my $wert = shift || 42;  
                        my $self = { Wert => $wert };  
                        bless $self, $pkg;  
                        return $self;  
                      }  
                        
                      sub TEST {  
                        my $obj = shift;  
                        return $obj->{Wert};  
                      }  
                        
                        
                      1;  
                      
                      

                      Im Hauptskript:

                        
                      use strict;  
                      use myClient;  
                      my $Client = myClient->new(123);  
                      print $Client->TEST;  
                      
                      

                      Es wird an die Funktion new() vom Package myClient »123« übergeben. Das ist jetzt in @_ - und da auch das einzige Element, oder?

                      Im Modul wird dieser Wert mittels »shift« aus @_ entfernt und an $pkg übergeben? Warum dann die Zeile mit $wert, bzw. was kann man da noch shiften?

                      Viele Grüße aus Frankfurt/Main,
                      Patrick

                      --

                      _ - jenseits vom delirium - _
                      [link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash]
                      Nichts ist unmöglich? Doch!
                      Heute schon gegökt?
                      1. Der OOP-Ansatz im Allgemeinen ist mir noch unklar, viel zu abstrakt für mein konkretes Verständnis ;)

                        Du solltest mal ins SVN gucken ;))

                        Nehmen wir also Siechfreds Beispiel:

                        Das ich mal kommentiere:

                        sub new {  
                          my $pkg = shift;  
                          my $wert = shift || 42;  
                          my $self = { Wert => $wert };  
                          bless $self, $pkg;  
                          return $self;  
                        }
                        

                        Rufst Du die Konstruktorfunktion auf, die hier new heißt, ist ihr erstes Argument ($_[0]) immer der Name der Klasse. Alles, was Du new in den Klammern mitgibst, hat den Index 1 pp. (also $_[1] bis $_[n]). Die Konstruktorfunktion holt sich also als erstes den Klassennamen, dann den via new übergebenen Parameter. Dann wird mit $self eine Hashreferenz angelegt, wo dem Schlüssel 'Wert' der Inhalt von $wert zugewiesen wird. Mehr passiert bis hierher nicht.

                        Knackpunkt ist bless, denn damit wird die Hashreferenz an den Klassennamen gebunden und erst dadurch bekommt man das gewünschte Objekt. Alles, was an Schlüsseln in $self enthalten ist, wird damit zur Objekteigenschaft.

                        sub TEST {  
                          my $obj = shift;  
                          return $obj->{Wert};  
                        }
                        

                        TEST ist eine Objektmethode. Wurde ein neues Objekt erzeugt, bekommen alle Methodenaufrufe automatisch als ersten Wert die Objektreferenz übergeben. Da TEST keine Parameter erwartet, musst Du ihr auch nichts weiter übergeben. Ein Beispiel wäre:

                        sub TEST {  
                          my $obj = shift;  
                          my $prop = shift;  
                          return $obj->{$prop};  
                        }
                        

                        Obiges Beispiel soll Objekteigenschaften ausgeben, sodass der Aufruf ohne weitere Parameter einen Fehler ergeben würde, man muss ihr das gesuchte mitteilen:

                        print $Client->TEST('Wert');

                        HTH,
                        Siechfred

                        --
                        Hinter den Kulissen passiert viel mehr, als man denkt, aber meistens nicht das, was man denkt.
                        1. Hallo Siechfred!

                          Du solltest mal ins SVN gucken ;))

                          Sollte ich in der Tat mal machen. Ich halte zwar den Tortoise-Ordner lokal immer aktuell, habe aber lange nicht im Red-Bereich (außer Forum) nachgeschaut.

                          Rufst Du die Konstruktorfunktion auf, die hier new heißt, ist ihr erstes Argument ($_[0]) immer der Name der Klasse.

                          Danke! Genau das hatte zum Verständnis gefehlt. Ich habe es wohl vergessen oder nicht richtig verinnerlicht, gelesen hatte ich es vermutlich schon. Und dadurch wird mir auch der gewählte Variablennamen (pkg für package) klar ;)

                          Da TEST keine Parameter erwartet, musst Du ihr auch nichts weiter übergeben. Ein Beispiel wäre:

                          sub TEST {

                          my $obj = shift;
                            my $prop = shift;
                            return $obj->{$prop};
                          }

                          
                          > `print $Client->TEST('Wert');`{:.language-Perl}  
                            
                          Auch klar, danke - auch wenn ich lange davon entfernt, so was zu schreiben (aber kommt sicher noch) ;)  
                            
                            
                          Viele Grüße aus Frankfurt/Main,  
                          Patrick
                          
                          -- 
                          ![](http://www.atomic-eggs.com/fuernA.jpg)  
                            
                          \_ - jenseits vom delirium - \_  
                            
                          [[link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash](http://www.atomic-eggs.com/)]  
                          Nichts ist unmöglich? [Doch!](http://www.atomic-eggs.com/cwi/cwi_4.shtml)  
                          Heute schon ge[gök](http://goek.atomic-eggs.com/goek_goek.html)t?
                          
                      2. Noch ein paar Ergänzungen

                        package myClient;
                        use strict;

                        sub new {
                          my $pkg = shift;
                          my $wert = shift || 42;
                          my $self = { Wert => $wert };
                          bless $self, $pkg;

                        Es wird an die Funktion new() vom Package myClient »123« übergeben. Das ist jetzt in @_ - und da auch das einzige Element, oder?

                        Nein, das kannst du dir z.b. mal anschauen:
                        [code lang=perl]sub new {
                          print "myClient->new(@_)\n";

                          
                        Ergibt: myClient->new(myClient 123)  
                          
                        Der erste Parameter ist das Objekt das du "blessen" willst.  
                          
                        Die Variante ist nicht unbedingt empfehlenswert, um später mal auch von einem Objekt erben zu können musst du noch testen ob der Parameter eine Referenz ist.  
                          
                        ~~~perl
                        sub new {  
                           my $pkg = shift;  
                           my $wert = shift || 42;  
                           return bless { Wert => $wert }, ref $pkg || $pkg;  
                        }
                        

                        Jetzt kannst du z.b. auch von $Client erben:

                        use strict;  
                        use myClient;  
                        my $Client = myClient->new(123);  
                          
                        my $andererClient = $Client->new(77);  
                        
                        

                        Eigentlich ist OOP in Perl einfach, das einzige was du brauchst ist package und bless, die mit bless gebunden Variabeln können dann auf die Funktionen in den package zugreifen.

                        Struppi.

                        1. Hallo Struppi!

                          Es wird an die Funktion new() vom Package myClient »123« übergeben. Das ist jetzt in @_ - und da auch das einzige Element, oder?
                          Nein, das kannst du dir z.b. mal anschauen:

                          sub new {

                          print "myClient->new(@_)\n";

                          
                          > Ergibt: myClient->new(myClient 123)  
                            
                          Eben, mein Denkfehler war, dass ich hier annahm, nur 123 würde in @\_ stehen. Wie gesagt, gelesen hatte ich das mit dem Package-Namen als erstes Element schon, nur entweder damals nicht verstanden oder wieder vergessen... Musste nach dem Post von Horst auch nachschauen, was slices sind - auch vor längerer Zeit gelesen und dann wieder vergessen ;)  
                            
                            
                          
                          > Eigentlich ist OOP in Perl einfach, das einzige was du brauchst ist package und bless, die mit bless gebunden Variabeln können dann auf die Funktionen in den package zugreifen.  
                            
                            
                          Wie gesagt, da muss ich mich mehr damit beschäftigen. Danke und  
                            
                            
                          viele Grüße aus Frankfurt/Main,  
                          Patrick
                          
                          -- 
                          ![](http://www.atomic-eggs.com/fuernA.jpg)  
                            
                          \_ - jenseits vom delirium - \_  
                            
                          [[link:hatehtehpehdoppelpunktslashslashwehwehwehpunktatomicminuseggspunktcomslash](http://www.atomic-eggs.com/)]  
                          Nichts ist unmöglich? [Doch!](http://www.atomic-eggs.com/cwi/cwi_4.shtml)  
                          Heute schon ge[gök](http://goek.atomic-eggs.com/goek_goek.html)t?