2

我有一个模块,它为它所属的包定义异常。异常是用 声明的Exception::Class::Nested

出于讨论的目的,假设该模块名为Foo::Bar::Exception,并且它定义的所有异常都是该模块的第一级子类(例如Foo::Bar::Exception:DoNotDoThat)。我关心的所有异常都在这个模块文件中定义;我对任何其他模块对我所做的任何额外的子类化都不感兴趣。

对于我的import方法,我想构建一个所有正在定义的异常的列表,并且我想通过以某种方式遍历符号表来做到这一点,而不是保持一个可能与定义不同步并且具有需要人工维护。

那么,如何Foo::Bar::Exception->import遍历Foo::Bar::Exception的符号表,找到模块中已经声明的所有异常(一级子类)呢?这只是我感兴趣的活动加载符号表;没有文件系统搜索等。

谢谢!

[附录]

由于我所有的异常子类名称都以Exceptionor结尾Error,这看起来越来越接近我想要的:

my %symtable = eval("'%' . __PACKAGE__ . '::'");
my @shortnames = grep(m!(?:Error|Exception)::$!, keys(%symtable));
@shortnames = ( map { $_ =~ s/::$//; $_; } @shortnames );
my @longnames = ( map { __PACKAGE__ . '::' . $_ } @shortnames );

一些括号是不必要的,但我添加它是为了清楚地了解数组上下文。

4

3 回答 3

1
use MRO::Compat;
my @classes = @{ mro::get_isarev("Foo::Bar::Exception") };
@classes = grep $_->isa("Foo::Bar::Exception"), @classes;

MRO::Compat在 5.10 之前的 perls 上启用mro API,否则不会有它(尽管在 5.10+get_isarev快得多),get_isarev返回从命名类(直接或间接)继承的类,最后的 grep 是因为get_isarev是一种启发式的函数——它永远不会错过一个继承了你指定的类的类,但是面对运行时@ISA修改它可能会报告一个实际上不再继承你的类的类。所以->isa检查确保类仍然存在并且仍然是子类。

编辑:刚刚注意到您只对命名空间下的包感兴趣的部分,但我仍然认为使用 mro API 是找到它们的良好基础——只需加上 a grep /^Foo::Bar::Exception::/:)

于 2011-03-07T02:23:01.200 回答
1

The symbol table for Foo::Bar::Exception is %Foo::Bar::Exception::, so you could write:

sub import {
    for my $key (keys %Foo::Bar::Exception::) {
        if (my ($name) = $key =~ /(.+)::$/) {
           my $pkg = 'Foo::Bar::Exception::'.$name;
           no strict 'refs';
           *{caller()."::$name"} = sub () {$pkg};
        }
    }
}
于 2011-03-07T01:46:25.430 回答
0

由于继承问题(显然由Exception::Classor引入Exception::Class::Nested),我选择了纯符号表路线。

长名称(例如Foo::Bar::Exception:DoNotDoThat)和短名称(DoNotDoThat)都是可导出的;默认情况下会导出长名称。(不清楚这是否有必要,但似乎没有害处。)

如果要导出短名称,这可以解决问题:

my $caller = caller();
$caller ||= 'main';
my @snames = @{$EXPORT_TAGS{shortnames}};
for my $short (@snames) {
    my $exc = __PACKAGE__ . '::' . $short;
    no strict 'refs';
    *{"$caller\::$short"} = sub () { $exc };
}

这与@Eric 的答案非常接近,但在我看到他之前就派生了。

感谢大家!

于 2011-03-09T21:14:05.507 回答