Как перебрать все методы класса в Perl?
Как вы перебираете все методы класса в Perl? Есть ли хорошие онлайн-ссылки на Perl introspection или reflection?
6 ответов
рекомендация Тодда Гарднера использовать Moose-хорошая, но пример кода, который он выбрал, не очень полезен.
Если вы проверяете не-лося, используя класс, вы бы сделали что-то вроде этого:
use Some::Class;
use Class::MOP;
my $meta = Class::MOP::Class->initialize('Some::Class');
for my $meth ( $meta->get_all_methods ) {
print $meth->fully_qualified_name, "\n";
}
посмотреть Class::MOP:: Class docs для получения более подробной информации о том, как сделать самоанализ.
вы также заметите, что я использовал Class::MOP вместо Moose. Класс:: MOP (MOP = Meta-Object Protocol) - это база, на которой строится Moose. Если вы работа с классами без лося, использование лося для интроспекции ничего не дает.
Если бы вы хотели, вы могли бы use Moose ()
и Moose::Meta::Class->initialize
вместо CMOP.
вы можете легко получить список методов класса, используя ответы уже предоставлены. Однако Perl является динамическим языком, что означает, что позже может быть определено больше методов. На самом деле нет способа получить список всех методов, с которыми будет работать какой-либо конкретный класс. Для более подробной информации об этом виде вещей у меня есть несколько глав в Освоение Perl.
люди дают вам (и upvoting) ответы, не говоря вам о ограничения.
Адам упоминает его Класс::Инспектор, но это действительно не работает, потому что он пытается сделать то, что динамический язык не делает (и это статично :) например, вот фрагмент, где Class::Inspector не возвращает методов, но я все еще могу вызвать VERSION
метод (а также isa
и can
):
BEGIN {
package Foo;
our $VERSION = '1.23'
}
use Class::Inspector;
my $methods = Class::Inspector->methods( 'Foo' );
print "Methods are [@$methods]\n"; # reports nothing
print Foo->VERSION, "\n";
вот еще один случай, когда я могу вызвать любой метод, который мне нравится, но Class::Inspector возвращает только AUTOLOAD
(и еще отсутствует VERSION
, isa
и can
):
BEGIN {
package Foo;
our $VERSION = '1.23';
my $object = bless {}, __PACKAGE__;
sub AUTOLOAD { $object }
}
use Class::Inspector;
my $methods = Class::Inspector->methods( 'Foo' );
print "Methods are [@$methods]\n"; # reports only "AUTOLOAD"
print Foo->dog->cat->bird, "\n";
Любопытно, что все, кажется, игнорируют UNIVERSAL, вероятно, потому, что они явно не обрабатывают его, так как он только практически в @ISA. Я могу добавить debug
метод для каждого класса и Class::Inspector все еще пропускает его, Хотя это определенный метод:
BEGIN {
sub UNIVERSAL::debug { "Hello debugger!\n" }
package Foo;
}
use Class::Inspector;
my $methods = Class::Inspector->methods( 'Foo' );
print "Methods are [@$methods]\n"; # still reports nothing
print Foo->debug, "\n";
класс:: MOP имеет те же ограничения.
не каждый модуль будет использовать автозапуск, но это не неясно или редко особенность либо. Если вы не возражаете, что вы пропустите некоторые из методов, тогда Class::Inspector или Class:: MOP могут быть в порядке. Это просто не даст вам список всех методов, которые вы можете вызвать в классе или объекте в каждом случае.
если у вас есть класс или объект, и вы хотите знать, можете ли вы вызвать определенный метод, используйте can(). Оберните его в блок eval, чтобы can мог вызвать can() на вещи, которые даже не являются объектами, чтобы все еще получить обратно false, а не смерть, в тех случаи:
if( eval { $object->can( 'method_name' ) } )
{
$object->( @args );
}
в общем случае вам придется проверить таблицу символов (если вы не используете Moose). Например, чтобы перечислить методы, определенные в IO::File
пакет:
use IO::File;
no strict 'refs';
print join ', ', grep { defined &{"IO::File::$_"} } keys %{IO::File::};
хэш %{IO::File::}
таблица символов IO::File package
и grep
отфильтровывает записи, не относящиеся к подпрограммам (например, переменные пакета).
чтобы расширить это, чтобы включить унаследованные методы, вы должны рекурсивно искать таблицы символов родительских классов (@IO::File::ISA
).
здесь пример:
sub list_methods_for_class {
my $class = shift;
eval "require $class";
no strict 'refs';
my @methods = grep { defined &{$class . "::$_"} } keys %{$class . "::"};
push @methods, list_methods_for_class($_) foreach @{$class . "::ISA"};
return @methods;
}
для получения дополнительной информации о пакетах и таблицах символов см. perlmod man page.
зависит от того, имеете ли вы в виду какой-либо класс или реализуете свой собственный. Для последнего я использую Лось, который предлагает очень чистый синтаксис этих функций. Из Поваренной книги:--4-->
my %attributes = %{ $self->meta->get_attribute_map };
for my $name ( sort keys %attributes ) {
my $attribute = $attributes{$name};
if ( $attribute->does('MyApp::Meta::Attribute::Trait::Labeled')
# ... keeps on