Perl 如何将方法修改器应用于自动加载生成的方法?

Perl 如何将方法修改器应用于自动加载生成的方法?,perl,autoload,moose,method-modifier,Perl,Autoload,Moose,Method Modifier,我有一个非常有趣的困境。我正在开发CVS存储库的Perl脚本接口,并创建了Perl对象来表示模块,路径,以及文件。由于模块、路径和文件都可以对其发出CVS命令,因此我设置了自动加载例程,以采用任何未识别的方法,并在对象上发出它们,就像它们是CVS命令一样 所有这些CVS命令都以完全相同的方式执行,但其中一些命令需要对输出进行特殊处理,以获得我想要的结果 例如,我想从diff命令获取输出,并在返回之前重新格式化它 我使用的是Moose,因此这种特殊处理通常可以按如下方式进行: after 'di

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

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


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

我使用的是
Moose
,因此这种特殊处理通常可以按如下方式进行:

after 'diff' => sub {
    # Reformat output here
}
问题是。。。我从未显式创建过
diff
方法,因为它是由
AUTOLOAD
生成的,Perl不允许我为它创建方法修饰符,因为它在技术上不存在

有没有办法让它按照我的意愿工作?


after
应用于
自动加载方法

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 '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(@_);
    }
};
这允许您在调用函数之前和之后执行特殊处理


有关更多信息,请参见:

根据
自动加载
-使用类的实现情况,您可能会发现它也尊重
can
方法,只需调用
can
就足以创建该方法

__PACKAGE__->can( "diff" );
after diff => sub { ... };

我建议您重新构建您的系统以使用traits,而不是依赖于自动加载行为。如果你不让行为分散在各处,那么可维护性和意图将更加明显

例如,您可以通过以下方式做您想做的事情:

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;

如果您希望使用自动加载来分派未知命令,那么这是危险的,因为可能会有一些您不知道的命令需要特殊处理,因此您可能会给自己带来未来的问题。

如果您的自动加载子命令创建了正在自动加载的符号(这样就不会再为该符号调用自动加载),这只是在
之后调用
的问题(这只是一个正常的子例程)创建符号后。在创建符号后如何执行此操作?如果我只是尝试在
之后使用
,则表示在继承层次结构中找不到方法“diff”。然后您没有创建符号(
diff
),或者你从错误的软件包中调用了
之后的
,那么你的意思是定义类似
*diff
?我没有太多的符号。但是你正在编写一个自动加载,其目的是“加载”符号…我将对此进行研究,但我使用
自动加载
的主要原因是因为有很多CVS命令,我不想手动实现它们。如果试图调用无效的CVS命令,它会将该命令传递给CVS,CVS会返回一个错误,说它是无效的命令。我真的很喜欢它他的方法是因为它将
自动加载
ed命令的任何特殊处理都集中在一个地方。感谢@mob!这似乎不适用于
驼鹿
类不幸的是:(