2009-08-18 7 views
0

Angenommen, das Modul AAA::BBB::CCC befindet sich in ~/modules/AAA/BBB/CCC.pm, und "~/modules" ist in @INC, also warum der folgende Code nicht funktioniert und zu Kompilierungsfehler führen?Warum kann ich einen Ausdruck nicht verwenden, um einen Klassennamen in Perls Requirement zu erstellen?

$class = "AAA::BBB" ; 
$type = "CCC"; 
require $class . '::' . $type ; 

Ich versuche zu verwenden AAA::BBB::CCC statt, es funktioniert. Wenn ich ein Modul dynamisch benötigen muss, indem ich Strings zusammenbilde, anstatt den Modulnamen direkt zu codieren, wie soll ich das machen?

dank

+1

Haben Sie jemals daran gedacht, zu betrachten "perldoc -f erforderlich"? d. h. http://perldoc.perl.org/functions/require.html – Ether

Antwort

6

Mein Ansatz:

my $class = "AAA::BBB"; 
my $type = "CCC"; 

my $full_class_name = $class . '::' . $type; 
(my $file_name = $full_class_name . '.pm') =~ s{::}{/}g; 

require $file_name; 

$full_class_name->test(); 

Mit eval, wenn Sie sind doing "die $ @ if $ @" macht nicht viel Sinn - ohne eval wird es genauso gut funktionieren.

Dieser zusätzliche Schritt zum Erstellen von file_name, der $ file_name anstelle von class erfordert, macht es nicht erforderlich, stringbasiertes eval zu verwenden, was eher langsam ist.

Natürlich können Sie immer noch eval verwenden, wenn Sie irgendeine Art von Rückfall zur Verfügung stellen möchten:

eval { require $file_name }; 
if (my $error = [email protected]) { 
    ... do something ... 
} 

Aber beachten Sie, dass dieser Block-basierte eval ist, und kein String-basierte ein.

+0

Sehen Sie den Teil, der mit "Aber wenn Sie dies versuchen: ..." in http://perldoc.perl.org/functions/require.html –

+0

@Sinan: nicht sicher, wie das relevant ist. Mein Code fällt nicht in diese Falle. Und die Tatsache, dass sie die Verwendung von String-based Eval zeigen - nun - es ist nicht meine Schuld ;-P –

5

Von perldoc -f require:

Aber wenn Sie versuchen, diese:

$class = 'Foo::Bar'; 
require $class; # $class is not a bareword 
#or 
require "Foo::Bar"; # not a bareword because of the "" 

Die Funktion erfordert die "Foo :: Bar" Datei aussehen wird in der @INC-Array und wird sich beschweren übernicht zu finden"Foo :: Bar" dort. In diesem Fall können Sie tun:

eval "require $class"; 

Daher Sie diese stattdessen versuchen:

$class = "AAA::BBB"; 
$type = "CCC"; 
eval qq{ require "${class}::${type}" }; 
+1

+1 für die Verwendung von eval. So mache ich es. – Xetius

+1

-1 für Eval-Verwendung auf Zeichenfolge. –

+2

@depesz Sie müssen diese Antwort nicht ablehnen. So sagt die Dokumentation für 'require', dass Sie ein' 'bareword''-Argument für' require' angeben müssen. –

7

Wenn ich Ihre Symptome neu formulieren kann, ich nehme an, Sie bedeuten nicht wie so:

require "AAA::BBB" . "::" . "CCC"; # built from $class and $type; 
# => Can't locate AAA::BBB::CCC in @INC (@INC contains ... 

, weil es nicht eine Datei mit dem Namen AAA::BBB::CCC finden. Doch diese gelingt:

require AAA::BBB::CCC; # note, this is _not_ quoted 

weil Perl sucht nach einem Unterverzeichnis-verschachtelten Modul mit dem Namen, teilweise AAA/BBB/CCC.pm.

So funktioniert require funktioniert.Aus der Dokumentation für requireEXPR:

Wenn EXPR ein Bareword ist, die erfordern nimmt eine „.pm“ Erweiterung und ersetzt ‚::‘ mit ‚/‘ im Dateinamen für Sie zu machen es einfach, Standardmodule zu laden.

So müssen Sie in der Regel entweder Ihre aufgebauten Modulnamen auf einen Pfadnamen Fragment konvertieren (s! ::! /! G Anfügen ".pm") oder String-eval IhrFormal konstruierten Modulnamen, wie andere vorgeschlagen haben.

1

nehme an das Modul AAA::BBB::CCC.pm in ~/modules/AAA/BBB/CCC.pm befindet

Es gibt nicht so etwas wie AAA::BBB::CCC.pm. Es gibt nur AAA/BBB/CCC.pm und ist AAA::BBB::CCC.

Verwechseln Sie nicht Paketnamen und Moduldateien.

+0

@Manni: Es ist meine Schuld, ich habe "AAA :: BBB :: CCC.pm" zu "AAA :: :: BBB :: CCC ". Danke vielmals. –

0

Ich habe diese kludgy Utility-Klasse in meinem aktuellen Projekt definiert:

package Util::RequireClass; 

use strict; 
use warnings; 

use Exporter 'import'; # gives you Exporter's import() method directly 
our @EXPORT_OK = qw(requireClass); 

sub requireClass 
{ 
    my $class = shift; 
    eval "require $class" or do { die "Ack, can't load $class: [email protected]" }; 
} 

1; 
Verwandte Themen