我正在处理一个明显的简单问题。
我正在编写一个类似于UML::Class::Simple的模块,但有一些改进。总而言之,我们的想法是为给定源中的每个模块检索记录卡,其中包含有关方法,属性,依赖关系和子项的信息。我目前的问题是获取每个模块的方法和属性。让我们看看我已编写的代码:
use Class::Inspector;
use Data::Dumper;
sub _load_methods{
my $pkg = shift;
my $methods = Class::Inspector->methods( $pkg, 'expanded' );
print Dumper $methods;
return 1;
}
为给定的包调用此函数,我得到的方法比我预期的多。原因是Class::Inspector返回所有继承的方法,如果模块是Moose :: Object,则返回访问器。我想过滤所有这些方法,只获得给定包中定义的方法,而不是父类。
有人能提供一种优雅的方式来按我建议的方式过滤方法列表吗?
提前致谢。
答案 0 :(得分:4)
如果某个班级是Moose班级,请勿使用Class :: Inspector 进行检查。 Moose提供了自己的非常广泛的内省API。它可以为您提供方法,属性等列表。
my $meta = Moose::Util::find_meta($class_name);
my @isa = $meta->superclasses;
my @does = $meta->calculate_all_roles;
my @can = $meta->get_method_list;
my @has = $meta->get_attribute_list;
所有这些的文档很遗憾地分散在很多不同的页面上。 Moose::Meta::Class不是一个糟糕的起点。
鼠标提供了几乎但不完全相同的内省API。
Moo不提供自己的内省API,但如果加载Moose会挂钩到Moose的API,以便您可以使用Moose::Util::find_meta
检索有关Moo类的信息。
答案 1 :(得分:3)
感谢@Oesor,他向我介绍了模块Data :: Printer,其中包含我的问题源代码解决方案,以及@tobyink,它给了我解析Moose的密钥我提出了以下解决方案:
sub _load_methods_for_one_pkg {
# Inspired in Data::Printer::_show_methods
# Thanks to Oesor
my $pkg = shift;
my $string = '';
my $methods = {
public => [],
private => [],
};
my $inherited = 'none';
require B;
my $methods_of = sub {
my ($name) = @_;
map {
my $m;
if ( $_
and $m = B::svref_2object($_)
and $m->isa('B::CV')
and not $m->GV->isa('B::Special') )
{
[ $m->GV->STASH->NAME, $m->GV->NAME ];
}
else {
();
}
} values %{ Package::Stash->new($name)->get_all_symbols('CODE') };
};
my %seen_method_name;
METHOD:
foreach my $method ( map $methods_of->($_), @{ mro::get_linear_isa($pkg) } ) {
my ( $package_string, $method_string ) = @$method;
next METHOD if $seen_method_name{$method_string}++;
my $type = substr( $method_string, 0, 1 ) eq '_' ? 'private' : 'public';
if ( $package_string ne $pkg ) {
next METHOD
unless $inherited ne 'none'
and ( $inherited eq 'all' or $type eq $inherited );
$method_string .= ' (' . $package_string . ')';
}
push @{ $methods->{$type} }, $method_string;
}
# If is a Moose object, we have more things to do!
if( grep 'Moose', @{ $self->dependencies->{ $pkg } }){
my ($roles, $this_methods, $properties) = _parse_moose_class($pkg);
push @{ $methods->{properties} }, @$properties;
push @{ $methods->{roles} }, @$roles;
}
return $methods;
}
=head2 _parse_moose_class
=cut
sub _parse_moose_class{
my $pkg = shift;
my $meta = Moose::Util::find_meta($pkg);
my @does = $meta->calculate_all_roles;
my @can = $meta->get_method_list;
my @has = $meta->get_attribute_list;
return ( \@does, \@can, \@has );
}