RoU*_*oUS 1 perl exception-handling namespaces packages perl-module
我正在开发一个Exception::Class::Nested为其"父"包定义异常(使用)的包.我不希望父包必须使用真正的长名称,并且我不想污染任何其他命名空间.
所以我想要做的是将类名的最后一个元素导出到use异常包的包的名称空间中.
例如,异常包的摘录:
package Klass:Foo::Bar::Exceptions;
use vars qw( @ISA @EXPORT @EXPORT_OK ... );
@ISA = qw( Klass::Foo::Bar Exporter );
use Exception::Class::Nested 0.04 (
'Klass::Foo::Bar::Exceptions::BaseClass' => {
description => 'Base class for exceptions',
'Klass::Foo::Bar::Exceptions::NameError' => {
error => "I don't like your face"
}
}
);
Run Code Online (Sandbox Code Playgroud)
'父母'包裹:
package Klass::Foo::Bar;
use Klass::Foo::Bar::Exceptions;
Klass::Foo::Bar::Exceptions::NameError->throw(error => "D'oh!");
my $e = NameError->new(error => 'Mwahaha!');
Run Code Online (Sandbox Code Playgroud)
我想导出/导入,使得第二调用(的异常类my $e之一)的作品,就好像NameError是在定义Klass::Foo::Bar,但我还没有想通出来呢.
(并且在任何人说'但Exception::Class有一个漂亮的alias东西之前' ,我会指出别名是专门与异常的throw方法相关联的,所以我不能将它用于非自动抛出的new调用..)
有一两件事我想是把这个在异常封装的importer子(@snames或者是完全合格的异常类(数组例如,'Klass::Foo::Bar::Exceptions::NameError'),或者只是尾部(例如,'NameError'):
my $caller = caller();
$caller ||= 'main';
my @snames = @{$EXPORT_TAGS{exceptions}};
for my $exc (@snames) {
$exc =~ s/^.*:://;
no strict qw(subs refs);
*{"${caller}\:\:${exc}\:\:"} = \*{__PACKAGE__ . "\:\:${exc}\:\:"};
}
Run Code Online (Sandbox Code Playgroud)
但这最终要求我使用Klass::Foo::Bar::NameError而不仅仅是调用异常NameError.它似乎有效,但太好了.
我不希望导入NameError到main::!
我担心,Typeglobs和符号表对我来说仍然有点神秘.
我确信有一种方法可以做我想做的事情(或者我正在做一些我不应该完全做的事情,但让我们暂时不管它).谁能帮我这个?
谢谢!
在您的示例import子项中,您正在对包存储器进行别名处理,这不会执行您想要的操作.相反,您希望创建具有返回完整包名称的缩写名称的子例程:
sub import {
my $caller = caller;
for my $long (@{$EXPORT_TAGS{exceptions}}) { # for each full name
my ($short) = $long =~ /([^:]+)$/; # grab the last segment
no strict 'refs';
*{"$caller\::$short"} = sub () {$long}; # install a subroutine named
# $short into the caller's pkg
# that returns $long
}
}
Run Code Online (Sandbox Code Playgroud)
打破最后一行,sub () {$long}创建一个不带参数的匿名子程序.代码引用包含单个变量$long,该变量保留循环迭代期间的值.这称为词法闭包,这基本上意味着只要子程序执行,子程序的编译环境($long及其值)将持续存在.
然后使用$short名称将此匿名子例程安装到调用者的包中.在调用者的包子程序的全名是caller::subname,其"$caller\::$short"构造.然后将其解除引用为typeglob *{ ... }.使用引用分配给typeglob填充typeglob的那个槽.因此,分配代码引用会安装子例程.
换句话说,以下子程序声明:
sub short () {'a::long::name'}
Run Code Online (Sandbox Code Playgroud)
意思是:
BEGIN {*{__PACKAGE__.'::short'} = sub () {'a::long::name'}}
Run Code Online (Sandbox Code Playgroud)