1
knowhow RoleToClassApplier {
3
sub has_method($target, $name, $local) {
4
my %mt := $target.HOW.method_table($target);
5
nqp::existskey(%mt, $name);
8
sub has_attribute($target, $name) {
9
my @attributes := $target.HOW.attributes($target, :local(1));
11
if $_.name eq $name { return 1; }
16
method apply($target, @roles) {
17
# If we have many things to compose, then get them into a single helper
21
if nqp::elems(@roles) == 1 {
22
$to_compose := @roles[0];
23
$to_compose_meta := $to_compose.HOW;
26
$to_compose := NQPConcreteRoleHOW.new_type(:instance_of(NQPMu));
27
$to_compose_meta := $to_compose.HOW;
29
$to_compose_meta.add_role($to_compose, $_);
31
$to_compose := $to_compose_meta.compose($to_compose);
35
my @collisions := $to_compose_meta.collisions($to_compose);
36
for @collisions -> $name {
37
unless has_method($target, $name, 1) {
38
nqp::die("Method '$name' collides and a resolution must be provided by the class '" ~
39
$target.HOW.name($target) ~ "'");
43
# Compose in any methods.
44
my @methods := $to_compose_meta.methods($to_compose);
46
my $name := nqp::can($_, 'name') ?? $_.name !! nqp::getcodename($_);
47
unless has_method($target, $name, 0) {
48
$target.HOW.add_method($target, $name, $_);
52
# Compose in any role attributes.
53
my @attributes := $to_compose_meta.attributes($to_compose);
55
if has_attribute($target, $_.name) {
56
nqp::die("Attribute '" ~ $_.name ~ "' already exists in the class '" ~
57
$target.HOW.name($target) ~ "', but a role also wishes to compose it");
59
$target.HOW.add_attribute($target, $_);
62
# The full list of done roles is just the list of the one role we have
66
@done[0] := $to_compose;