我定义了自己的元模型类来创建一种特殊的类。现在,我希望这些类自动向一种特殊类型的管理器注册。基本上,这是这样的(每次加载类模块时只调用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
es。它可以扫描加载模块的符号表。但是,如果加载的文件包含多个模块或根本没有模块,这将不起作用——就像上面的例子一样。
到目前为止,看起来INIT
相位器可以提供解决方案,但我很难找到如何从composer
方法中获得类的主体块。
在进行元编程时,在编译过程中会调用元对象的方法,解析声明。因此,在解析myclass foo { }
声明之后立即调用compose
方法。然后保存模块编译的结果,加载模块时不会再次处理元对象中的任何内容。
据我所知,没有支持的方法可以将加载时回调注入到声明类型的模块中。然而,可以将符号安装到一个单独的包中(用作注册表(,然后在那里找到它们。
例如,假设我有一个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
中,因为加载程序知道如何对它们进行符号合并,而在编译不同模块期间以不同方式接触的其他类型将导致加载时间冲突。
你只剩下一个小小的挑战,那就是确保将所有东西都安装在一个足够独特的密钥下;我在这里使用的类型名称一般来说可能不够唯一。也许我只是生成了一些足够随机的东西,碰撞的可能性非常小。