2

我正在尝试扩展一个mA正在使用的类()Sub::Exporter。我想Sub::Exporter在子类(mB)中使用。我不知道如何通过对inmA的调用传递唯一的选项。下面是一些测试代码:Sub::ExportermB

#!/usr/bin/env perl

use 5.10.1;
use strict;
use warnings;


{
    package mA;

    use Sub::Exporter -setup => {
            exports => { gmorn => \&build_gmorn },
        };

    sub build_gmorn {
        my ( $class, $name, $arg ) = @_;
        return sub { say "$arg->{salutation}"; }
    }

    sub new { return bless {}, shift }
}

{
    package mB;

    use parent -norequire, 'mA';

    use Sub::Exporter -setup => {
        exports => { gnite => \&build_gnite },
    };

    sub build_gnite {
        my ( $class, $name, $arg ) = @_;
        return sub { say "$arg->{salutation}"; }
    }
}

{
    package mFr;

    use parent -norequire, 'mB';

    mB->import(
       gmorn => { salutation => 'Bon Jour' },
       gnite => { salutation => 'Bon Nuit' }
    );

}

my $obj = mFr->new;

$obj->gmorn();
$obj->gnite();

结果是:

% perl t
"gmorn" is not exported by the mB module at t line 66.

有没有办法继承Sub::Exporter规范?

4

1 回答 1

0

Since you are writing object-oriented perl, it is a very bad idea to import symbols from one package into another. The inheritance the Perl's standard mechanism will work fine, and all you seem to be doing here is renaming the imported methods.

The problem is that use parent doesn't call the other package's import routine, so build_gmorn is never imported into mB as gmorn.

In addition, as your error message says, gmorn is not exported by the mB module, so it cannot be imported into mFr.

If you change mB to look like this then your code will mostly work. Note that because there is no mA.pm I have had to write mA->import('gmorn') as the correct use mA 'gmorn' would fail.

package mB;

mA->import('gmorn');
use parent -norequire, 'mA';

use Sub::Exporter -setup => {
    exports => {
        gmorn => undef,
        gnite => \&build_gnite 
    }
};

sub build_gnite {
    my ( $class, $name, $arg ) = @_;
    return sub { say "$arg->{salutation}"; }
}



Update

There is no way to get the parameters to use Sub::Exporter to "pass through" multiple levels of use, because the import subroutine needs to call the generator function. So in your example mB::import needs to call mA::build_gmorn but it has no knowledge of that subroutine so it cannot be done.

The only convenient solution is to export both the generator and a generated subroutine, so that the calling code can either use the function or export a generated function itself.

This set of programs works fine.

mA.pm

use 5.010;
use warnings;

package mA;

use Sub::Exporter -setup => {
    exports => [
        'build_gmorn',
        gmorn => \&build_gmorn,
    ]
};

sub build_gmorn {
    my ( $class, $name, $arg ) = @_;
    return sub { say "$arg->{salutation}"; }
}

1;

mB.pm

use 5.010;
use warnings;

package mB;

use mA qw/ gmorn build_gmorn /;
use parent 'mA';

use Sub::Exporter -setup => {
    exports => [
        'build_gmorn', 
        gmorn => \&build_gmorn,
        'build_gnite', 
        gnite => \&build_gnite
    ]
};

sub build_gnite {
    my ( $class, $name, $arg ) = @_;
    return sub { say "$arg->{salutation}"; }
}

1;

mFr.pl

use 5.010;
use warnings;

package mFr;

use parent 'mB';

mB->import(
   gmorn => { salutation => 'Bon Jour' },
   gnite => { salutation => 'Bon Nuit' }
);

sub new { return bless {}, shift }

my $obj = mFr->new;

$obj->gmorn();
$obj->gnite();

output

Bon Jour
Bon Nuit
于 2013-02-06T16:32:05.427 回答