Догоняя 'require' для класса метамодели - PullRequest
0 голосов
/ 14 декабря 2018

Я определил собственный класс метамодели для создания особого вида классов.Теперь я хотел бы, чтобы эти классы автоматически регистрировали себя с помощью специального менеджера.По сути, это будет выглядеть так (будет вызываться только 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.

1 Ответ

0 голосов
/ 14 декабря 2018

При выполнении метапрограммирования методы метаобъекта вызываются во время компиляции, так как объявления анализируются.Поэтому метод 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, так как загрузчик знает, как их объединить по символам, тогда как другие типы, по-разному затронутые во время компиляции разных модулей, приведут к конфликтам времени загрузки.

Перед вами стоит небольшая задача - убедиться, что все установлено под достаточно уникальным ключом;имя типа, которое я использовал здесь, вероятно, не достаточно уникально в общем.Возможно, я бы просто сгенерировал что-то достаточно случайное, чтобы вероятность столкновения была крайне маловероятной.

...