确定从哪里继承了 Moose 属性和方法?

Determine where Moose attributes and methods were inherited from?

我经常在我工作的地方处理一个巨大的 not-very-well-documented、object-oriented 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);
}

我经常发现自己花了太多时间在 parent 类 上进行追踪。所以我的问题是,有没有一种简单的方法可以让我弄清楚 $self->mystery 来自哪里?或者换句话说,我需要找到宣布神秘的地方。

"easy way",我并不是说使用 ackgrep 在文件中进行字符串搜索。我希望有某种我可以安装和使用的调试模块,它可以帮助我获得一些见解。

谢谢。

您确定不想要 IDE 吗?这似乎是你要问的。 Padre, Eclipse EPIC, Emacs , and vim 和许多其他编辑器提供了您提到的功能的一些变化 - 可能比您想要的更简单。如果你有大项目需要导航 ctags 可以提供帮助 - 它通常很容易集成到编辑器中,你可以修改你的配置文件(使用 regexes BTW)来获得它可以识别一组复杂的源文件的位。

有一个相关的PERL FAQ entry about IDEs and a SO question: 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 has a good short summary of debugging tools as part of its documentation. Generally though you can be very productive combining Data::Dumper the B:: modules (B::Xref , B::Deparse, etc., etc.) 与调试器和 ack

感谢标准 Perl。 . . comes_from 方法!

你不需要下载任何特殊的工具或模块,更不用说一些巨大的 IDE 因为你的未记录的 class 结构已经变得太复杂了,人类如果不笨重就无法理解IDE.

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

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

这将 return 该方法将解析为的子例程的原始名称。如您所见,comes_from 既作为对象方法又作为 class 方法,就像 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。为了让您和您的所有 classes 和对象以及更多东西都可以访问它,只需在某处添加这段代码 — 任何您喜欢的地方:)

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 一样。享受吧!