Come faccio a includere tutti / alcuni dei “moduli sub” in uno script Perl?

StackOverflow https://stackoverflow.com/questions/542436

  •  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.

È stato utile?

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" ) };
    }

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top