简而言之,我想知道如何进行模块继承,就像base.pm/parent.pm为面向对象模块做的那样;仅适用于基于Exporter的模块.
我的意思的一个假设的例子:
这是我们的脚本.它最初加载了Foo.pm并从中调用了baz(),但是baz()有一个可怕的bug(我们很快就会看到),所以我们现在使用Local / Patched / Foo.pm来解决这个问题.我们这样做,因为在这个假设的情况下我们不能改变Foo(它是一个正在积极开发的cpan模块,你看),并且它是巨大的(严重的).
#!/usr/bin/perl # use Foo qw( baz [... 100 more functions here ...] ); use Local::Patched::Foo qw( baz [... 100 more functions here ...] ); baz();
这是Foo.pm.正如你所看到的,它导出了调用qux的baz(),它有一个可怕的bug,导致事情崩溃.我们希望保留baz和Foo.pm的其余部分,但没有做大量的复制粘贴,特别是因为它们可能会在以后更改,因为Foo仍在开发中.
package Foo; use parent 'Exporter'; our @EXPORT = qw( baz [... 100 more functions here ...] ); sub baz { qux(); } sub qux { print 1/0; } # !!!!!!!!!!!!! [... 100 more functions here ...] 1;
最后,由于Foo.pm用于很多地方,我们不想使用Sub :: Exporter,因为这意味着将bandaid修复程序复制粘贴到所有这些地方.相反,我们正在尝试创建一个新的模块,其行为和看起来像Foo.pm,并且实际上仍然从Foo.pm加载其99%的功能,并用更好的一个替换丑陋的qux子.
接下来是如果Foo.pm是面向对象的,那么这样的事情会是什么样子:
package Local::Patched::Foo; use parent 'Foo'; sub qux { print 2; } 1;
现在这显然不适用于我们目前的情况,因为parent.pm只是不做这种事情.
是否有一种干净而简单的方法来编写Local / Patched / Foo.pm(使用任何适用的CPAN模块),这种方法可以工作,而不是手动复制Foo.pm的函数命名空间?
解决方法
package Local::Patched::Foo; use Foo (); # load but import nothing sub Foo::qux { print "good qux"; }
这是有效的,因为Perl的包总是可变的,只要上面的代码在加载Foo.pm后出现,它就会覆盖现有的baz例程.你可能也不需要警告’重新定义’;沉默任何警告.
然后使用它:
use Local::Patched::Foo; use Foo qw( baz ); baz(); # calls the patched qux() routine
您可以通过在Local :: Patched :: Foo中编写自定义导入方法来消除这两个使用行,如下所示:
# in the Local::Patched::Foo package: sub import { return unless @_; # return if no imports splice @_,1,'Foo'; # change 'Local::Patched::Foo' to 'Foo' goto &{ Foo->can('import') }; # jump to Foo's import method }
然后就是:
use Local::Patched::Foo qw( baz ); baz(); # calls the patched qux()