2011年12月9日星期五

[PerlChina] 2011 CN Perl Advent Day 10: Exporter::Auto

http://perlchina.github.com/advent.perlchina.org/2011/Exporter_Auto.html 

=for advent_year 2011

=for advent_day 10

=for advent_title Exporter::Auto

=for advent_author Fayland Lam

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

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

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

=begin pre

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__

=end pre

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

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

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

谢谢。


--
Fayland Lam // http://www.fayland.org/

--
您收到此邮件是因为您订阅了 Google 网上论坛的“PerlChina Mongers 讨论组”论坛。
要向此网上论坛发帖,请发送电子邮件至 perlchina@googlegroups.com。
要取消订阅此网上论坛,请发送电子邮件至 perlchina+unsubscribe@googlegroups.com。
若有更多问题,请通过 http://groups.google.com/group/perlchina?hl=zh-CN 访问此网上论坛。

没有评论: