Tworzenie niestandardowego deklaratora

9

Powiedzmy, że używam pewien zestaw płyt kotłowych dość regularnie:

class Foo {

  method abc($a: $b, $c, +@d) is pure {
    use Slang::Bar;
    …
  }

  method xyz($a: $b, $c, +@d) is pure {
    use Slang::Bar;
    …
  }

  method blarg($a: $b, $c, +@d) is pure {
    use Slang::Bar;
    …
  }

}

Wolałbym móc po prostu powiedzieć:

class Foo is/does Bar {
  bar  abc   { … }
  bar  xyz   { … }
  bar  blarg { … }
}

I gdzieś w Barze ustaw deklarację dla baru (lub, ponieważ klasa Foo sama ostatecznie użyje własnego deklaratora, może pójść gdzie indziej i nie musi być wyciągana w osobnym typie). Jak miałbym to zrobić?

użytkownik 0721090601
źródło
Rozumiem, że to w zasadzie pytanie „jak to zrobić?” ale nie widziałem żadnych prawdziwych wpisów, a istniejące moduły, które go używają (Red / Cro) są dość złożonymi (jeśli pięknymi) bestiami, które trudno jest na pierwszy rzut oka śledzić.
user0721090601
Wygląda na to, że chcesz ponownie wykorzystać podpisy, prawda?
jjmerelo
2
jjmerelo: nie, tak naprawdę ostatecznym celem jest wykonanie podklasy metody (rejestracja jej w klasie, jeśli jest używana w środku) i użycie całkowicie innego języka wewnątrz bloku kodu (w tym przypadku
wyrażenia regularnego
2
jjmerelo: zobacz propozycję gist.github.com/alabamenhu/2fec7a8f51a24091dc1b104a2ae2f04d . Mam kilka dni do pokazania modułu testowego, ale większość logistyki Binexa działa, ale dla składni podobnej do Raku
0721090601

Odpowiedzi:

5

-1. Ograniczenia (tylko w przypadku pakietów)

Metoda EXPORTHOW wywołuje .set_how na bieżąco, $?LANGdodając do niego slang.
Następnie dodaje add_package_declarator do, MAIN $?LANGktóry dodaje package_declaratormetodę do swoich akcji i gramatyki. Myślę, że to jedyny „dynamiczny slang” (w World.nqp).

Jeśli chcesz zastąpić routine_declarator . Następnie musisz napisać slang imitujący właśnie cytowany łańcuch. Jeśli akceptujesz zachowanie słowa kluczowego metody i automatyczne podpisywanie w klasie, powiedzmy zgodnie z nazwą metody, oto sposób:

Uwaga: Pakiet jest kontenerem (pakiet, gramatyka, moduł, rola, know-how, wyliczanie, klasa, podzbiór). Jeśli wstawisz kod jak metodę, zostanie to wykonane (właśnie próbowałem):

0. Opis (EKSPORT)

Użyłbym nieudokumentowane EXPORTHOW oraz DECLAREw module bo nie znaleźć sposób z Phaser . Najwyraźniej jest już za późno, nawet w BEGIN.

Daję przykład, że dekoruję każdą metodę w klasie (nawet BUILDALL).

1. Lib ( decorator.rakumod)

class DecoratedClassHOW is Metamodel::ClassHOW {
    method add_method(Mu $obj, $name, $code_obj) {
        sub wrapper ($obj, $a, $b) {
            say "Before $name";
            my $res = $code_obj($obj, $a, $b);
            say "After $name";
            return $res;
        }
        my $res = callwith($obj, $name, &wrapper);
        return $res;
    }
}

my module EXPORTHOW {
    package DECLARE {
        constant decorated = DecoratedClassHOW;
    }
}

2. Plik wykonywalny

use lib '.';
use decorator-lib;

decorated Foo {
  method abc($a, $b) {
      say "In abc: $a:$b";
  }
}

my $f = Foo.new;
$f.abc(1, 2);

3. Wyjście

Before BUILDALL
After BUILDALL
Before abc
In abc: 1:2
After abc

4. Źródła

Tinmarino
źródło
Świetny. Prosty i bezpośredni. Dzięki!
user0721090601