别名包以启用双用途命名空间

时间:2011-02-07 21:52:13

标签: perl namespaces

我有一个有趣的情况。在一些(大型)遗留代码中,有一个名称空间应该看起来像require A::B,但是添加了A的路径,因此可以只说require B。但是,我希望能够使用这两种调用。这是否可以在不创建重定向包的情况下实现?例如,有没有办法双重声明一个包?

谢谢!

3 个答案:

答案 0 :(得分:16)

首先加载包:

require A::B;

然后将B别名改为A::B

*B:: = *A::B::;

然后告诉require它已加载B

$INC{'B.pm'}++;

为了确保一切正常,最好在BEGIN块内执行这些操作:

BEGIN {
    require A::B;
    *B:: = *A::B::;
    $INC{'B.pm'}++;
}

在此之后,所有require A::B;require B;行都将变为无操作。您还可以使用任一名称引用该包中的变量。 \&A::B::foo == \&B::foo

为了使透明工作,您可以将以下代码添加到每个文件中:

  • A/B.pm

    *B:: = *A::B::;
    $INC{'B.pm'}++;
    
  • B.pm

    *A::B:: = *B::;
    $INC{'A/B.pm'}++;
    

然后,如果用户require A::B;,他们可以致电A::B::fooB::foorequire B;将成为无操作。

如果用户require B;,他们可以致电A::B::fooB::foorequire A::B;将成为无操作。

但是为了可维护性,最好将所有实际代码保存在一个文件中(连同上面的别名代码),并将另一个文件设置为仅加载真实文件的填充程序。假设A/B.pm包含真实代码:

  • A/B.pm

    *B:: = *A::B::;  # this gets added to the existing file
    $INC{'B.pm'}++;
    
  • B.pm

    require A::B;  # this is the entire file
    

答案 1 :(得分:2)

require Something将在@INC中的目录中搜索名为Something.pm的文件。 要让some-path/A/B.pm加载require Brequire A::B,您需要在some-path目录列表中同时包含some-path/A@INC

many many ways添加目录或以其他方式操纵您的@INC列表。

答案 2 :(得分:1)

Eric的解决方案可行,但说实话,我会拍摄任何在真实生产代码中执行此操作的人。您可以通过使用Package::Stash中的方法获得类似的结果,但同样,为什么要像这样弄乱符号表呢?我宁愿修复那些调用错误方式的遗留代码。说真的,对代码进行搜索和替换以及修改软件包名称有多难?

require B;实际找到包A :: B的另一个快速而简单的方法是简单地在lib /目录中创建指向A / B.pm的符号链接:

cd lib
ln -sf -T A/B.pm B.pm

请注意,这将创建具有相同代码的两个包,因此一个中的变量与另一个相同:$A::B::foo将完全相同即使它们的声明来自同一个文件,也要与$B::foo分开。