web-dev-qa-db-fra.com

Comment puis-je vérifier si j'ai un module Perl avant de l'utiliser?

J'ai le code Perl suivant qui s'appuie sur Term::ReadKey pour obtenir la largeur du terminal; Mon build NetBSD manque ce module, donc je veux par défaut la largeur du terminal à 80 lorsque le module est manquant.

Je n'arrive pas à comprendre comment utiliser conditionnellement un module, sachant à l'avance s'il est disponible. Mon implémentation actuelle se termine juste avec un message disant qu'elle ne trouve pas Term::ReadKey s'il est absent.

#/usr/pkg/bin/Perl -w
# Try loading Term::ReadKey
use Term::ReadKey;
my ($wchar, $hchar, $wpixels, $hpixels) = GetTerminalSize();
my @p=(2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97);
my $plen=$#p+1;
printf("num |".("%".int(($wchar-5)/$plen)."d") x $plen."\n",@p);

J'utilise Perl 5.8.7 sur NetBSD et 5.8.8 sur CygWin Pouvez-vous m'aider à l'implémenter plus efficacement dans mon script?

50
dlamblin

Voici une solution à nu qui ne nécessite pas d'autre module:

my $rc = eval
{
  require Term::ReadKey;
  Term::ReadKey->import();
  1;
};

if($rc)
{
  # Term::ReadKey loaded and imported successfully
  ...
}

Notez que toutes les réponses ci-dessous (j'espère qu'elles sont en dessous de celle-ci! :-) qui utilisent eval { use SomeModule } sont incorrectes car les instructions use sont évaluées au moment de la compilation, quel que soit leur emplacement dans le code. Donc, si SomeModule n'est pas disponible, le script mourra immédiatement lors de la compilation.

(L'évaluation d'une chaîne d'une instruction use fonctionnera également (eval 'use SomeModule';), mais il n'y a aucun sens à analyser et à compiler du nouveau code au moment de l'exécution lorsque la paire require/import fait la même chose, et la syntaxe est vérifiée au moment de la compilation pour démarrer.)

Enfin, notez que mon utilisation de eval { ... } et $@ ici est succinct pour les besoins de cet exemple. Dans le code réel, vous devez utiliser quelque chose comme Try :: Tiny , ou au moins soyez conscient des problèmes qu'il résout .

91
John Siracusa

Découvrez le module CPAN Module :: Load :: Conditional . Il fera ce que vous voulez.

11
m0j0

La réponse classique (remontant à Perl 4, au moins, bien avant qu'il y ait une "utilisation") était de "exiger ()" un module. Ceci est exécuté pendant l'exécution du script, plutôt que lors de sa compilation, et vous pouvez tester le succès ou l'échec et réagir de manière appropriée.

7
Jonathan Leffler
if  (eval {require Term::ReadKey;1;} ne 1) {
# if module can't load
} else {
Term::ReadKey->import();
}

ou

if  (eval {require Term::ReadKey;1;}) {
#module loaded
Term::ReadKey->import();
}

Noter la 1; ne s'exécute que si require Term::... chargé correctement.

4
ShqTth

Et si vous avez besoin d'une version spécifique du module:

my $GOT_READKEY;
BEGIN {
    eval {
        require Term::ReadKey;
        Term::ReadKey->import();
        $GOT_READKEY = 1 if $Term::ReadKey::VERSION >= 2.30;
    };
}


# elsewhere in the code
if ($GOT_READKEY) {
    # ...
}
4
Hinrik

Je pense que cela ne fonctionne pas lors de l'utilisation de variables. Veuillez vérifier ce lien qui explique comment il peut être utilisé avec une variable

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

La fonction require recherchera le fichier "Foo :: Bar" dans le tableau @INC et se plaindra de ne pas y trouver "Foo :: Bar". Dans ce cas, vous pouvez faire:

 eval "require $class";
0
Utkarsh Kumar