我已经定义了自己的元模型类来创建一种特殊的类.现在,我希望这些类能够自动注册一个特殊的经理.基本上,这就像这样(只有compose在每次加载类'模块时才会调用):
use MyManager;
class MyHOW is Metamodel::ClassHOW {
method compose ( Mu \type ) {
self.add_parent( type, MyParentClass );
callsame;
registerMyClass( type );
}
}
Run Code Online (Sandbox Code Playgroud)
然后我有类似的东西:
use v6;
use MyClass;
myclass Foo { ... }
Run Code Online (Sandbox Code Playgroud)
在一个模块中.然后有一个管理器对象,它扫描require名称与特定模式匹配的存储库/文件系统和模块.之后,它需要知道myclass每个模块中定义了什么.它可以扫描加载模块的符号表.但是如果加载的文件包含多个模块或根本没有模块,这将无法工作 - 如上例所示.
到目前为止,看起来INIT移相器会提供解决方案,但我很难找到如何从composer方法中获取类的主体块.
在进行元编程时,在编译期间调用元对象的方法,因为解析了声明.因此,在compose解析myclass foo { }声明后立即调用该方法.然后保存模块编译的结果,并在加载模块时再次处理元对象中的任何内容.
我没有任何支持的方法可以将一个加载时回调注入到声明类型的模块中.但是,可以将符号安装到单独的包中 - 用作注册表 - 然后在那里找到它们.
例如,鉴于我有一个lib/MyClass.pm6如下所示:
package MyRegistry { }
class MyParentClass { }
class MyHOW is Metamodel::ClassHOW {
method compose ( Mu \type ) {
MyRegistry::{self.name(type)} = type;
self.add_parent( type, MyParentClass );
callsame;
}
}
my package EXPORTHOW {
package DECLARE {
constant myclass = MyHOW;
}
}
Run Code Online (Sandbox Code Playgroud)
我写了一些文件mods/A.pm6,mods/B.pm6像这样:
use MyClass;
myclass A { }
Run Code Online (Sandbox Code Playgroud)
还有这个:
use MyClass;
myclass B { }
Run Code Online (Sandbox Code Playgroud)
然后,当我在这样的脚本中要求它们并将密钥转储时MyRegistry,它们都将在那里注册:
use MyClass;
for dir('mods', test => /pm6$/) {
require $_;
}
dd MyRegistry.WHO.values;
Run Code Online (Sandbox Code Playgroud)
从而提供了一种可预测的方法来找到它们.
请注意,对于这样的技术来说,你真的需要将它们存储到a中Stash,因为加载器知道如何对它们进行符号合并,而在编译不同模块期间以不同方式触摸的其他类型将导致加载时间冲突.
您将面临轻微的挑战,确保在一个足够独特的密钥下安装所有东西; 我在这里使用的类型名称通常可能不够独特.可能我只是产生足够随机的东西,以至于碰撞的可能性极小.