Come faccio a includere tutti / alcuni dei “moduli sub” in uno script Perl?
-
23-08-2019 - |
Domanda
Mi limiterò a iniziare dicendo io non sono affatto sperimentato con la creazione di moduli Perl quindi mi dispiace se sono lontano qui.
Diciamo che sto creando un paio di moduli:
foo::bar
foo::bar::a
foo::bar::b
Dato che io non so che cosa si chiamano, io chiamo i moduli a.pm e b.pm "moduli secondari", in quanto essi sono legati al modulo bar.pm, ma potrebbe ancora essere in qualche modo indipendente.
Quindi, uno dei miei script Perl potrebbe utilizzare foo :: :: bar un altro script potrebbe utilizzare foo :: :: bar b, e forse ho un altro script che ha bisogno di utilizzare le funzioni sia da "a" e "b ". Invece di dire questo:
use foo::bar;
use foo::bar::a qw(one two);
use foo::bar::b;
Io voglio fare qualcosa di simile:
use foo::bar qw(:a :b);
Nella mia mente, che darebbe il mio accesso script per tutto in bar.pm, a.pm e b.pm.
Ho provato qualcosa di simile, e sono stato ovviamente sbagliato.
E 'qualcosa di simile a questo possibile? Suppongo che potrei avere l'uso bar.pm a.pm e b.pm, e quindi avere funzioni "wrapper" che passano la chiamata sui "moduli sub", ma sembra che ci sarebbe un modo più semplice.
Soluzione
Guardate il mio modulo Test :: dati per un esempio di fare questo. Anche se è possibile farlo accadere, non sono mai stato terribilmente appassionato del risultato. Si potrebbe prendere in considerazione un plugin o approccio Mixin invece. Ci sono alcuni moduli su CPAN che può aiutare con questo.
Ecco il import
personalizzato che ho scritto per Test :: Dati:
sub import { my $self = shift; my $caller = caller; foreach my $package ( @_ ) { my $full_package = "Test::Data::$package"; eval "require $full_package; 1"; if( $@ ) { carp "Could not require Test::Data::$package: $@"; } $full_package->export($caller); } }
Altri suggerimenti
Sì, è possibile farlo. Sarà probabilmente comporterà la scrittura di un 'sub importazione' personalizzato in foo bar :: che interpreta gli argomenti in arrivo nel modo desiderato.
Probabilmente stai usando un esportatore in questo momento, ed è la sua mancanza di supporto per la sintassi che è il problema. Troverete che non c'è niente di particolarmente speciale circa gli attrezzi Esportatore sintassi modulo; è solo una convenzione comune. È probabile che consigliamo di guardare come si fa business per ottenere un'idea di come si vorrà, però.
Se non sapete cosa sia un modulo è chiamato, perché stai includerlo? Non dovrebbe essere necessario includerlo. includere solo un modulo nel modulo (chiamata) che ne ha bisogno, e non altrove.
Cioè: se lo si utilizza, quindi "usare" esso. Se non si usa, non "usare" esso.
Sì, ma è necessario attrezzare il proprio sub di importazione:
use strict;
use warnings;
package ab;
use base qw<Exporter>;
our @EXPORT_OK;
our %EXPORT_TAGS;
BEGIN {
@EXPORT_OK = qw<>;
%EXPORT_TAGS = ( a => 1, b => 1, all => \@EXPORT_OK );
}
sub setup_part {
#use Smart::Comments;
my $code = shift;
my $mini_path = "foo/bar/$code.pm";
return if exists $INC{$mini_path};
require $mini_path;
my $arr_ref
= do { no strict 'refs';
\@{Symbol::qualify( 'EXPORT_OK', $code )};
};
$code->import( @$arr_ref );
push @EXPORT_OK, @$arr_ref;
$EXPORT_TAGS{$code} = [ @$arr_ref ];
return;
}
sub import {
my ( $package_name, @imports ) = @_;
my %import_hash = map { $_ => 1 } @imports;
if ( exists $import_hash{':all'} ) {
@import_hash{qw<:a :b>} = ( 1, 1 );
}
foreach my $import ( grep { exists $import_hash{$_} } qw<:a :b> ) {
setup_part( substr( $import, 1 ));
}
goto &{Exporter->can( 'import' )};
}
1;
Prova anche guardando Class :: MixinFactory
Ho cercato la soluzione simile a quello recente. So - troppo vecchio thread, ma mi piacerebbe commentare la risposta ( 12 febbraio '09 alle 17:55 ) da brian d foy , ma purtroppo non lo fanno hanno abbastanza reputazione per raggiungere questo obiettivo. È per questo che aggiungo il mio commento come nuova risposta.
La sua risposta mi ha aiutato a risolvere il problema simile a quello recente. Ma richiede qualche modifica se viene utilizzato con use lib
.
Ho un sacco di moduli che assomigliano A::B::*
. Questi dovrebbero essere caricati agli script dal modulo A::B
generale. Tutti i moduli sono all'interno delle loro file nella stessa directory dello script di caricamento. Utilizzando il meccanismo suggerito da brian d foy che possiamo ottenere molti subroutine ridefinito errori . Per evitare tutti loro, credo, ho trovato una soluzione migliore, meglio di no warnings 'redefine'
. Ora siamo liberi di usare use lib
, no warnings 'redefine'
o shift @INC, ...
nello script principale.
sub import { @TAGS = ( @_ ); my $me = shift @TAGS; ( my $pm = $me ) =~ s|::|/|g; $pm .= ".pm"; ( $dir = $INC{$pm} ) =~ s/\.pm$//; foreach ( glob "$dir/*.pm" ) { /(\w+)\.pm$/; my $module = "${me}::$1"; eval "use $module qw(:all)"; # You are free to use any items in the exporting list die "$me: Error while loading $module from $_: $@\n" if $@; } # Fill in @EXPORT_OK and %EXPORT_TAGS manually from each A::B::*::EXPORT_OK # ... goto &{ Exporter->can( "import" ) }; }