如何在 Perl 中重命名导出函数?

发布于 2024-07-17 12:30:55 字数 502 浏览 8 评论 0原文

我有一些导出各种函数的 Perl 模块。 (我们已经有几年没有在新模块中使用@EXPORT了,但为了与旧脚本兼容而保留了它。)

我重命名了许多函数和方法以更改为一致的命名策略,并认为然后添加一个列表 这样的行

*directory_error      = *directoryError;

像模块末尾

只会将旧名称别名为新名称。 这是有效的,除非导出旧名称,并且调用脚本使用非限定名称调用函数:在这种情况下,它报告未找到子例程(在调用模块中)。

我猜想发生的情况是,当别​​名尚未创建时,Exporter 在 BEGIN 中准备列表; 但我尝试将 typeglob 赋值放在 BEGIN 块中,但这没有帮助。

我已经尝试过 AUTOLOAD,但是当然这不会使该名称在调用上下文中可用。 当然,我可以编写一系列包装函数,但这很乏味。 我有可能自动生成包装函数,尽管我不确定如何生成。

有什么建议可以解决这个问题?

I have some Perl modules which exports various functions. (We haven't used @EXPORT in new modules for some years, but have retained it for compatibility with old scripts.)

I have renamed a number of functions and methods to change to a consistent naming policy, and thought that then adding a list of lines like

*directory_error      = *directoryError;

at the end of the module would just alias the old name to the new.

This works, except when the old name is exported, and a calling script calls the function with an unqualified name: in this case, it reports that the subroutine is not found (in the calling module).

I guess that what is happening is that Exporter prepares the list in a BEGIN, when the alias has not been created; but I tried putting the typeglob assignment in a BEGIN block and that didn't help.

I've tried AUTOLOAD, but of course that does not make the name available in the calling context. Of course I could write a series of wrapper functions, but that is tedious. It's possible I could generate wrapper functions automatically, though I'm not sure how.

Any suggestions of a neat way of handling this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

墟烟 2024-07-24 12:30:55

导出

手动调用 @EXPORT =() 的东西变得有点憔悴。

package Bar;
use strict;
use warnings;

use Sub::Exporter -setup => {
    exports => [qw[ foo ]],
    groups  => {
        default => [qw[ foo ]],
    }
};

sub foo(){

};


1;

使用:

use strict;
use warnings;
use Bar  foo => { -as-> 'Foo' }; 

Sub::Exporter 可以做很多很棒的事情,比如组导出、组排除、构建器方法(即:它导出的子程序如何工作是由传递的参数确定的,并且子程序是在其他子程序内部生成的,等等)

重命名

对于重命名,最好有一个辅助函数,它只是作为 Carp() 调用时推荐代码的遗留函数这表明它到处都可以转移到新方法。 这将提高代码范围内的一致性。

然后,当您的测试停止发出警告时,您可以删除遗留功能。

sub old {  # line 1
   Carp::carp('Legacy function \'old\' called, please move to \'newmethod\' '); 
   goto &newmethod; # this passes @_ literally and hides itself from the stack trace. 
} # line 4

sub newmethod { # line 6
   Carp::cluck('In New Method'); 
   return 5;
} # line 9

print old(), "\n";  # line 11
Legacy function 'old' called, please move to 'newmethod' at code.pl line 2
    main::old() called at code.pl line 11
In New Method at code.pl line 7
    main::newmethod() called at code.pl line 11
5

请注意 newmethod 中的警告看起来与直接调用它们完全相同。

Exporting

Manually calling @EXPORT =() stuff is getting a bit haggard.

package Bar;
use strict;
use warnings;

use Sub::Exporter -setup => {
    exports => [qw[ foo ]],
    groups  => {
        default => [qw[ foo ]],
    }
};

sub foo(){

};


1;

Use:

use strict;
use warnings;
use Bar  foo => { -as-> 'Foo' }; 

Sub::Exporter can do lots of awesome stuff, like group exports, group exclusion, builder methods ( Ie: how the subs it exports work are determined by passed parameters , and the subs are generated inside other subs, etc )

Renaming

For renaming things it might be better to have a secondary function which just stands as a legacy function that Carp()s when its called to recommend the code that points to it everywhere to be moved to the new method. This will increase consistency codewide.

Then when your tests stop spouting forth warnings, you can remove the legacy function.

sub old {  # line 1
   Carp::carp('Legacy function \'old\' called, please move to \'newmethod\' '); 
   goto &newmethod; # this passes @_ literally and hides itself from the stack trace. 
} # line 4

sub newmethod { # line 6
   Carp::cluck('In New Method'); 
   return 5;
} # line 9

print old(), "\n";  # line 11
Legacy function 'old' called, please move to 'newmethod' at code.pl line 2
    main::old() called at code.pl line 11
In New Method at code.pl line 7
    main::newmethod() called at code.pl line 11
5

Note how the warnings in newmethod look exactly like they'd been called directly.

最好是你 2024-07-24 12:30:55

以下内容对我有用。 这似乎就是你所描述的; 你一定是在某个地方犯了错误。

主要脚本:

use strict;
use warnings;
use Bar;

baz();

模块:

package Bar;
use strict;
use warnings;

require Exporter;
our @ISA    = qw(Exporter);
our @EXPORT = qw(baz);

sub Baz { print "Baz() here\n" }

*baz = *Baz;

1;

The following works for me. This seems to be what you're describing; you must have made a mistake somewhere.

Main script:

use strict;
use warnings;
use Bar;

baz();

Module:

package Bar;
use strict;
use warnings;

require Exporter;
our @ISA    = qw(Exporter);
our @EXPORT = qw(baz);

sub Baz { print "Baz() here\n" }

*baz = *Baz;

1;
梦里兽 2024-07-24 12:30:55

如果您希望两个名称都可见,则必须导出这两个名称。 使用迈克尔·卡曼的答案作为基础,您需要

our @EXPORT = qw(Baz baz);

our @EXPORT    = qw(Baz);
our @EXPORT_OK = qw(baz);

如果您希望能够在程序中调用其中之一。 仅仅因为它们指向相同的 coderef 并不意味着该 coderef 的所有名称都会在导出时导出。

You must export both names if you want both names to be visible. Using Michael Carman's answer as a base, you need

our @EXPORT = qw(Baz baz);

or

our @EXPORT    = qw(Baz);
our @EXPORT_OK = qw(baz);

if you want to be able to call either one in the program. Just because they point to the same coderef does not mean all names for that coderef will be exported when one is.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文