问题描述
如何找到本地安装的模块,以及我可以在 Raku 程序中Top.rakumod
的模块?
假设我们有三个分布:Parent、brother、Sister。父'提供'multi method on-starting { ... }
,而兄弟和姐妹分别提供'Top::Son.rakumod'和'Top::Daughter.rakumod'。兄弟姐妹在他们的 Meta6.json 中有一个 'depends':'Top'。
每个发行版都在自己的 git 存储库中。每个都由zef安装。
假设 Top 被设置为一个具有接口方法的类,可能类似于:Top::brother
,每个子类都必须实现它,并且在运行时为调用者提供有关子类的信息.所以 Top::Daughter
和 on-starting
都实现了 Top::Aunt
。也可能存在未在本地安装的发行版 Top::*
等。我们需要找到安装了哪些。
所以,现在我们运行一个 Top 实例(在 Parent 中定义)。它需要查找与 $*REPO
匹配的已安装模块。开始的地方(我认为)是 Top::*
,它是包含已安装模块的存储库的链接列表。 $*REPO 还承担 Compunit::Repository 角色,后者又具有“need”方法。
我不明白的是如何操作 $*REPO 来获取所有与 ^can
匹配的候选模块的列表,以及整个链表。
获得候选列表后,我可以使用 on-starting
检查它是否具有 SyntaxError
方法,然后调用该方法。
如果这不是得到 Top 发现本地安装模块的结果的方法,我很感激我刚刚制定的方案的一些替代方案。
解决方法
CompUnit::Repository
(CUR) 有一个用于搜索分布的 candidates
方法,但它不允许按名称前缀搜索(因为它也可以进行快速查找,需要全名才能获取其 sha1 目录/抬头)。对于 CompUnit::Repository::FileSystem
(CURFS),您可以调用 .distribution
来获取提供的分布,对于 CompUnit::Repository::Installation
(CURI),您可以调用 .installed
以获取它提供的所有分布:
raku -e ' \
say $*REPO.repo-chain \
.grep(CompUnit::Repository::FileSystem | CompUnit::Repository::Installation) \
.map({ $_ ~~ CompUnit::Repository::FileSystem ?? $_.distribution !! $_.installed.Slip }) \
.grep(*.defined) \
;'
如果要匹配命名空间,则需要对发行版名称或其模块名称进行 grep:
my @matches = @distributions.grep({ $_.meta<provides>.keys.first({.starts-with("Top::")}) });
这种处理方式可以在 Pluggable 模块中看到(如果您还想加载此类代码,我建议您使用它)
当然,您只明确要求安装模块,但忽略 CURFS 没有任何意义——作为应用程序开发人员,它不应该在何处或如何加载模块。如果有人想使用 -I ./foo
而不是安装它,没有充分的理由忽略它。如果您无论如何都坚持这样做,那么如何更改上面的示例以适应应该是显而易见的。
一旦我有了候选人名单,我就可以使用 ^can 检查它是否有一个 on-starting 方法,然后调用该方法。
除了检查元文件或读取各种文件的源代码之外,拥有候选列表不会让您做任何事情。至少你会加载你想调用的任何模块,例如.^can
首先,这将涉及几个步骤,分发对象不能直接用于加载(您从中提取全名并使用它来加载它)--所以我再次建议使用 Pluggable