Perlのクラスのすべてのメソッドをどのようにループしますか?Perlの内省または考察への良いオンライン参照はありますか?
6 に答える
Todd GardnerがMooseを使用するために推奨したものは良いものですが、彼が選択したサンプルコードはあまり役に立ちません。
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のドキュメントを参照してください。
また、Mooseの代わりにClass::MOPを使用したことにも注意してください。Class :: MOP(MOP =メタオブジェクトプロトコル)は、Mooseが構築するベースです。Moose以外のクラスで作業している場合、Mooseを使用して内省しても何も得られません。
必要に応じて、CMOPの代わりにuse Moose ()
できます。Moose::Meta::Class->initialize
すでに提供されている回答を使用して、クラスの定義済みメソッドのリストを簡単に取得できます。ただし、Perlは動的言語であるため、後でさらに多くのメソッドを定義できます。特定のクラスが処理するすべてのメソッドのリストを取得する方法は実際にはありません。この種のものの詳細については、Perlのマスターにいくつかの章があります。
人々はあなたに制限について言わずにあなたに答えを与えています(そして賛成しています)。
Adamは彼のClass::Inspectorについて言及していますが、動的言語が実行しないことを実行しようとしているため、実際には機能しません(静的です:)。たとえば、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";
Class::MOPにも同じ制限があります。
すべてのモジュールがAUTOLOADを使用するわけではありませんが、あいまいな機能でもまれな機能でもありません。一部のメソッドを見逃してもかまわない場合は、Class::InspectorまたはClass::MOPで問題ない可能性があります。あらゆる場合にクラスまたはオブジェクトで呼び出すことができるすべてのメソッドのリストを提供するわけではありません。
クラスまたはオブジェクトがあり、特定のメソッドを呼び出すことができるかどうかを知りたい場合は、can()を使用します。それをevalブロックでラップして、オブジェクトでさえないものに対して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のマニュアルページを参照してください。
あなたが意味するかどうか、任意のクラス、またはあなたがあなた自身を実装していたかどうかに依存します。後者の場合、私はMooseを使用します。これは、これらの機能に非常にクリーンな構文を提供します。クックブックから:
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
Class :: Inspector-> methods('Your :: Class')が必要になる可能性があります。
言っ途切れる。
忘れた時のためにここに置いておきます。これは非常に強力です。残念ながら、ほとんどのPerlプログラマーがそれを体験することは決してありません。
package Foo;
use strict;
sub foo1 {};
sub foo2 {};
our $foo3 = sub{};
my $foo4 = "hello, world!";
package Bar;
use strict;
# woo, we're javascript!
(sub {
*Bar::foo1 = sub { print "hi!"; };
*Bar::foo2 = sub { print "hello!"; };
$Bar::foo1 = 200;
})->();
package main;
use strict;
use Data::Dumper;
$Data::Dumper::Deparse = 1;
print Dumper \%Data::Dumper::;
print Dumper \%Foo::;
print Dumper \%Bar::;