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);
37
my $name := nqp::can($_, 'name') ?? $_.name !! nqp::getcodename($_);
38
unless has_method($target, $name, 1) {
39
nqp::die("Method '$name' collides and a resolution must be provided by the class '" ~
40
$target.HOW.name($target) ~ "'");
44
# Compose in any methods.
45
my @methods := $to_compose_meta.methods($to_compose);
47
my $name := nqp::can($_, 'name') ?? $_.name !! nqp::getcodename($_);
48
unless has_method($target, $name, 0) {
49
$target.HOW.add_method($target, $name, $_);
53
# Compose in any role attributes.
54
my @attributes := $to_compose_meta.attributes($to_compose);
56
if has_attribute($target, $_.name) {
57
nqp::die("Attribute '" ~ $_.name ~ "' already exists in the class '" ~
58
$target.HOW.name($target) ~ "', but a role also wishes to compose it");
60
$target.HOW.add_attribute($target, $_);
63
# The full list of done roles is just the list of the one role we have
67
@done[0] := $to_compose;