How can I find all packages that inherit from a package in Perl?

I have several different sites on which I upload data and massage into other formats (using Perl) for use at work, they all run from the same kind of Perl script like:

#! /usr/bin/perl use strict; use My::Package1; use My::Package2; my $p1 = My::Package1->new; $p1->download; my $p2 = My::Package2->new; $p2->download; 

etc. etc. Currently, each My::Package is its own package; it does not inherit from the base package or anything else. I plan to overwrite them with Moose , and I was hoping that instead of editing the Perl script, which starts the download every time a new package is added, there might be a way to find packages that inherit from the base package, and then loop each and perform a download, sort of like:

 #! /usr/bin/perl use strict; for my $pname (packages_that_inherit_from("My::Package")) { my $package = $pname->new; $package->download; } 

Is this possible, or something like that?

TIA

+4
source share
4 answers

Using Moose Class::MOP , the underlying you can find the subclasses assigned to each class (at this point in time).

From Class::MOP::Class docs:

$ metaclass-> subclasses This returns a list of all subclasses for this class, even indirect subclasses.

$ metaclass-> direct_subclasses This returns a list of immediate subclasses for this class, which does not include indirect subclasses.

So, for example, if we build these classes:

 { package Root; use Moose; use namespace::clean -except => 'meta'; sub baz { say 'Some root thingy' } sub download { say "downloading from " . __PACKAGE__ } } { package NodeA; use Moose; extends 'Root'; use namespace::clean -except => 'meta'; sub download { say "downloading from " . __PACKAGE__ } } { package NodeA1; use Moose; extends 'NodeA'; use namespace::clean -except => 'meta'; sub download { say "downloading from " . __PACKAGE__ } } 

Then, using your example as a basis, we can do this:

 for my $pname ( Root->new->meta->direct_subclasses ) { my $package = $pname->new; $package->download; } # => "downloading from NodeA" 

So the above is done by NodeA->download . When changing above, meta->subclasses will also execute NodeA1->download .

/ I3az /

+6
source

Although you say you're moving to Moose , the non- Moose way is to put all the derived packages in a known subdirectory based on the name of the base package. Then you load all the modules

For example, if your base package is Local::Downloader , all derived packages start with Local::Downloader::Plugin or something similar. Then you look for all the modules in @INC , which is significantly .../Local/Downloader/Plugin/... Although it’s not too difficult to do it yourself, something like Module :: PluginFinder can do it for you as well.

+3
source

What you ask for will not be possible because none of the packages that you intend to use will be downloaded. Why not put all the packages in a shared directory, and then have your script open that directory and require it for each file, and then instantiate your objects.

+2
source

It is impossible to do this on the basis of inheritance, because the parent class does not even know if it has descendants, no matter how much it has or what they have.

However, if you adhere to the general agreement on using hierarchical namespaces and naming descendants like Parent::Foo , Parent::Bar , etc., you can come close to this using Module :: Pluggable to load everything in the Parent namespace :

 use Module::Pluggable require => 1, search_path => ['Parent']; my @descendants = plugins(); 

Since this is based on namespaces, it will pull Parent::Helper::ThatIsNotAChild , and Child::NotUnder::Parent::Namespace missing, so it is not entirely ideal.

+1
source

All Articles