Is it possible to get all valid methods for a specific Perl class?

Is it possible to get all valid methods for a specific Perl class?

I am trying to manipulate the character table of a class and get all its methods. I found that I can extract subroutines from non-subroutines via $obj->can($method) , but that doesn’t do exactly what I think it does.

The following data is returned:

 subroutine, Property, croak, Group, confess, carp, File 

However, subroutine not a method (only a subroutine) and croak , confess and carp were imported into my package.

I really want to print:

 Property,Group, File 

But I will take:

 subroutine, Property,Group, File 

Below is my program:

 #! /usr/bin/env perl use strict; use warnings; use feature qw(say); my $sections = Section_group->new; say join ", ", $sections->Sections; package Section_group; use Carp; sub new { return bless {}, shift; } sub Add { my $self = shift; my $section = shift; } sub Sections { my $self = shift; my @sections; for my $symbol ( keys %Section_group:: ) { next if $symbol eq "new"; # This is a constructor next if $symbol eq "Add"; # Not interested in this method next if $symbol eq "Sections"; # This is it own method push @sections, $symbol if $self->can($symbol); } return wantarray ? @sections : \@sections; } sub subroutine { my $param1 = shift; my $param2 = shift; } sub Group { my $self = shift; my $section = shift; } sub File { my $self = shift; my $section = shift; } sub Property { my $self = shift; my $section = shift; } 
+6
source share
2 answers

This is pretty trivial. We want to keep only those subheadings that were originally defined in our package. Each CV (code value) has a pointer to the package in which it was defined. Thanks to B we can verify that:

 use B (); ... if (my $coderef = $self->can($symbol)) { my $cv = B::svref_2object $coderef; push @sections, $symbol if $cv->STASH->NAME eq __PACKAGE__; } # Output as wanted 

That is, we perform introspection using svref_2object . This returns a Perl object representing the internal perl data structure.

If we look at coderef, we get a B::CV object, which is an internal CV . The STASH field in CV indicates Stash where it was defined. As you know, Stash is just a special hash (internally represented as HV ), so $cv->STASH returns a B::HV . The NAME a HV field contains the full name of the Stash package if the HV is a Stash and not a regular hash.

Now we have all the information we need, and we can compare the desired package name with the coderef wallet name.

Of course, this is simplified, and you will want to go through @ISA for general classes.


No one likes dirty namespaces. Fortunately, there are modules that remove external characters from Stash, for example. namespace::clean . This is not a problem when the CVs of all the subscribers you call are known at compile time.

+6
source

What are you trying to do? Why does it matter how the class defines or implements the method to which it responds?

Perl is a dynamic language, so this means that methods should not exist at all. Using AUTOLOAD method can be perfectly accurate and callable, but never appear in a symbol table. A good interface will make can work in this case, but there may be times when a class or object decides to respond with false.

The Package :: Stash module can help you find specific routines in a specific namespace, but, as you say, they cannot be defined in the same file. Methods in a class can be derived from an inherited class. If you care about where they came from, you are probably mistaken.

+6
source

Source: https://habr.com/ru/post/952312/


All Articles