2014-07-26 2 views
5

Avere un codice successivo:Come rilevare i sottotitoli esportati sovrascrivi?

use strict; 
use warnings; 

use Devel::Peek; 
use YAML; 

my $s = {a=>'b'}; 
print Dump($s); 

esso stampa uscita YAML:

--- 
a: b 

ora cambiare l'ordine dei moduli.

use strict; 
use warnings; 

use YAML; 
use Devel::Peek; 

my $s = {a=>'b'}; 
print Dump($s); 

esso stampa:

SV = IV(0x7ff5d2829308) at 0x7ff5d2829318 
    REFCNT = 1 
    FLAGS = (PADMY,ROK) 
    RV = 0x7ff5d2803438 
    SV = PVHV(0x7ff5d2808d20) at 0x7ff5d2803438 
    REFCNT = 1 
    FLAGS = (SHAREKEYS) 
    ARRAY = 0x7ff5d243acf0 (0:7, 1:1) 
    hash quality = 100.0% 
    KEYS = 1 
    FILL = 1 
    MAX = 7 
    Elt "a" HASH = 0x274d838f 
    SV = PV(0x7ff5d2804070) at 0x7ff5d2828a00 
     REFCNT = 1 
     FLAGS = (POK,IsCOW,pPOK) 
     PV = 0x7ff5d240e2d0 "b"\0 
     CUR = 1 
     LEN = 16 
     COW_REFCNT = 1 
Use of uninitialized value in print at yy line 8. 

Entrambi modulo esporta una funzione Dump così, gli ultimi vince.

Ho abilitato warnings, ma non mi avvisa delle funzioni esportate ridefinire (sovrascrivere?). È possibile rilevare e mostrare un avviso per tali ridefinizioni?

risposta

5

Domanda più interessante. Il problema, penso, sta nel fatto che Exporter.pm non ha abilitato gli avvertimenti. Ecco un semplice insieme di file che illustra il comportamento che hai descritto:

Foo.pm:

package Foo; 
use base 'Exporter'; 
our @EXPORT = qw(Baz); 

sub Baz { 
    print "Hello from Foo::Baz\n"; 
} 

Bar.pm:

package Bar; 
use base 'Exporter'; 
our @EXPORT = qw(Baz); 

sub Baz { 
    print "Hi from Bar::Baz\n"; 
} 

import-redefine.pl:

use strict; 
use warnings; 

use Foo; 
use Bar; 
Baz(); 

esempio:

C:\Users\Lona\Desktop\pm>perl import-redefine.pl 
Hi from Bar::Baz 

invertire la use dichiarazioni, come segue:

use strict; 
use warnings; 

use Bar; 
use Foo; 
Baz(); 

ed eseguire di nuovo:

C:\Users\Lona\Desktop\pm>perl import-redefine.pl 
Hello from Foo::Baz 

mi è venuta in mente la seguente soluzione, che ridefinisce il metodo di default import di Exporter.pm:

BEGIN { 
    require Exporter;        # We'll need Exporter.pm loaded. 
    my $old_import = \&Exporter::import;   # Save copy of original Exporter::import. 

    no strict 'refs';        # We'll be using some hacks that will 
    no warnings 'redefine';       # raise errors and warnings. Suppress those. 

    *Exporter::import = sub {      # Our enhancement of Exporter::import. 
     use Carp; 
     my $pkg = shift; 
     my $callpkg = caller($Exporter::ExportLevel + 1); 

     my @exports = @_ > 0      # Which subs to export? 
         ? @_       # Those provided as 'use MODULE' arguments...     
         : @{"$pkg\::EXPORT"}   # Or thosedefined in the module's @EXPORT? 
     ; 
     foreach my $sub (@exports) {    # For each of the exportees... 
      if (exists ${"$callpkg\::"}{$sub}) { # ... check if it exists... 
       carp "Subroutine $callpkg\::$sub redefined by import"; # and throw a warning if needed. 
      } 
     $old_import->($pkg, @_);     # Call the original Exporter::import. 
     } 
    } 
} 

Per utilizzare questo, ma da qualche parte nel file di script principale, sopra il use MODULE dichiarazioni:

use strict; 
use warnings; 

BEGIN { 
    require Exporter;        # We'll need Exporter.pm loaded. 
    my $old_import = \&Exporter::import;   # Save copy of original Exporter::import. 

    no strict 'refs';        # We'll be using some hacks that will 
    no warnings 'redefine';       # raise errors and warnings. Suppress those. 

    *Exporter::import = sub {      # Our enhancement of Exporter::import. 
     use Carp; 
     my $pkg = shift; 
     my $callpkg = caller($Exporter::ExportLevel + 1); 

     my @exports = @_ > 0      # Which subs to export? 
         ? @_       # Those provided as 'use MODULE' arguments...     
         : @{"$pkg\::EXPORT"}   # Or thosedefined in the module's @EXPORT? 
     ; 
     foreach my $sub (@exports) {    # For each of the exportees... 
      if (exists ${"$callpkg\::"}{$sub}) { # ... check if it exists... 
       carp "Subroutine $callpkg\::$sub redefined by import"; # and throw a warning if needed. 
      } 
     $old_import->($pkg, @_);     # Call the original Exporter::import. 
     } 
    } 
} 

use Foo; 
use Bar; 
Baz(); 

ed eseguirlo:

C: \ Users \ Lona \ Desktop \ pm> perl import-redefine.pl

Subroutine main::Baz redefined by import at import-redefine.pl line 21. 
     main::__ANON__("Bar") called at import-redefine.pl line 30 
     main::BEGIN() called at import-redefine.pl line 30 
     eval {...} called at import-redefine.pl line 30 
Hi from Bar::Baz 
+0

Wow - grande e dettagliata risposta. Onestamente, speravo in qualcosa di più semplice, ad esempio "usa warnins" exported_functions "o soo, ma sembra che non sia una cosa facile. Grazie. – kobame