-
Notifications
You must be signed in to change notification settings - Fork 0
/
RoleToRoleApplier.pm
88 lines (81 loc) · 2.77 KB
/
RoleToRoleApplier.pm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
knowhow RoleToRoleApplier {
method apply($target, @roles) {
# Aggregate all of the methods sharing names.
my %meth_info;
for @roles {
my @methods := $_.HOW.methods($_);
for @methods {
my $name := ~$_;
my $meth := $_;
my @meth_list;
if nqp::defined(%meth_info{$name}) {
@meth_list := %meth_info{$name};
}
else {
%meth_info{$name} := @meth_list;
}
my $found := 0;
for @meth_list {
if $meth =:= $_ {
$found := 1;
}
}
unless $found {
@meth_list.push($meth);
}
}
}
# Also need methods of target.
my %target_meth_info;
my @target_meths := $target.HOW.methods($target);
for @target_meths {
%target_meth_info{~$_} := $_;
}
# Process method list.
for %meth_info {
my $name := ~$_;
my @add_meths := %meth_info{$name};
# Do we already have a method of this name? If so, ignore all of the
# methods we have from elsewhere.
unless nqp::defined(%target_meth_info{$name}) {
# No methods in the target role. If only one, it's easy...
if +@add_meths == 1 {
$target.HOW.add_method($target, $name, @add_meths[0]);
}
else {
# More than one - add to collisions list.
$target.HOW.add_collision($target, $name);
}
}
}
# Now do the other bits.
my @all_roles;
for @roles {
my $how := $_.HOW;
# Compose is any attributes, unless there's a conflict.
my @attributes := $how.attributes($_);
for @attributes {
my $add_attr := $_;
my $skip := 0;
my @cur_attrs := $target.HOW.attributes($target);
for @cur_attrs {
if $_ =:= $add_attr {
$skip := 1;
}
else {
if $_.name eq $add_attr.name {
nqp::die("Attribute '" ~ $_.name ~ "' conflicts in role composition");
}
}
}
unless $skip {
$target.HOW.add_attribute($target, $add_attr);
}
}
# Build up full list.
# XXX Not really right yet...
@all_roles.push($_);
}
return @all_roles;
}
}