2010-10-06 16 views
4

Si un fichier est déjà chargé, est-il possible de se connecter au use/require afin de pouvoir lancer une exception? Dans mon prochain nextgen::blacklist, j'essaye de mourir si certains modules sont utilisés. J'utilise la méthode object-hook comme mentionné dans perldoc -f require: il y a trois crochets comme objet, tableau avec subref, et sous-réf. L'exemple dans ce post est le crochet d'objet, vous pouvez trouver ma tentative du crochet sous-réf dans nextgen::blacklist.Comment puis-je me connecter à Perl's use/require pour pouvoir lancer une exception?

La syntaxe je désire est quelque chose comme:

perl -Mnextgen -E"use NEXT"

package Foo; 
use nextgen; 
use NEXT; 

Idéalement, il est censé jeter un message comme celui-ci:

nextgen::blacklist violation with import attempt for: [ NEXT (NEXT.pm) ] try 'use mro' instead. 

J'ai essayé ce un tas de façons différentes.

package Class; 
use Data::Dumper; 
use strict; 
use warnings; 

sub install { 
    unshift @main::INC, bless {}, __PACKAGE__ 
    unless ref $main::INC[0] eq __PACKAGE__ 
    ; 
} 

sub reset_cache { undef %main::INC } 

sub Class::INC { 
    my ($self, $pmfile) = @_; 
    warn Dumper [\%main::INC, $pmfile]; 
    #undef %INC; 
} 

package main; 
    BEGIN { Class->install; undef %main::INC } 
    use strict; 
    use strict; 
    use strict; 
    use strict; 
    use warnings; 
    use strict; 
    use warnings; 

Il semble que %INC n'est mis après ces crochets. Je suis intéressé par tout ce qui me permettra de faire une exception. Si une tentative est faite pour charger/recharger un module, son statut en tant que dépendance d'autres modules qui n'utilisent pas mon pragma, je veux mourir.

package Foo; 
use NEXT; 

package main; 
use Foo; (which uses Next.pm); 
use NEXT.pm; ## Throw exception 

Répondre

5

Vous voulez probablement mettre un coderef sur le début @INC, comme décrit dans perldoc -f require. A partir de là, vous pouvez lever des exceptions pour empêcher le chargement de certains modules, ou ne rien faire pour laisser continuer son travail normal de recherche du module dans les autres entrées @INC.

$ perl -E'BEGIN { unshift @INC, sub { die q{no NEXT} if pop eq q{NEXT.pm};() }; }; use Carp; say q{success}' 
success 
$ perl -E'BEGIN { unshift @INC, sub { die q{no NEXT} if pop eq q{NEXT.pm};() }; }; use NEXT; say q{success}' 
no NEXT at -e line 1. 
BEGIN failed--compilation aborted at -e line 1. 

Si vous voulez que le comportement soit lexical, vous devez utiliser des notes de hachage Perl %^H. Traiter avec cela est un peu délicat, donc je vous recommande d'utiliser Devel::Pragma, qui peut prendre soin de tous les détails sanglants pour vous.

Comme vous l'avez souligné, les hooks @INC ne seront pas exécutés pour un module déjà chargé. Si vous devez également vous connecter au use ou au require d'un module chargé, le remplacement de CORE::GLOBAL::require fonctionnerait comme il est appelé pour chaque tentative de chargement d'un module.

$ perl -E'BEGIN { *CORE::GLOBAL::require = sub { warn @_ } } use NEXT; use NEXT;' 
NEXT.pm at -e line 1 
NEXT.pm at -e line 1. 

En outre, en tant que responsable de NEXT, j'approuve complètement d'empêcher les gens de l'utiliser, du tout, jamais. :-)

+0

Merci pour les mots d'encouragement, j'ai essayé de mettre un coderef dans '@ INC', consultez [nextgen :: blacklist] (http://github.com/EvanCarroll/nextgen/tree/blacklist/lib/nextgen /), pour cette tentative. Il y a trois hooks qui semblent tous fournir cette fonctionnalité (array w/coderef, object, et coderef), aussi dans le perldoc que vous référencez. –

+0

Alors quel est le problème? Je viens d'ajouter un petit exemple de cela à ma réponse, et cela fonctionne comme prévu. – rafl

+0

Par titre, (et texte) Si NEXT est inclus par une dépendance, je veux toujours 'utiliser NEXT' pour lancer une exception. Cela signifie que si vous utilisez Foo.pm, qui dépend de 'NEXT'. Je ne veux toujours pas que NEXT soit autorisé. Mais, je ne veux pas que l'include pour Foo.pm provoque une exception. –