2010-08-11 13 views
10

Können sagen, Sie eine übergeordnete Perl-Klasse in einer Datei haben:Erben Perl-Unterklassen importierte Module und Pragmas?

#!/usr/bin/perl 
package Foo; 
use strict; 
use warnings; 

use Data::Dumper; 

sub new{ 
    my $class = shift; 
    my %self =(); 
    return bless %self, $class; 
} 
1; 

und eine Unterklasse in einer anderen Datei:

#!/usr/bin/perl 
package Bar; 
use base "Foo"; 
1; 

Wird die Unterklasse die Verwendung Aussagen der Eltern erben? Ich weiß, dass die Methode neu vererbt wird.

Im Grunde bin ich versucht, die Menge an vorformulierten in meinem Code zu reduzieren, und ich kann eine klare Antwort auf diese Frage nicht finden.

+0

Ich frage nach dieser Funktionalität, weil Test :: Most und Moose behaupten, es zu tun, aber ich habe nicht herausgefunden, wie sie es tun. – chotchki

+3

Schauen Sie sich die Methode import() in Test :: Most an. So macht es das. Es lädt alle diese Boilerplate-Module manuell und exportiert sie zwei Ebenen nach oben. –

+0

Danke für all die Hilfe für alle! Das Import-Sub war der Schlüssel. (Ich kann mir einfach zukünftige Schmerzen ersparen und einfach Moose gehen). – chotchki

Antwort

4

Ah, gute Frage!

Will the subclass inherit the use statements from the parent? 

Nun, das hängt davon ab, was Sie mit erben. Ich werde bis zum Ende keine Annahmen machen, aber die Antwort ist vielleicht. Sie sehen, Perl vermischt die Ideen von Classes und Namespaces - ein package ist ein Begriff, der eine von ihnen beschreiben kann. Jetzt ist das Problem die Anweisung use alles, was es tut, ist ein Paket Aufnahme zwingen, und rufen Sie die Ziele import() Sub. Dies bedeutet, dass es im Wesentlichen unbegrenzte Kontrolle über Ihr Paket hat - und damit Ihre Klasse.

Nun, Verbindung dieses mit allen Methoden in Perl ist nichts mehr als subs, die $self als ein erstes Argument von Konvention nehmen und Sie sind mit Perl5 verlassen. Dies hat einen enormen Vorteil für diejenigen, die wissen, wie man es benutzt. Während streng ist ein lexikalisches Pragma, was ist mit Moose?

package BigMooseUser; 
use Moose; 

package BabyMooseUser; 
our @ISA = 'BigMooseUser'; 

package Foo; 
my $b = BabyMooseUser->new; 
print $b->meta->name; 

Nun, wo hat BabyMooseUser bekommen den Konstruktor (neu) aus? Woher hat es die Meta-Klasse? All dies wird von einer einzelnen use Moose; in der übergeordneten Klasse (Namespace) bereitgestellt. So

Will the subclass inherit the use statements from the parent? 

Nun, hier, in unserem Beispiel, wenn die Auswirkungen der use-Anweisung sind Methoden an, als sicher.

Dieses Thema ist eine Art tief, und es hängt davon ab, ob Sie über Pragmas sprechen, oder Unbekannter Objektrahmen oder Verfahrensmodule. Wenn Sie verhindern möchten, dass ein Eltern-Namespace Ihre eigenen im OO-Paradigma beeinflusst, lesen Sie .

+1

Eigentlich, erzwingt die Verwendung eines Pakets Aufnahme.Es sucht nach einer Datei basierend auf dem Paketnamen, den Sie verwenden möchten(). Diese Datei muss dieses Paket nicht laden. Per Konvention benennen wir unsere Dateien mit dem Paketnamen, den es enthält, aber das ist nicht etwas, woran use() interessiert ist. Zum Beispiel ist Module :: Build :: Version wirklich da, um die Version zu laden. Die Datei use() lädt möglicherweise sogar mehr als ein Paket. –

+2

BabyMooseUser erhält seine neue(), weil Sie eine Vererbungsbeziehung deklarieren. Der einzelne Moose-Anruf stellt das nicht für Sie bereit. Und, autoclean wird sich nur mit importierten Symbolen beschäftigen. Es wird den Zugang zu nichts anderem einschränken, auf das Sie zugreifen wollen. –

+2

Es ist irgendwie komisch zu sagen, dass Methoden Subs sind, die * $ self als erstes Argument nehmen. Methoden sind Subs, aber Sie enden mit ihrem Referenten als erstem Argument, ohne es explizit als Argument anzugeben. Dieser Referent könnte der Klassenname (eine Zeichenkette) oder ein Verweis auf ein Objekt sein, abhängig davon, was sich links von -> befindet (indirekte Aufrufe ignorieren). Es ist auch nicht so einfach, auf der linken Seite nach Literalen oder Variablen zu suchen. :) –

1

Sie können für jedes Paket durch Untersuchen der Symboltabellen eine definitive Antwort erhalten:

# examine-symbol-tables.pl 
use Bar; 

%parent_names = map{$_ => 1} keys %Foo::; 
%child_names = map{$_ => 1} keys %Bar::; 

delete $parent_names{$_} && ($common_names{$_} = delete $child_names{$_}) foreach keys %child_names; 

print "Common names in symbol tables:\n"; 
print "@{[keys %common_names]}\n\n"; 

print "Unique names in Bar symbol table:\n"; 
print "@{[keys %child_names]}\n\n"; 

print "Unique names in Foo symbol table:\n"; 
print "@{[keys %parent_names]}\n\n"; 

 
$ perl inherit.pl 
Common names in symbol tables: 
BEGIN 

Unique names in Bar symbol table: 
ISA isa import 

Unique names in Foo symbol table: 
Dumper new VERSION 
4

Für Boilerplattenreduktion habe ich ein paar Strategien: Die meisten meiner Klassen sind Moose Klassen, die kümmert sich um OO-Setup und gibt mir auch strenge und Warnungen. Wenn ich Funktionen in vielen Paketen zur Verfügung stellen möchte, erstelle ich ein projektspezifisches Modul MyProject::Util, das Sub-Exporter verwendet, um mir meine eigenen Funktionen und meine eigene Schnittstelle zur Verfügung zu stellen. Dies macht es konsistenter, und wenn ich mich entscheide, den Dumper zum Beispiel aus irgendeinem Grund später zu ändern, muss ich nicht viel Code ändern. Dadurch können Sie auch Exporte gruppieren.Eine Klasse sieht dann in der Regel etwas wie folgt aus:

package Foo; 
use Moose; 
use MyProject::Util qw(:parsing :logging); 

use namespace::autoclean; 

# class implementation goes here 

1; 

Wenn es andere Dinge, die Sie als Text betrachten und einfacher machen wollen aufzunehmen, es hängt natürlich davon ab, was diese Dinge sind.

7

Sie fragte in einem Kommentar über Test::Most und wie es Boilerplate reduziert. Schauen Sie sich die import Methode an. Es lädt die Module in seinen Namensraum, fügt diese Symbole zu @EXPORT hinzu, ruft dann einen anderen import durch einen goto erneut auf, um sie schließlich in den aufrufenden Namespace zu bringen. Es ist eine ernstzunehmende schwarze Magie, die Curtis dort vorfindet, obwohl ich mich frage, warum er so etwas wie import_to_level nicht verwendet hat. Vielleicht gibt es einige Nebenwirkungen, über die ich nicht nachdenke.


Ich spreche ziemlich viel über diese Art der Sache in Avoid accidently creating methods from module exports in The Effective Perler. Es ist in einem anderen Kontext, aber es sind einige der gleichen Probleme.

Hier ist ein anderes Beispiel.

Wenn ein anderes Modul ein Modul lädt, haben Sie Zugriff darauf. Es ist jedoch nicht gut, sich darauf zu verlassen. Hier sind drei separate Dateien:

Top.pm

use 5.010; 

package Top; 
use File::Spec; 

sub announce { say "Hello from top!" } 
1; 

Bottom.pm

package Bottom; 
use parent qw(Top); 

sub catfiles { File::Spec->catfile(@_) } 

1; 

test.pl

use 5.010; 

use Bottom; 

say Bottom->catfiles(qw(foo bar baz)); 

say File::Spec->catfile(qw(one two three)); 

Ich lade nur File :: Spec in Top.pm. Sobald es einmal geladen ist, kann ich es überall in meinem Perl-Programm verwenden. Die Ausgabe zeigt, dass ich in der Lage war, „zu verwenden“, um das Modul in anderen Dateien, obwohl ich es nur in einer geladen:

Bottom/foo/bar/baz 
one/two/three 

Damit dies funktioniert, wird der Teil des Codes, der das Modul lädt muss geladen werden, bevor Jeder andere Teil des Codes versucht, dieses Modul zu verwenden. Wie gesagt, es ist eine schlechte Idee, sich darauf zu verlassen: Wenn die Ladesequenz sich ändert oder das Lademodul verschwindet, brechen die Dinge.

Wenn Sie jedoch Symbole importieren möchten, müssen Sie das gewünschte Modul explizit laden, während Sie sich in dem Paket befinden, in das Sie importieren möchten. Das ist nur so, weil das exportierende Modul die Symbole in diesem Paket definiert. Es hängt nicht vom Umfang ab.

2

Eine pragmatische Antwort auf Ihr Problem: Entweder verwenden Sie oder schauen Sie sich an, wie Modern::Perl es tut, strenge und Warnungen zu erzwingen.

+0

Modern :: Perl zieht strenge und Warnungen ein, die Module sind, die mit $^H fuzz sind. Die meisten Module werden das nicht wollen. –

Verwandte Themen