简体   繁体   English

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

[英]Determine where Moose attributes and methods were inherited from?

I often work on a huge, not-very-well-documented, object-oriented Perl repo at my place of employment. 我经常在我的工作地点处理一个庞大的,没有很好记录的,面向对象的Perl回购。 While maintaining the code, I frequently need to trace things that are inherited from other classes so that I can understand what they're doing. 在维护代码的同时,我经常需要跟踪从其他类继承的内容,以便我能够理解他们正在做什么。 For example, I need to figure out what $self->mystery is and what it's doing: 例如,我需要弄清楚$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);
}

I usually find myself spending way too much time tracing through parent classes. 我经常发现自己花费太多时间来追踪父类。 So my question is, is there an easy way for me to figure out where $self->mystery comes from? 所以我的问题是,有一个简单的方法让我弄清楚$self->mystery来自哪里? Or in other words, I need to find where mystery is declared. 或者换句话说,我需要找到声明神秘的地方。

And by "easy way", I don't mean using ack or grep to string search through files. 通过“简单的方法”,我并不是说使用ackgrep来搜索文件。 I'm hoping there's some sort of debugging module I can install and use which could help give me some insight. 我希望有一些我可以安装和使用的调试模块,这可以帮助我一些见解。

Thank you. 谢谢。

Thanks to Standard Perl . 感谢Standard Perl。 . . the comes_from Method! comes_from方法!

You don't need to download any special tool or module this, let alone some giant IDE because your undocumented class structure has gotten too complicated for mere humans ever to understand without a hulking IDE. 你不需要下载任何特殊的工具或模块,更不用说一些巨大的IDE,因为你的未记录的类结构已经变得太复杂,只有人类才能理解而没有笨重的IDE。

Why not? 为什么不? Simple: Standard Perl contains everything you need to get the answer you're looking for. 简单: 标准Perl包含您获得所需答案所需的一切 The easy way to find out where something comes from is to use the very useful comes_from method: 找出问题来源的简单方法是使用非常有用的comes_from方法:

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

That will return the original name of the subroutine which that method would resolve to. 这将返回该方法将解析的子例程的原始名称。 As you see, comes_from works as both an object method and a class method, just like can and isa . 如您所见, comes_from可以作为对象方法, comes_from可以作为类方法,就像canisa

Note that when I say the name of the subroutine it resolves to, I mean where that subroutine was originally created, back before any importing or inheritance. 请注意,当我说出它解析为的子例程的名称时,我指的是最初创建子例程的位置,在任何导入或继承之前。 For example, this code: 例如,这段代码:

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

prints out: 打印出来:

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

Similar calls would also reveal things like: 类似的电话也会发现:

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

It works just fine on plain ole subroutines, too: 它也适用于普通的ole子程序:

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

The lovely comes_from method isn't quite built in though it requires nothing outside of Standard Perl . 可爱的comes_from方法并不是完全内置的,尽管它不需要标准Perl之外的任何东西。 To make it accessible to you and all your classes and objects and more, just add this bit of code somewhere — anywhere you please really :) 为了使您和您的所有类和对象可以访问它,只需在某处添加这些代码 - 您真正喜欢的任何地方:)

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;
}

By declaring that as a UNIVERSAL sub, now everybody who's anybody gets to play with it, just like they do with can and isa . 通过声明作为UNIVERSAL子,现在每个人都可以使用它,就像他们使用canisa Enjoy! 请享用!

Are you sure you don't want an IDE? 您确定不需要IDE吗? It seems to be what you are asking about. 这似乎是你在问什么。 Padre , Eclipse EPIC , Emacs , and vim and many other editors offer some variation on the features you mention - probably simpler than you seem to want. PadreEclipse EPICEmacsvim以及许多其他编辑器对您提到的功能提供了一些变化 - 可能比您想要的更简单。 If you have big project to navigate ctags can help - it's usually easy to integrate into an editor and you are allowed to hack on your configuration file (with regexes BTW) to get it to recognize bits of a complicated set of source files. 如果您有大型项目导航ctags可以提供帮助 - 通常很容易集成到编辑器中,您可以破解配置文件(使用正则表达式 BTW),以使其识别一组复杂的源文件。

There is a related PERL FAQ entry about IDEs and a SO question: What's a good development environment for Perl? 有一个关于IDE的相关PERL FAQ条目和一个SO问题: Perl的开发环境是什么? . There are also a host of CPAN modules you will want to use when developing that let you look into your code programmatically: 您还需要在开发时使用许多CPAN模块,以便以编程方式查看代码:

You can see an example of a script that looks for methods in classes in the SO node: Get all methods and/or properties in a given Perl class or module . 您可以看到一个脚本示例,该脚本在SO节点的类中查找方法: 获取给定Perl类或模块中的所有方法和/或属性

You might be able to get tools like these to help you hop around in your source in a way you find useful from a shell or from inside the debugger. 您可以使用这些工具来帮助您以一种从shell或调试器内部发现有用的方式在源代码中跳转。 Trepan has a good short summary of debugging tools as part of its documentation. 作为文档的一部分, Trepan对调试工具有一个很好的简短总结。 Generally though you can be very productive combining Data::Dumper the B:: modules ( B::Xref , B::Deparse , etc. , etc .) with the debugger and ack . 但是总的来说,你可以非常高效结合Data::DumperB::模块B::XrefB::Deparse等等等等 。)与调试器和ack

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM