2009-08-18 7 views
0

Supposons que le module AAA::BBB::CCC situé dans ~/modules/AAA/BBB/CCC.pm, et "~/modules" soit dans @INC, alors pourquoi le code suivant ne fonctionne pas et conduit à une erreur de compilation?Pourquoi ne puis-je pas utiliser une expression pour créer un nom de classe dans Perl?

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

J'essaie d'utiliser à la place exigent AAA::BBB::CCC, cela fonctionne. Si j'ai besoin dynamiquement d'un module en combinant des chaînes ensemble plutôt qu'en codant directement le nom du module, comment dois-je faire?

grâce

+1

Avez-vous jamais pensé à regarder « perldoc -f besoin »? c'est-à-dire http://perldoc.perl.org/functions/require.html – Ether

Répondre

6

Mon approche:

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(); 

Utiliser eval, si vous êtes seulement faire "die $ @ if $ @" n'a pas beaucoup de sens - sans eval cela fonctionnera aussi bien.

Cette étape supplémentaire de création de nom_fichier et nécessitant $ nom_fichier à la place de la classe ne nécessite pas l'utilisation d'une évaluation basée sur des chaînes, ce qui tend à être plutôt lent.

Bien sûr, vous pouvez toujours utiliser eval si vous voulez fournir une sorte de repli:

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

Mais notez que c'est eval à base de blocs, et non une base de chaînes.

+0

Voir la partie qui commence par "Mais si vous essayez ceci: ..." dans http://perldoc.perl.org/functions/require.html –

+0

@Sinan: je ne sais pas comment cela est pertinent. Mon code ne tombe pas dans ce piège. Et le fait qu'ils montrent l'utilisation de l'évaluation à base de chaîne - bien - ce n'est pas ma faute ;-P –

5

De perldoc -f require:

Mais si vous essayez ceci:

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

La fonction require cherchera le fichier "Foo :: Bar" dans le tableau @INC et va se plaindre de ne pas trouver "Foo :: Bar" là. Dans ce cas, vous pouvez le faire :

eval "require $class"; 

Par conséquent, vous pouvez essayer ceci:

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

+1 pour l'utilisation d'eval. C'est comme ça que je le fais. – Xetius

+1

-1 pour l'utilisation d'eval sur chaîne. –

+2

@depesz Il n'est pas nécessaire de reporter cette réponse. C'est ainsi que la documentation de 'require' vous demande de fournir un argument non-bareword à' require'. –

7

Si je retraiter vos symptômes, je suppose que vous parlez de cette ne comme ceci:

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

parce qu'il ne peut pas trouver un fichier nommé AAA::BBB::CCC. Cependant, cette réussit:

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

parce que les recherches perl pour un module imbriqué sous-répertoire nommé, en partie, AAA/BBB/CCC.pm.

Voici comment fonctionne require.De la documentation requireEXPR:

Si EXPR est un mot simple, l'exigent suppose une ".pm" extension et remplace "::" avec "/" dans le nom de fichier pour vous, faire il est facile de charger des modules standard.

Donc, vous devez généralement soit convertir votre nom de module construit à un fragment de chemin (s! ::! /! G appending ".pm") ou une chaîne eval votre nom de module construit, comme d'autres l'ont suggéré.

1

Supposons le module AAA::BBB::CCC.pm situé dans ~/modules/AAA/BBB/CCC.pm

Il n'y a pas une telle chose comme AAA::BBB::CCC.pm. Il n'y a que AAA/BBB/CCC.pm et AAA::BBB::CCC. Ne confondez pas les noms de paquetages et les fichiers de module.

+0

@Manni: C'est ma faute, j'ai changé "AAA :: BBB :: CCC.pm" à "AAA :: BBB :: CCC ". Merci beaucoup. –

0

J'ai cette classe utilitaire kludgy défini dans mon projet actuel:

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; 
Questions connexes