Perl Advent Calendar 2011-12-10

Exporter::Auto

by Fayland Lam

Exporter::AutoExporter 的 enhanced 版本。它默认将您代码里的 subs 导入到 @EXPORT 里,免去了您在 @EXPORT 里人工添加和删除 sub 的烦恼。

该模块今天新鲜出炉,功能方便有某些缺陷,比如您不能控制弄到 @EXPORT_OK (有兴趣的童鞋可以给作者发送 patch, 通过传递 import 参数来配置),比如您不能将 $, @, % 自动或者额外加到 @EXPORT 里,但是该模块还是非常方便的完成了一个既定的任务,将所有的 subs 自动导出。

尤其是代码非常简洁优雅,所以想和诸位共享一下。(中文注释是本人添加)

package Exporter::Auto;
use strict;
use warnings;
use 5.008005;
our $VERSION = '0.01';

use Sub::Identify qw(stash_name);
use B::Hooks::EndOfScope;
use Exporter; # 该行并无必要

sub import {
    my $klass = caller(0); # 得到该调用模块的名字

    no strict 'refs';
    unshift @{"${klass}::ISA"}, 'Exporter'; # 将 Exporter 当成目标模块的父类

    on_scope_end { # 在编译该块代码结束马上运行,因为在 runtime 时会无效
        while (my ($k, $v) = each %{"${klass}::"}) {
            next if $k =~ /^(?:BEGIN|CHECK|END)$/; # 跳过一些 Perl 自带的 sub, 因为都没必要导入。可能需要更多的如 INIT, DESTORY, AUTOLOAD 等。
            next if $k =~ /^_/; # 不导入私有函数
            next unless *{"${klass}::${k}"}{CODE}; # 只导入代码,不导入 scalar, array, hash 等
            next if $klass ne stash_name($klass->can($k)); # 只导入属于调用模块的,而非调用模块所导入的额外sub
            push @{"${klass}::EXPORT"}, $k; # 添加到 @EXPORT
        }
    };
}


1;
__END__

非常简洁优雅。use Exporter::Auto; 就等同于 unshift @MYCLASS::ISA, 'Exporter'; @MYCLASS::EXPORT = ('all-my-subs');

每一行都起作用,又能非常完美地完成既定任务。多阅读阅读类似的代码,对 Perl 的学习提升非常有帮助。

PS,阅读模块的代码别忘了阅读模块的 .t 文件。

谢谢。

View Source (POD)