Как включить все / некоторые из «подмодулей» в сценарий Perl? - PullRequest
4 голосов
/ 12 февраля 2009

Я просто начну с того, что у меня нет опыта создания модулей Perl, поэтому извините, если я далеко отсюда.

Допустим, я создаю несколько модулей:

foo::bar
foo::bar::a
foo::bar::b

Поскольку я не знаю, как они называются, я называю субмодули модулей a.pm и b.pm, поскольку они связаны с модулем bar.pm, но все еще могут быть несколько независимыми.

Таким образом, один из моих сценариев Perl может использовать foo :: bar :: a, другой сценарий может использовать foo :: bar :: b, и, возможно, у меня есть другой сценарий, которому нужно использовать функции как из «a», так и из «b» ». Вместо того чтобы сказать это:

use foo::bar;
use foo::bar::a qw(one two);
use foo::bar::b;

Я хочу сделать что-то вроде этого:

use foo::bar qw(:a :b);

По-моему, это дало бы моему сценарию доступ ко всему в bar.pm, a.pm и b.pm.

Я проверил что-то подобное, и я явно ошибся.

Возможно ли что-то подобное? Я полагаю, что я мог бы использовать bar.pm с использованием a.pm и b.pm, а затем иметь функции «обертки», которые передают вызов на «подмодули», но кажется, что есть более простой способ.

Ответы [ 6 ]

5 голосов
/ 12 февраля 2009

Посмотрите в моем модуле Test :: Data пример того, как это сделать. Даже если вы можете сделать это, я никогда не был в восторге от результата. Возможно, вы захотите рассмотреть плагин или миксин подход вместо этого. На CPAN есть несколько модулей, которые могут помочь с этим.

Вот пользовательский import, который я написал для Test :: Data:

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

    }
2 голосов
/ 12 февраля 2009

Да, вы можете сделать это. Вероятно, это будет связано с написанием пользовательского «sub import» в foo :: bar, который интерпретирует входящие аргументы так, как вы хотите.

Возможно, вы используете Exporter прямо сейчас, и проблема заключается в отсутствии поддержки вашего синтаксиса. Вы обнаружите, что нет ничего особенного в реализации синтаксиса модуля Exporter; это просто общее соглашение. Вы, вероятно, захотите взглянуть на то, как это работает, чтобы понять, как вы этого хотите.

1 голос
/ 12 февраля 2009

Если вы не знаете, как называется модуль, почему вы включаете его? Вам не нужно включать его. Включите модуль в (вызывающий) модуль, который ему нужен, и больше нигде.

То есть: если вы используете его, то «используйте» его. Если вы не используете его, не «используйте» его.

0 голосов
/ 09 апреля 2014

Я искал решение, похожее на последнее. Я знаю - слишком старая тема, но я хотел бы прокомментировать ответ ( 12 февраля 2009 в 17: 55 ) Брайан Д Фой но, к сожалению, мне не хватает репутация для достижения этой цели. Вот почему я добавляю свой комментарий как новый ответ.

Его ответ помог мне решить проблему, аналогичную последней. Но это требует некоторой модификации, если используется с use lib.

У меня есть несколько модулей, которые выглядят как A::B::*. Они должны быть загружены в скрипты общим модулем A::B. Все эти модули находятся в своих файлах в том же каталоге, что и скрипт загрузки. Используя механизм, предложенный Брайаном Д Фой , мы можем получить множество переопределенных процедурных ошибок . Я считаю, что, чтобы избежать всех их, я нашел лучшее решение, чем no warnings 'redefine'. Теперь мы можем использовать use lib, no warnings 'redefine' или shift @INC, ... в основном скрипте.


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

0 голосов
/ 12 февраля 2009

Да, но вы должны настроить собственный импортный саб:

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;
0 голосов
/ 12 февраля 2009

Также попробуйте посмотреть на Class :: MixinFactory

...