确定Moose属性和方法的继承地点?

时间:2015-03-06 00:42:56

标签: perl oop introspection moose

我经常在我的工作地点处理一个庞大的,没有很好记录的,面向对象的Perl回购。在维护代码的同时,我经常需要跟踪从其他类继承的内容,以便我能够理解他们正在做什么。例如,我需要弄清楚$self->mystery是什么以及它在做什么:

package Foo::Bar;
use Moose;
use Method::Signatures;
use Foo::Bar::Element;
use Foo::Bar::Function;
use base qw (Baz::Foo::Bar);

method do_stuff ($some_arg) {
    # mystery is not defined in Foo::Bar
    my $mystery = $self->mystery;
    $mystery->another_mystery($some_arg);
}

我经常发现自己花费太多时间来追踪父类。所以我的问题是,有一个简单的方法让我弄清$self->mystery来自哪里?或者换句话说,我需要找到声明神秘的地方。

通过"简单方法",我不是指使用ackgrep来搜索文件。我希望有一些我可以安装和使用的调试模块,这可以帮助我提供一些见解。

谢谢。

2 个答案:

答案 0 :(得分:5)

感谢Standard Perl。 。 。 comes_from方法!

你不需要下载任何特殊的工具或模块,更不用说一些巨大的IDE了,因为没有笨重的IDE,你的未记录的类结构变得太复杂,只有人类才能理解。

为什么不呢?简单:标准Perl包含您需要的一切以获得您正在寻找的答案。找出问题所在的简单方法是使用非常有用的comes_from方法:

$origin        = $self->comes_from("mystery");
$secret_origin = $self->comes_from("another_mystery");
$birthplace    = Some::Class->comes_from("method_name");

这将返回该方法将解析的子例程的原始名称。如您所见,comes_from同时作为对象方法和类方法,就像canisa一样。

请注意,当我说出它解析为的子例程的名称时,我指的是最初创建子例程的位置,在任何导入或继承之前。例如,此代码:

use v5.10.1;
use Path::Router;
my($what, $method) = qw(Path::Router dump);
say "$what->$method is really ", $what->comes_from($method);

打印出来:

Path::Router->dump is really Moose::Object::dump

类似的电话也会显示如下内容:

Net::SMTP->mail     is really Net::SMTP::mail
Net::SMTP->status   is really Net::Cmd::status
Net::SMTP->error    is really IO::Handle::error

它也适用于普通的ole子程序:

SQL::Translator::Parser::Storable->normalize_name 
 is really SQL::Translator::Utils::normalize_name

可爱的comes_from方法并非 完全 ,但它不需要标准Perl 之外的任何内容。为了使您和所有类和对象可以访问它,只需在某处添加这些代码 - 您真正喜欢的地方:)

sub UNIVERSAL::comes_from($$) {
    require B;
    my($invocant, $invoke) = @_;
    my $coderef  = $invocant->can($invoke) || return;
    my $cv       = B::svref_2object($coderef);
    return unless $cv->isa("B::CV");            
    my $gv       = $cv->GV;
    return if $gv->isa("B::SPECIAL");
    my $subname  = $gv->NAME;
    my $packname = $gv->STASH->NAME;
    return $packname . "::" . $subname;
}

通过声明为UNIVERSAL子,现在每个人都可以使用它,就像他们使用canisa一样。享受!

答案 1 :(得分:2)

您确定不需要IDE吗?这似乎是你在问什么。 PadreEclipse EPICEmacsvim以及许多其他编辑者对您提到的功能提供了一些变体 - 可能比您想要的更简单。如果您有大型项目导航ctags可以提供帮助 - 通常很容易将其集成到编辑器中,并且您可以使用 regexes BTW来破解配置文件以使其识别一组复杂的源文件。

有一个相关的PERL FAQ entry about IDEs和一个SO问题:What's a good development environment for Perl?。您还需要在开发时使用许多CPAN模块,以便以编程方式查看代码:

您可以看到一个脚本示例,该脚本在SO节点的类中查找方法:Get all methods and/or properties in a given Perl class or module

您可以使用这些工具来帮助您以一种从shell或调试器内部发现有用的方式在源代码中跳转。 Trepan有一个很好的调试工具简短摘要作为其文档的一部分。一般来说,Data::Dumper B:: modules B::XrefB::Deparseetc。{调试器和ack