Making a custom declarator

Viewed 150

Let's say I use a certain set of boilerplate fairly regularly:

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;
    …
  }

}

I'd rather be able to just say:

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

And somewhere in Bar, set up the declaration for bar (or, since class Foo will itself ultimately use its own declarator, it could go somewhere else and doesn't have to be pulled out in a separate Type). How would I go about doing that?

1 Answers

-1. Limitations (only for packages)

The method EXPORTHOW calls .set_how on current $?LANG adding a slang to the latter.
Then it add_package_declarator to the MAIN $?LANG which adds a package_declarator method to its Actions and Grammar. It is, I think, the only "dynamic slang" (in World.nqp).

If what you want is to overwrite routine_declarator. Then you have to write a slang imitating the chain just cited. If you accept to keep the method keyword and make the automatic signature in the class, say according to the method name, here is a way:

Note: A Package is a container (package, grammar, module, role, knowhow, enum, class, subset). If you put code inside like a method, this gets executed (I'v just tried):

0. Description (EXPORTHOW)

I would use undocumented EXPORTHOW and DECLARE in a module because I did not find a way with Phaser. Apparently it is too late even at BEGIN.

The example I give, is decorating every method in a class (even 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. Executable

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. Output

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

4. Sources

Related