我已经定义了自己的元模型类来创建一种特殊的类。现在,我希望这些类自动向特殊类型的管理器注册。基本上,这是这样的(每次加载类模块时,只会调用compose
)
use MyManager;
class MyHOW is Metamodel::ClassHOW {
method compose ( Mu \type ) {
self.add_parent( type, MyParentClass );
callsame;
registerMyClass( type );
}
}
然后我有类似的东西:
use v6;
use MyClass;
myclass Foo { ... }
在模块中。然后有一个管理器对象,用于扫描名称与特定模式匹配的存储库/文件系统和require
的模块。之后,它需要知道每个模块中定义了什么myclass
。它可以扫描已加载模块的符号表。但是,如果加载的文件包含多个模块或根本不包含任何模块,则将无法正常工作–如上例所示。
到目前为止,看来INIT
移相器将提供解决方案,但我一直在努力寻找如何从composer
方法中获取类的主体块的方法。
答案 0 :(得分:5)
进行元编程时,将在编译期间调用元对象的方法,因为会解析声明。因此,在解析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;
}
}
我这样写了一些文件mods/A.pm6
和mods/B.pm6
:
use MyClass;
myclass A { }
这:
use MyClass;
myclass B { }
然后,当我在这样的脚本中要求它们并将其密钥转储到MyRegistry
中时,它们都将在此处注册:
use MyClass;
for dir('mods', test => /pm6$/) {
require $_;
}
dd MyRegistry.WHO.values;
因此提供了一种可预测的方式来找到它们。
请注意,要使类似的技术起作用,您确实需要将它们存储在Stash
中,因为加载程序知道如何对它们进行符号合并,而其他类型则在编译过程中以不同的方式涉及不同的模块将导致加载时冲突。
要确保将所有内容都安装在足够唯一的密钥下,这将给您带来一些挑战。通常,我在这里使用的类型名称可能不够唯一。也许我会生成一些足够随机的东西,以致发生碰撞的可能性极小。