4

我有一个非常有趣的困境。我正在开发 CVS 存储库的 Perl 脚本接口,并创建了 Perl 对象来表示ModulesPathsFiles. 由于ModulesPathsFiles都可以对它们发出 CVS 命令,因此我设置了AUTOLOAD例程以采用任何未识别的方法并在对象上发出它们,就好像它们是 CVS 命令一样。

所有这些 CVS 命令都以完全相同的方式执行,但其中一些需要对输出进行特殊处理才能获得我想要的结果。


例如,我想从 diff 命令获取输出并在返回之前重新格式化它。

我正在使用Moose,因此通常可以按如下方式完成此特殊处理:

after 'diff' => sub {
    # Reformat output here
}

问题是……我从来没有明确地创建过这个diff方法,因为它是由 Perl 生成的,AUTOLOAD而且 Perl 不会让我为它创建一个方法修饰符,因为它在技术上不存在!

有没有办法让它按我想要的方式工作?

4

3 回答 3

3

适用after于您的AUTOLOAD方法。

after 'AUTOLOAD' => sub {
    my $method = $The::Package::AUTOLOAD;
    $method =~ s/.*:://;
    if ($method eq 'diff') {
        # do  after diff  stuff
    } elsif ($method eq 'foo') {
        # do  after foo  stuff
    } else {
        # never mind, don't want to do anything after this function
    }
};

编辑:

我发现我可能想要更多地控制diff命令,所以我在你的答案中添加了更多细节。希望有人会发现这些信息有用。

为了获得更多控制,您可以使用around

around 'AUTOLOAD' => sub {
    my $orig = shift;
    my $self = shift;
    (my $command = $AUTOLOAD) =~ s{.+::}{};

    # Special processing
    if ($command eq 'diff') {

        #
        # Add "before" special processing here
        #

        my $output = $self->$orig(@_);

        #
        # Add "after" special processing here
        #

    }
    else {
        return $self->$orig(@_);
    }
};

这允许您在调用函数之前和之后进行特殊处理。

有关更多信息,请参阅:Moose::Manual::MethodModifiers

于 2015-09-11T20:59:49.390 回答
0

根据AUTOLOAD-using 类的实现程度,您可能会发现它也尊重can方法,并且简单地调用can就足以创建方法。

__PACKAGE__->can( "diff" );
after diff => sub { ... };
于 2015-09-12T12:29:10.503 回答
0

我建议您重新构建系统以使用特征,而不是依赖 AUTOLOAD 行为。如果您没有分散在各处的行为,可维护性和意图将更加明显。

例如,您可以使用以下内容执行您想要的操作:

package Trait::CVSActions;

use Moose::Role;

sub commit { print 'in commit for ' . shift . "\n" }

sub diff { print 'diffing for ' . shift . "\n" }

package Module;

use Moose;

with 'Trait::CVSActions';

package Path;

use Moose;

with 'Trait::CVSActions';

after commit => sub { print "after commit on Path\n" };

package main;

my $module = new Module;
my $path = new Path;

$module->commit;
$path->commit;

如果您希望使用 AUTOLOAD 来分派未知命令,那么这很危险,因为您可能需要对某些您不知道的特殊处理进行处理,因此您可能会为自己带来未来的问题。

于 2015-09-12T21:36:55.570 回答