我有许多不同的网站,我从中下载数据并按摩到其他格式(使用Perl)以便在工作中使用,这些都是从一个Perl脚本运行的,如下所示:
#! /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;
依此类推。目前每个My::Package
都是自己的包;它不会从基础包或任何东西继承。我打算使用Moose
重新编写它们,我希望每次添加新包时都不必编辑运行下载的Perl脚本,可能有办法找到继承的包一个基础包,然后在一个循环中实例化每个并进行下载,有点像:
#! /usr/bin/perl
use strict;
for my $pname (packages_that_inherit_from("My::Package")) {
my $package = $pname->new;
$package->download;
}
它或其他东西可能吗?
TIA
答案 0 :(得分:6)
使用Moose
的Class::MOP
基础,您可以找到分配给每个类的子类(在那个时间点)。
来自Class::MOP::Class
docs:
<强> $ metaclass-&GT;亚类强> 这将返回此类的所有子类的列表,甚至是间接子类。
<强> $ metaclass-&GT; direct_subclasses 强> 这将返回此类的直接子类列表,其中不包含间接子类。
例如,如果我们构建这些类:
{
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__ }
}
然后以您的示例为基础,我们可以这样做:
for my $pname ( Root->new->meta->direct_subclasses ) {
my $package = $pname->new;
$package->download;
}
# => "downloading from NodeA"
以上运行NodeA->download
。将上方更改为meta->subclasses
也会运行NodeA1->download
。
/ I3az /
答案 1 :(得分:3)
虽然您说您要转移到Moose
,但非Moose
方法是根据基本包名称将所有派生包放入已知子目录中。然后加载所有模块
例如,如果您的基础包是Local::Downloader
,则所有派生包都以Local::Downloader::Plugin
或类似的东西开头。然后,您@INC
中.../Local/Downloader/Plugin/...
查找所有模块{{1}}。虽然自己做起来并不难,但像Module::PluginFinder这样的东西也可以帮到你。
答案 2 :(得分:2)
您要求的是不可能的,因为您要使用的所有软件包都不会被加载。为什么不将所有软件包放在一个公共目录中,然后让脚本打开该目录,对于每个文件,需要它,然后实例化对象。
答案 3 :(得分:1)
基于继承没有办法做到这一点,因为父类甚至不知道它是否有后代,更不用说它有多少或它们的名字是什么。
但是,如果您遵循使用分层命名空间并将后代命名为Parent::Foo
,Parent::Bar
等的通用约定,则可以使用Module::Pluggable来加载所有内容在Parent
命名空间下:
use Module::Pluggable require => 1, search_path => ['Parent'];
my @descendants = plugins();
由于这是基于命名空间的,因此它会引入Parent::Helper::ThatIsNotAChild
,同时缺少Child::NotUnder::Parent::Namespace
,因此它并不完全完美。