2010-09-07 6 views
1

Je rencontre un problème avec l'utilisation d'une constante définie dans un fichier de configuration. Ceci est mon paquet:Importer un fichier requis comme s'il s'agissait d'une instruction d'utilisation

package myPackage; 
require "APIconfig.pl"; 
APIconfig::import(APIconfig); 

use constant SERVICE_URL => APIconfig::SERVICE_URL(); 

La configuration ressemble à ceci:

package APIconfig; 
use constant SERVICE_URL => 'http://api.example.org/blah'; 
1; 

Lors de l'exécution de ce code, je reçois l'erreur suivante:

Undefined subroutine &APIconfig::SERVICE_URL called at API.pl line 4. 

Je ne peux pas utiliser 'l'utilisation' au lieu de 'require' car cela attend que le fichier de configuration soit nommé .pm, et il s'appelle .pl sur beaucoup de serveurs sur notre réseau. Comment puis-je utiliser le package sans renommer le fichier?

Répondre

7

Il existe deux différences entre 'use' et 'require'. L'un d'entre eux affecte votre problème actuel, l'autre non. Malheureusement, vous travaillez autour d'un qui n'a aucun effet.

Les différences sont les suivantes:

1/'utilisation' appelle la fonction d'importation(), 'require' ne fonctionne pas. 2/'use' arrive à la compilation, 'require' arrive à l'exécution.

Vous travaillez sur le fait que 'require' n'appelle pas import() en l'appelant explicitement. Cela n'a aucun effet car votre module n'exporte aucun symbole et n'a pas de sous-programme import().

Vous ne travaillez pas sur le fait que les instructions 'use' sont exécutées lors de l'exécution. Le problème est que "use constant SERVICE_URL => APIconfig :: SERVICE_URL();" est exécuté au moment de la compilation et votre 'require' n'est pas exécuté alors myPackage ne sait rien à propos d'APIconfig.

La solution (méchante, hacky) consiste à placer l'instruction 'require' dans un bloc BEGIN - pour le forcer à être exécuté au moment de la compilation. Vous devrez également supprimer l'appel à import() car cela provoque une erreur d'exécution (en raison de l'absence de la sous-routine).

Les fichiers de test que je travaillais ceci sont les suivantes:

$ cat APIconfig.pl 
package APIconfig; 
use constant SERVICE_URL => 'http://api.example.org/blah'; 
1; 

$ cat api.pl 
#!/usr/bin/perl 

package myPackage; 
BEGIN { 
    require "APIconfig.pl"; 
} 
# APIconfig::import(APIconfig); 

use constant SERVICE_URL => APIconfig::SERVICE_URL(); 

print SERVICE_URL, "\n"; 
$ ./api.pl 
http://api.example.org/blah 

La vraie solution consiste à réécrire APIconfig comme un véritable module. Vous indiquez que vous le savez, mais que les problèmes environnementaux vous empêchent d'adopter cette approche. Je recommande fortement d'essayer de contourner ces problèmes et de faire les choses correctement.

2

Cela ne peut pas être possible - il n'y a pas de sous-programme import dans le paquet APIconfig. Une fois que vous accédez à des noms symboliques avec un chemin de package complet, vous n'avez pas besoin d'exporter/importer de toute façon.

La solution consiste à exécuter require au moment de la compilation, avant use constant. Cela fonctionne:

package myPackage; 
BEGIN { 
    require "APIconfig.pl"; 
} 

use constant SERVICE_URL => APIconfig::SERVICE_URL(); 
1

S'il s'agit d'un fichier de configuration, ne le faites pas de code. J'ai un chapitre entier dans Maîtriser Perl à ce sujet, et il y a beaucoup de modules sur CPAN pour vous aider avec presque n'importe quel format de configuration.

Si c'est du code, pourquoi ne pas en faire un module pour pouvoir utiliser use. Les modules sont tellement plus faciles à contrôler et à manipuler dans un autre programme.

Les solutions les plus simples sont celles où vous ne nagez pas contre la marée. :)

Au-delà, use est le même que:

BEGIN { 
     require Module; 
     Module->import; 
     } 

vous venez de faire la même chose avec le nom de fichier et l'espace de noms définit (tant que le code dans le fichier ressemble à un module):

BEGIN { 
     require "file.pl"; # defines SomeNamespace 
     SomeNamespace->import; 
     }