Догоняя 'require' для класса метамодели
Я определил собственный класс метамодели для создания особого вида классов. Теперь я хотел бы, чтобы эти классы автоматически регистрировали себя с помощью специального менеджера. В принципе, это было бы так (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
s модули с именами, соответствующими определенному шаблону. После этого нужно знать, что myclass
Они определены в каждом модуле. Он может сканировать таблицу символов загруженного модуля. Но это не будет работать, если загруженный файл содержит несколько модулей или вообще не содержит модулей - как в примере выше.
Пока это выглядит как INIT
Фазер предоставил бы решение, но я изо всех сил пытаюсь найти, как получить блок тела класса изнутри composer
метод.
1 ответ
При выполнении метапрограммирования методы метаобъекта вызываются во время компиляции, так как объявления анализируются. Следовательно 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
, поскольку загрузчик знает, как объединить эти символы, тогда как другие типы, по-разному затронутые во время компиляции разных модулей, приведут к конфликтам во время загрузки.
Перед вами стоит небольшая задача - убедиться, что все установлено под достаточно уникальным ключом; имя типа, которое я использовал здесь, вероятно, не достаточно уникально в общем. Вероятно, я бы просто сгенерировал что-то достаточно случайное, чтобы вероятность столкновения была крайне маловероятной.