line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package UR::Role::Prototype; |
2
|
|
|
|
|
|
|
|
3
|
266
|
|
|
266
|
|
1010
|
use strict; |
|
266
|
|
|
|
|
364
|
|
|
266
|
|
|
|
|
6195
|
|
4
|
266
|
|
|
266
|
|
820
|
use warnings; |
|
266
|
|
|
|
|
332
|
|
|
266
|
|
|
|
|
4926
|
|
5
|
|
|
|
|
|
|
|
6
|
266
|
|
|
266
|
|
841
|
use UR; |
|
266
|
|
|
|
|
325
|
|
|
266
|
|
|
|
|
1154
|
|
7
|
266
|
|
|
266
|
|
971
|
use UR::Object::Type::InternalAPI; |
|
266
|
|
|
|
|
357
|
|
|
266
|
|
|
|
|
1481
|
|
8
|
266
|
|
|
266
|
|
4375
|
use UR::Util; |
|
266
|
|
|
|
|
356
|
|
|
266
|
|
|
|
|
1059
|
|
9
|
266
|
|
|
266
|
|
4441
|
use UR::AttributeHandlers; |
|
266
|
|
|
|
|
362
|
|
|
266
|
|
|
|
|
1152
|
|
10
|
|
|
|
|
|
|
|
11
|
266
|
|
|
266
|
|
4821
|
use Sub::Name qw(); |
|
266
|
|
|
|
|
414
|
|
|
266
|
|
|
|
|
4691
|
|
12
|
266
|
|
|
266
|
|
903
|
use Sub::Install qw(); |
|
266
|
|
|
|
|
358
|
|
|
266
|
|
|
|
|
4211
|
|
13
|
266
|
|
|
266
|
|
889
|
use List::MoreUtils qw(any); |
|
266
|
|
|
|
|
365
|
|
|
266
|
|
|
|
|
2275
|
|
14
|
266
|
|
|
266
|
|
103569
|
use Carp; |
|
266
|
|
|
|
|
378
|
|
|
266
|
|
|
|
|
231610
|
|
15
|
|
|
|
|
|
|
our @CARP_NOT = qw(UR::Object::Type); |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our $VERSION = "0.46"; # UR $VERSION;; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
UR::Object::Type->define( |
20
|
|
|
|
|
|
|
class_name => 'UR::Role::Prototype', |
21
|
|
|
|
|
|
|
doc => 'Object representing a role', |
22
|
|
|
|
|
|
|
id_by => 'role_name', |
23
|
|
|
|
|
|
|
has => [ |
24
|
|
|
|
|
|
|
id_by => { is => 'ARRAY', doc => 'List of ID properties and their definitions' }, |
25
|
|
|
|
|
|
|
role_name => { is => 'Text', doc => 'Package name identifying the role' }, |
26
|
|
|
|
|
|
|
class_names => { is => 'Text', is_many => 1, doc => 'Class names composing this role' }, |
27
|
|
|
|
|
|
|
methods => { is => 'HASH', doc => 'Map of method names and coderefs', default => {} }, |
28
|
|
|
|
|
|
|
overloads => { is => 'HASH', doc => 'Map of overload keys and coderefs', default => {} }, |
29
|
|
|
|
|
|
|
has => { is => 'ARRAY', doc => 'List of properties and their definitions' }, |
30
|
|
|
|
|
|
|
roles => { is => 'ARRAY', doc => 'List of other role names composed into this role', default => [] }, |
31
|
|
|
|
|
|
|
requires => { is => 'ARRAY', doc => 'List of properties required of consuming classes', default => [] }, |
32
|
|
|
|
|
|
|
attributes_have => { is => 'HASH', doc => 'Meta-attributes for properites' }, |
33
|
|
|
|
|
|
|
excludes => { is => 'ARRAY', doc => 'List of Role names that cannot compose with this role', default => [] }, |
34
|
|
|
|
|
|
|
method_modifiers => { is => 'UR::Role::MethodModifier', |
35
|
|
|
|
|
|
|
is_many => 1, |
36
|
|
|
|
|
|
|
doc => q(List of 'before', 'after' and 'around' method modifiers), |
37
|
|
|
|
|
|
|
reverse_as => 'role' |
38
|
|
|
|
|
|
|
}, |
39
|
|
|
|
|
|
|
map { $_ => _get_property_desc_from_ur_object_type($_) } |
40
|
|
|
|
|
|
|
meta_properties_to_compose_into_classes(), |
41
|
|
|
|
|
|
|
], |
42
|
|
|
|
|
|
|
is_transactional => 0, |
43
|
|
|
|
|
|
|
); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub property_data { |
46
|
23
|
|
|
23
|
1
|
28
|
my($self, $property_name) = @_; |
47
|
23
|
|
|
|
|
44
|
return $self->has->{$property_name}; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
sub has_property_names { |
51
|
136
|
|
|
136
|
1
|
113
|
my $self = shift; |
52
|
136
|
|
|
|
|
117
|
return keys %{ $self->has }; |
|
136
|
|
|
|
|
226
|
|
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub id_by_property_names { |
56
|
66
|
|
|
66
|
1
|
66
|
my $self = shift; |
57
|
66
|
|
|
|
|
54
|
return @{ $self->id_by }; |
|
66
|
|
|
|
|
145
|
|
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub method_names { |
61
|
71
|
|
|
71
|
1
|
78
|
my $self = shift; |
62
|
71
|
|
|
|
|
51
|
return keys %{ $self->methods }; |
|
71
|
|
|
|
|
151
|
|
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub meta_properties_to_compose_into_classes { |
66
|
591
|
|
|
591
|
0
|
2452
|
return qw( is_abstract is_final is_singleton doc |
67
|
|
|
|
|
|
|
composite_id_separator id_generator valid_signals |
68
|
|
|
|
|
|
|
subclassify_by subclass_description_preprocessor sub_classification_method_name |
69
|
|
|
|
|
|
|
sub_classification_meta_class_name |
70
|
|
|
|
|
|
|
schema_name data_source_id table_name select_hint join_hint ); |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub define { |
74
|
42
|
|
|
42
|
1
|
63
|
my $class = shift; |
75
|
42
|
|
|
|
|
117
|
my $desc = $class->_normalize_role_description(@_); |
76
|
|
|
|
|
|
|
|
77
|
42
|
50
|
|
|
|
111
|
unless ($desc->{role_name}) { |
78
|
0
|
|
|
|
|
0
|
Carp::croak(q('role_name' is a required parameter for defining a role)); |
79
|
|
|
|
|
|
|
} |
80
|
|
|
|
|
|
|
|
81
|
42
|
|
|
|
|
103
|
my $methods = _introspect_methods($desc->{role_name}); |
82
|
42
|
|
|
|
|
109
|
my $overloads = _introspect_overloads($desc->{role_name}); |
83
|
|
|
|
|
|
|
|
84
|
42
|
|
|
|
|
1238
|
my $extra = delete $desc->{extra}; |
85
|
42
|
|
|
|
|
286
|
my $role = UR::Role::Prototype->__define__(%$desc, methods => $methods, overloads => $overloads); |
86
|
|
|
|
|
|
|
|
87
|
42
|
100
|
66
|
|
|
225
|
if ($extra and %$extra) { |
88
|
1
|
|
|
|
|
5
|
$role->UR::Object::Type::_apply_extra_attrs_to_class_or_role($extra); |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
41
|
|
|
|
|
103
|
$role->_inject_instance_constructor_into_namespace(); |
92
|
|
|
|
|
|
|
|
93
|
41
|
|
|
|
|
1444
|
return $role; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
our @ROLE_DESCRIPTION_KEY_MAPPINGS = ( |
97
|
|
|
|
|
|
|
@UR::Object::Type::CLASS_DESCRIPTION_KEY_MAPPINGS_COMMON_TO_CLASSES_AND_ROLES, |
98
|
|
|
|
|
|
|
[ role_name => qw// ], |
99
|
|
|
|
|
|
|
[ methods => qw// ], |
100
|
|
|
|
|
|
|
[ requires => qw// ], |
101
|
|
|
|
|
|
|
[ excludes => qw// ], |
102
|
|
|
|
|
|
|
); |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
sub _normalize_role_description { |
105
|
42
|
|
|
42
|
|
53
|
my $class = shift; |
106
|
42
|
|
|
|
|
99
|
my $old_role = { @_ }; |
107
|
|
|
|
|
|
|
|
108
|
42
|
|
|
|
|
102
|
my $role_name = delete $old_role->{role_name}; |
109
|
|
|
|
|
|
|
|
110
|
42
|
|
|
|
|
142
|
my $new_role = { |
111
|
|
|
|
|
|
|
role_name => $role_name, |
112
|
|
|
|
|
|
|
has => {}, |
113
|
|
|
|
|
|
|
attributes_have => {}, |
114
|
|
|
|
|
|
|
UR::Object::Type::_canonicalize_class_params($old_role, \@ROLE_DESCRIPTION_KEY_MAPPINGS), |
115
|
|
|
|
|
|
|
}; |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
# The above call to _canonicalize_class_params removed recognized keys. Anything |
118
|
|
|
|
|
|
|
# left over wasn't recognized |
119
|
42
|
|
|
|
|
70
|
$new_role->{extra} = $old_role; |
120
|
|
|
|
|
|
|
|
121
|
42
|
|
|
|
|
66
|
foreach my $key (qw( requires excludes ) ) { |
122
|
84
|
50
|
|
|
|
170
|
unless (UR::Util::ensure_arrayref($new_role, $key)) { |
123
|
0
|
|
|
|
|
0
|
Carp::croak("The '$key' metadata for role $role_name must be an arrayref"); |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# UR::Object::Type::_normalize_class_description_impl() copies these over before |
128
|
|
|
|
|
|
|
# processing the properties. We need to, too |
129
|
42
|
|
|
|
|
107
|
@$old_role{'has', 'attributes_have'} = @$new_role{'has','attributes_have'}; |
130
|
42
|
|
|
|
|
101
|
@$new_role{'has','attributes_have'} = ( {}, {} ); |
131
|
42
|
|
|
|
|
101
|
UR::Object::Type::_massage_field_into_arrayref($new_role, 'id_by'); |
132
|
42
|
|
|
|
|
93
|
UR::Object::Type::_normalize_id_property_data($old_role, $new_role); |
133
|
42
|
|
|
|
|
101
|
UR::Object::Type::_process_class_definition_property_keys($old_role, $new_role); |
134
|
42
|
|
|
|
|
98
|
_complete_property_descriptions($new_role); |
135
|
|
|
|
|
|
|
|
136
|
42
|
|
|
|
|
68
|
return $new_role; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub _complete_property_descriptions { |
140
|
42
|
|
|
42
|
|
47
|
my $role_desc = shift; |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
# stole from UR::Object::Type::_normalize_class_description_impl() |
143
|
42
|
|
|
|
|
64
|
my $properties = $role_desc->{has}; |
144
|
42
|
|
|
|
|
74
|
foreach my $property_name ( keys %$properties ) { |
145
|
17
|
|
|
|
|
25
|
my $old_property = $properties->{$property_name}; |
146
|
17
|
|
|
|
|
72
|
my %new_property = UR::Object::Type->_normalize_property_description1($property_name, $old_property, $role_desc); |
147
|
17
|
|
|
|
|
45
|
delete $new_property{class_name}; # above normalizer fills this in as undef |
148
|
17
|
|
|
|
|
43
|
$properties->{$property_name} = \%new_property; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
my %property_definition_key_to_method_name = ( |
153
|
|
|
|
|
|
|
is => 'data_type', |
154
|
|
|
|
|
|
|
len => 'data_length', |
155
|
|
|
|
|
|
|
); |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
sub _get_property_desc_from_ur_object_type { |
158
|
4256
|
|
|
4256
|
|
3908
|
my $property_name = shift; |
159
|
|
|
|
|
|
|
|
160
|
4256
|
|
|
|
|
10147
|
my $prop_meta = UR::Object::Property->get(class_name => 'UR::Object::Type', property_name => $property_name); |
161
|
4256
|
50
|
|
|
|
7430
|
Carp::croak("Couldn't get UR::Object::Type property meta for $property_name") unless $prop_meta; |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# These properties' definition key is the same as the method name |
164
|
22344
|
|
|
|
|
30771
|
my %definition = map { $_ => $prop_meta->$_ } |
165
|
4256
|
|
|
|
|
4991
|
grep { defined $prop_meta->$_ } |
|
25536
|
|
|
|
|
44435
|
|
166
|
|
|
|
|
|
|
qw( is_many is_optional is_transient is_mutable default_value doc ); |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# These have a translation |
169
|
4256
|
|
|
|
|
11179
|
while(my($key, $method) = each(%property_definition_key_to_method_name)) { |
170
|
0
|
|
|
|
|
0
|
$definition{$key} = $prop_meta->$method; |
171
|
|
|
|
|
|
|
} |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# For any UR::Object::Type properties that are required or have a default value, |
174
|
|
|
|
|
|
|
# those don't apply to Roles |
175
|
4256
|
|
|
|
|
4214
|
$definition{is_optional} = 1; |
176
|
4256
|
|
|
|
|
3811
|
delete $definition{default_value}; |
177
|
|
|
|
|
|
|
|
178
|
4256
|
|
|
|
|
10271
|
return \%definition; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
{ |
182
|
|
|
|
|
|
|
my @overload_ops; |
183
|
|
|
|
|
|
|
sub _all_overload_ops { |
184
|
53
|
100
|
|
53
|
|
132
|
@overload_ops = map { split /\s+/ } values(%overload::ops) unless @overload_ops; |
|
45
|
|
|
|
|
161
|
|
185
|
53
|
|
|
|
|
847
|
@overload_ops; |
186
|
|
|
|
|
|
|
} |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
my @DONT_EXPORT_THESE_SUBS_TO_CLASSES = qw(__import__ FETCH_CODE_ATTRIBUTES MODIFY_CODE_ATTRIBUTES MODIFY_SCALAR_ATTRIBUTES before after around); |
190
|
|
|
|
|
|
|
sub _introspect_methods { |
191
|
42
|
|
|
42
|
|
54
|
my $role_name = shift; |
192
|
|
|
|
|
|
|
|
193
|
42
|
|
|
|
|
108
|
my $subs = UR::Util::coderefs_for_package($role_name); |
194
|
42
|
|
|
|
|
107
|
delete @$subs{@DONT_EXPORT_THESE_SUBS_TO_CLASSES}; # don't allow __import__ to be exported to a class's namespace |
195
|
42
|
|
|
|
|
99
|
delete @$subs{ map { "($_" } ( _all_overload_ops, ')', '(' ) }; |
|
3234
|
|
|
|
|
2760
|
|
196
|
42
|
|
|
|
|
280
|
return $subs; |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub _introspect_overloads { |
200
|
84
|
|
|
84
|
|
117
|
my $role_name = shift; |
201
|
|
|
|
|
|
|
|
202
|
84
|
100
|
|
|
|
253
|
return {} unless overload::Overloaded($role_name); |
203
|
|
|
|
|
|
|
|
204
|
11
|
|
|
|
|
304
|
my %overloads; |
205
|
11
|
|
|
|
|
13
|
my $stash = do { |
206
|
266
|
|
|
266
|
|
1362
|
no strict 'refs'; |
|
266
|
|
|
|
|
417
|
|
|
266
|
|
|
|
|
309582
|
|
207
|
11
|
|
|
|
|
11
|
\%{$role_name . '::'}; |
|
11
|
|
|
|
|
22
|
|
208
|
|
|
|
|
|
|
}; |
209
|
11
|
|
|
|
|
17
|
foreach my $op ( _all_overload_ops ) { |
210
|
825
|
100
|
|
|
|
736
|
my $op_key = $op eq 'fallback' ? ')' : $op; |
211
|
825
|
|
|
|
|
585
|
my $overloaded = $stash->{'(' . $op_key}; |
212
|
|
|
|
|
|
|
|
213
|
825
|
100
|
|
|
|
920
|
if ($overloaded) { |
214
|
16
|
|
|
|
|
11
|
my $subref = *{$overloaded}{CODE}; |
|
16
|
|
|
|
|
29
|
|
215
|
|
|
|
|
|
|
$overloads{$op} = $subref eq \&overload::nil |
216
|
16
|
100
|
|
|
|
46
|
? ${*{$overloaded}{SCALAR}} # overridden with string method name |
|
14
|
|
|
|
|
10
|
|
|
14
|
|
|
|
|
47
|
|
217
|
|
|
|
|
|
|
: $subref; # overridden with a subref |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
} |
220
|
11
|
|
|
|
|
47
|
return \%overloads; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# Called by UR::Object::Type::Initializer::compose_roles to apply a role name |
224
|
|
|
|
|
|
|
# to a partially constructed class description |
225
|
|
|
|
|
|
|
sub _apply_roles_to_class_desc { |
226
|
12763
|
|
|
12763
|
|
16016
|
my($class, $desc) = @_; |
227
|
12763
|
50
|
33
|
|
|
60632
|
if (ref($class) or ref($desc) ne 'HASH') { |
228
|
0
|
|
|
|
|
0
|
Carp::croak('_apply_roles_to_class_desc() must be called as a class method on a basic class description'); |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
|
231
|
12763
|
|
|
|
|
32062
|
_validate_class_method_overrides_consumed_roles($desc); |
232
|
12762
|
100
|
66
|
|
|
31559
|
return unless ($desc->{roles} and @{ $desc->{roles} }); |
|
12762
|
|
|
|
|
49622
|
|
233
|
59
|
|
|
|
|
136
|
my @role_objs = _role_prototypes_with_params_for_class_desc($desc); |
234
|
|
|
|
|
|
|
|
235
|
56
|
|
|
|
|
132
|
_validate_role_exclusions($desc, @role_objs); |
236
|
54
|
|
|
|
|
106
|
_validate_role_requirements($desc, @role_objs); |
237
|
51
|
|
|
|
|
115
|
_validate_class_desc_overrides($desc, @role_objs); |
238
|
|
|
|
|
|
|
|
239
|
47
|
|
|
|
|
142
|
my $id_property_names_to_add = _collect_id_property_names_from_roles($desc, @role_objs); |
240
|
46
|
|
|
|
|
108
|
my $properties_to_add = _collect_properties_from_roles($desc, @role_objs); |
241
|
43
|
|
|
|
|
2409
|
my $meta_properties_to_add = _collect_meta_properties_from_roles($desc, @role_objs); |
242
|
42
|
|
|
|
|
991
|
my $overloads_to_add = _collect_overloads_from_roles($desc, @role_objs); |
243
|
40
|
|
|
|
|
82
|
my $method_modifiers_to_add = _collect_method_modifiers_from_roles($desc, @role_objs); |
244
|
|
|
|
|
|
|
|
245
|
39
|
|
|
|
|
124
|
_save_role_instances_to_class_desc($desc, @role_objs); |
246
|
39
|
|
|
|
|
115
|
_assert_all_role_params_are_bound_to_values($desc, @role_objs); |
247
|
36
|
|
|
|
|
60
|
do { $_->prototype->add_class_name($desc->{class_name}) } foreach @role_objs; |
|
49
|
|
|
|
|
117
|
|
248
|
|
|
|
|
|
|
|
249
|
36
|
|
|
|
|
167
|
UR::Role::Param->replace_unbound_params_in_struct_with_values( |
250
|
|
|
|
|
|
|
[ $id_property_names_to_add, $properties_to_add, $meta_properties_to_add, $overloads_to_add ], |
251
|
|
|
|
|
|
|
@role_objs); |
252
|
|
|
|
|
|
|
|
253
|
36
|
|
|
|
|
130
|
_import_methods_from_roles_into_namespace($desc->{class_name}, \@role_objs); |
254
|
35
|
|
|
|
|
787
|
_apply_overloads_to_namespace($desc->{class_name}, $overloads_to_add); |
255
|
35
|
|
|
|
|
86
|
_apply_method_modifiers_to_namespace($desc, $method_modifiers_to_add); |
256
|
|
|
|
|
|
|
|
257
|
35
|
|
|
|
|
111
|
_merge_role_meta_properties_into_class_desc($desc, $meta_properties_to_add); |
258
|
35
|
|
|
|
|
89
|
_merge_role_id_property_names_into_class_desc($desc, $id_property_names_to_add); |
259
|
35
|
|
|
|
|
79
|
_merge_role_properties_into_class_desc($desc, $properties_to_add); |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
sub _save_role_instances_to_class_desc { |
263
|
39
|
|
|
39
|
|
57
|
my($desc, @role_prototypes) = @_; |
264
|
|
|
|
|
|
|
|
265
|
39
|
|
|
|
|
57
|
my $class_name = $desc->{class_name}; |
266
|
39
|
|
|
|
|
70
|
my @instances = map { $_->instantiate_role_instance($class_name) } |
|
52
|
|
|
|
|
197
|
|
267
|
|
|
|
|
|
|
@role_prototypes; |
268
|
39
|
|
|
|
|
103
|
$desc->{roles} = \@instances; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub _assert_all_role_params_are_bound_to_values { |
272
|
39
|
|
|
39
|
|
85
|
my($desc, @role_instances) = @_; |
273
|
|
|
|
|
|
|
|
274
|
39
|
|
|
|
|
96
|
foreach my $instance ( @role_instances ) { |
275
|
52
|
|
|
|
|
133
|
my $role_name = $instance->role_name; |
276
|
52
|
|
|
|
|
239
|
my %expected_params = map { $_ => 1 } |
|
5
|
|
|
|
|
14
|
|
277
|
|
|
|
|
|
|
UR::Role::Param->param_names_for_role($role_name); |
278
|
52
|
|
|
|
|
108
|
my $got_params = $instance->role_params; |
279
|
52
|
100
|
|
|
|
140
|
if (my @missing = grep { ! exists($got_params->{$_}) } keys %expected_params) { |
|
5
|
|
|
|
|
18
|
|
280
|
2
|
|
|
|
|
28
|
Carp::croak("Role $role_name expects values for these params: ",join(', ', @missing)); |
281
|
|
|
|
|
|
|
} |
282
|
50
|
100
|
|
|
|
158
|
if (my @extra = grep { ! exists($expected_params{$_}) } keys %$got_params) { |
|
4
|
|
|
|
|
15
|
|
283
|
1
|
|
|
|
|
17
|
Carp::croak("Role $role_name does not recognize these params: ",join(', ', @extra)); |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
} |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub _merge_role_meta_properties_into_class_desc { |
290
|
35
|
|
|
35
|
|
38
|
my($desc, $meta_properties_to_add) = @_; |
291
|
|
|
|
|
|
|
|
292
|
35
|
|
|
|
|
71
|
my $valid_signals = delete $meta_properties_to_add->{valid_signals}; |
293
|
35
|
|
|
|
|
81
|
my @meta_prop_names = keys %$meta_properties_to_add; |
294
|
35
|
|
|
|
|
67
|
@$desc{@meta_prop_names} = @$meta_properties_to_add{@meta_prop_names}; |
295
|
35
|
100
|
|
|
|
85
|
if ($valid_signals) { |
296
|
3
|
|
|
|
|
4
|
push @{$desc->{valid_signals}}, @$valid_signals; |
|
3
|
|
|
|
|
7
|
|
297
|
|
|
|
|
|
|
}; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
sub _merge_role_properties_into_class_desc { |
301
|
35
|
|
|
35
|
|
38
|
my($desc, $properties_to_add) = @_; |
302
|
|
|
|
|
|
|
|
303
|
35
|
|
|
|
|
70
|
my @property_names = keys %$properties_to_add; |
304
|
35
|
|
|
|
|
43
|
@{$desc->{has}}{@property_names} = @$properties_to_add{@property_names}; |
|
35
|
|
|
|
|
172
|
|
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub _merge_role_id_property_names_into_class_desc { |
308
|
35
|
|
|
35
|
|
42
|
my($desc, $id_properties_to_add) = @_; |
309
|
|
|
|
|
|
|
|
310
|
35
|
|
|
|
|
57
|
push @{$desc->{id_by}}, @$id_properties_to_add; |
|
35
|
|
|
|
|
75
|
|
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
sub _role_prototypes_with_params_for_class_desc { |
314
|
59
|
|
|
59
|
|
75
|
my $desc = shift; |
315
|
|
|
|
|
|
|
|
316
|
59
|
|
|
|
|
80
|
my @role_prototypes; |
317
|
59
|
|
|
|
|
52
|
foreach my $role_name ( @{ $desc->{roles} } ) { |
|
59
|
|
|
|
|
93
|
|
318
|
81
|
|
|
|
|
76
|
my $role; |
319
|
81
|
|
|
|
|
65
|
my $exception = do { |
320
|
81
|
|
|
|
|
70
|
local $@; |
321
|
81
|
|
|
|
|
91
|
$role = eval { $role_name->__role__ }; |
|
81
|
|
|
|
|
220
|
|
322
|
81
|
|
|
|
|
125
|
$@; |
323
|
|
|
|
|
|
|
}; |
324
|
81
|
100
|
|
|
|
138
|
unless ($role) { |
325
|
3
|
|
|
|
|
6
|
my $class_name = $desc->{class_name}; |
326
|
3
|
|
|
|
|
31
|
Carp::croak("Cannot apply role $role_name to class $class_name: $exception"); |
327
|
|
|
|
|
|
|
} |
328
|
78
|
|
|
|
|
122
|
push @role_prototypes, $role; |
329
|
|
|
|
|
|
|
} |
330
|
56
|
|
|
|
|
97
|
return @role_prototypes; |
331
|
|
|
|
|
|
|
} |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
sub _collect_id_property_names_from_roles { |
334
|
47
|
|
|
47
|
|
76
|
my($desc, @role_objs) = @_; |
335
|
|
|
|
|
|
|
|
336
|
47
|
|
|
|
|
66
|
my %class_id_by_properties = map { $_ => 1 } @{ $desc->{id_by} }; |
|
2
|
|
|
|
|
7
|
|
|
47
|
|
|
|
|
96
|
|
337
|
13
|
|
|
|
|
34
|
my %class_property_is_id_by = map { $_ => $class_id_by_properties{$_} } |
338
|
47
|
|
|
|
|
66
|
keys %{ $desc->{has} }; |
|
47
|
|
|
|
|
102
|
|
339
|
|
|
|
|
|
|
|
340
|
47
|
|
|
|
|
58
|
my @property_names_to_add; |
341
|
47
|
|
|
|
|
84
|
foreach my $role ( @role_objs ) { |
342
|
66
|
|
|
|
|
157
|
my @role_id_property_names = $role->id_by_property_names; |
343
|
|
|
|
|
|
|
|
344
|
66
|
100
|
|
|
|
90
|
my @conflict = grep { exists($class_property_is_id_by{$_}) and ! $class_property_is_id_by{$_} } |
|
2
|
|
|
|
|
120
|
|
345
|
|
|
|
|
|
|
@role_id_property_names; |
346
|
66
|
100
|
|
|
|
124
|
if (@conflict) { |
347
|
|
|
|
|
|
|
Carp::croak(sprintf(q(Cannot compose role %s: Property '%s' was declared as a normal property in class %s, but as an ID property in the role), |
348
|
|
|
|
|
|
|
$role->role_name, |
349
|
|
|
|
|
|
|
join(q(', '), @conflict), |
350
|
|
|
|
|
|
|
$desc->{class_name}, |
351
|
1
|
|
|
|
|
3
|
)); |
352
|
|
|
|
|
|
|
} |
353
|
65
|
|
|
|
|
98
|
push @property_names_to_add, @role_id_property_names; |
354
|
|
|
|
|
|
|
} |
355
|
46
|
|
|
|
|
94
|
return \@property_names_to_add; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub _collect_properties_from_roles { |
359
|
46
|
|
|
46
|
|
62
|
my($desc, @role_objs) = @_; |
360
|
|
|
|
|
|
|
|
361
|
46
|
|
|
|
|
73
|
my $properties_from_class = $desc->{has}; |
362
|
|
|
|
|
|
|
|
363
|
46
|
|
|
|
|
51
|
my(%properties_to_add, %source_for_properties_to_add); |
364
|
46
|
|
|
|
|
78
|
foreach my $role ( @role_objs ) { |
365
|
65
|
|
|
|
|
136
|
my @role_property_names = $role->has_property_names; |
366
|
65
|
|
|
|
|
88
|
foreach my $property_name ( @role_property_names ) { |
367
|
23
|
|
|
|
|
54
|
my $prop_definition = $role->property_data($property_name); |
368
|
23
|
100
|
|
|
|
46
|
if (my $conflict = $source_for_properties_to_add{$property_name}) { |
369
|
3
|
|
|
|
|
8
|
Carp::croak(sprintf(q(Cannot compose role %s: Property '%s' conflicts with property in role %s), |
370
|
|
|
|
|
|
|
$role->role_name, $property_name, $conflict)); |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
|
373
|
20
|
|
|
|
|
41
|
$source_for_properties_to_add{$property_name} = $role->role_name; |
374
|
|
|
|
|
|
|
|
375
|
20
|
100
|
|
|
|
46
|
next if exists $properties_from_class->{$property_name}; |
376
|
|
|
|
|
|
|
|
377
|
17
|
|
|
|
|
42
|
$properties_to_add{$property_name} = $prop_definition; |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
} |
380
|
43
|
|
|
|
|
130
|
return UR::Util::deep_copy(\%properties_to_add); |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
sub _collect_overloads_from_roles { |
384
|
42
|
|
|
42
|
|
65
|
my($desc, @role_objs) = @_; |
385
|
|
|
|
|
|
|
|
386
|
42
|
|
|
|
|
99
|
my $overloads_from_class = _introspect_overloads($desc->{class_name}); |
387
|
|
|
|
|
|
|
|
388
|
42
|
|
|
|
|
1648
|
my(%overloads_to_add, %source_for_overloads_to_add); |
389
|
42
|
|
|
|
|
94
|
my $fallback_validator = _create_fallback_validator(); |
390
|
|
|
|
|
|
|
|
391
|
42
|
|
|
|
|
65
|
foreach my $role ( @role_objs ) { |
392
|
57
|
|
|
|
|
126
|
my $role_name = $role->role_name; |
393
|
57
|
|
|
|
|
121
|
my $overloads_this_role = $role->overloads; |
394
|
|
|
|
|
|
|
|
395
|
57
|
|
|
|
|
153
|
$fallback_validator->($role_name, $overloads_this_role->{fallback}); |
396
|
56
|
|
|
|
|
207
|
while( my($op, $impl) = each(%$overloads_this_role)) { |
397
|
26
|
100
|
|
|
|
54
|
next if ($op eq 'fallback'); |
398
|
16
|
100
|
|
|
|
33
|
if (my $conflict = $source_for_overloads_to_add{$op}) { |
399
|
1
|
|
|
|
|
12
|
Carp::croak("Cannot compose role $role_name: Overload '$op' conflicts with overload in role $conflict"); |
400
|
|
|
|
|
|
|
} |
401
|
15
|
|
|
|
|
18
|
$source_for_overloads_to_add{$op} = $role_name; |
402
|
|
|
|
|
|
|
|
403
|
15
|
100
|
|
|
|
23
|
next if exists $overloads_from_class->{$op}; |
404
|
|
|
|
|
|
|
|
405
|
14
|
|
|
|
|
40
|
$overloads_to_add{$op} = $impl; |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
|
409
|
40
|
|
|
|
|
57
|
my $fallback = $fallback_validator->(); |
410
|
40
|
100
|
|
|
|
76
|
$overloads_to_add{fallback} = $fallback if defined $fallback; |
411
|
40
|
|
|
|
|
279
|
return \%overloads_to_add; |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
sub _collect_method_modifiers_from_roles { |
415
|
40
|
|
|
40
|
|
69
|
my($desc, @role_objs) = @_; |
416
|
|
|
|
|
|
|
|
417
|
40
|
|
|
|
|
78
|
my $class_name = $desc->{class_name}; |
418
|
40
|
|
|
|
|
68
|
my @all_modifiers = map { $_->method_modifiers } @role_objs; |
|
53
|
|
|
|
|
148
|
|
419
|
|
|
|
|
|
|
|
420
|
40
|
|
|
|
|
101
|
my $isa = join('::', $class_name, 'ISA'); |
421
|
266
|
|
|
266
|
|
1355
|
no strict 'refs'; |
|
266
|
|
|
|
|
444
|
|
|
266
|
|
|
|
|
10738
|
|
422
|
40
|
|
|
|
|
106
|
local @$isa = (@$isa, @{$desc->{is}}); |
|
40
|
|
|
|
|
742
|
|
423
|
266
|
|
|
266
|
|
1005
|
use strict 'refs'; |
|
266
|
|
|
|
|
363
|
|
|
266
|
|
|
|
|
409550
|
|
424
|
|
|
|
|
|
|
|
425
|
40
|
|
|
|
|
141
|
foreach my $mod ( @all_modifiers ) { |
426
|
6
|
100
|
|
|
|
30
|
unless ($class_name->can($mod->name)) { |
427
|
1
|
|
|
|
|
56
|
my $role_name = $mod->role->role_name; |
428
|
1
|
|
|
|
|
6
|
my $type = $mod->type; |
429
|
1
|
|
|
|
|
4
|
my $subname = $mod->name; |
430
|
1
|
|
|
|
|
21
|
Carp::croak(qq(Cannot compose role $role_name: Cannot apply '$type' method modifier: Method "$subname" not found via class $class_name)); |
431
|
|
|
|
|
|
|
} |
432
|
|
|
|
|
|
|
} |
433
|
39
|
|
|
|
|
229
|
return \@all_modifiers; |
434
|
|
|
|
|
|
|
} |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
sub _create_fallback_validator { |
437
|
42
|
|
|
42
|
|
59
|
my($fallback, $fallback_set_in); |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
return sub { |
440
|
97
|
100
|
|
97
|
|
201
|
unless (@_) { |
441
|
|
|
|
|
|
|
# no args, return current value |
442
|
40
|
|
|
|
|
85
|
return $fallback; |
443
|
|
|
|
|
|
|
} |
444
|
|
|
|
|
|
|
|
445
|
57
|
|
|
|
|
121
|
my($role_name, $value) = @_; |
446
|
57
|
100
|
100
|
|
|
159
|
if (defined($value) and !defined($fallback)) { |
447
|
5
|
|
|
|
|
6
|
$fallback = $value; |
448
|
5
|
|
|
|
|
6
|
$fallback_set_in = $role_name; |
449
|
5
|
|
|
|
|
6
|
return 1; |
450
|
|
|
|
|
|
|
} |
451
|
52
|
100
|
100
|
|
|
148
|
return 1 unless (defined($fallback) and defined ($value)); |
452
|
3
|
100
|
75
|
|
|
15
|
return 1 unless ($fallback xor $value); |
453
|
|
|
|
|
|
|
|
454
|
1
|
0
|
|
|
|
21
|
Carp::croak(sprintf(q(Cannot compose role %s: fallback value '%s' conflicts with fallback value '%s' in role %s), |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
455
|
|
|
|
|
|
|
$role_name, |
456
|
|
|
|
|
|
|
$value ? $value : defined($value) ? 'FALSE' : 'UNDEF', |
457
|
|
|
|
|
|
|
$fallback ? $fallback : defined($fallback) ? 'FALSE' : 'UNDEF', |
458
|
|
|
|
|
|
|
$fallback_set_in)); |
459
|
42
|
|
|
|
|
177
|
}; |
460
|
|
|
|
|
|
|
} |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
sub _collect_meta_properties_from_roles { |
464
|
43
|
|
|
43
|
|
75
|
my($desc, @role_objs) = @_; |
465
|
|
|
|
|
|
|
|
466
|
43
|
|
|
|
|
50
|
my(%meta_properties_to_add, %source_for_meta_properties_to_add); |
467
|
43
|
|
|
|
|
75
|
foreach my $role ( @role_objs ) { |
468
|
59
|
|
|
|
|
164
|
foreach my $meta_prop_name ( $role->meta_properties_to_compose_into_classes ) { |
469
|
934
|
100
|
100
|
|
|
1735
|
next if (defined $desc->{$meta_prop_name} and $meta_prop_name ne 'valid_signals'); |
470
|
751
|
100
|
|
|
|
1325
|
next unless defined $role->$meta_prop_name; |
471
|
|
|
|
|
|
|
|
472
|
16
|
100
|
|
|
|
22
|
if ($meta_prop_name ne 'valid_signals') { |
473
|
12
|
100
|
|
|
|
22
|
if (exists $meta_properties_to_add{$meta_prop_name}) { |
474
|
|
|
|
|
|
|
Carp::croak(sprintf(q(Cannot compose role %s: Meta property '%s' conflicts with meta property from role %s), |
475
|
|
|
|
|
|
|
$role->role_name, |
476
|
|
|
|
|
|
|
$meta_prop_name, |
477
|
1
|
|
|
|
|
4
|
$source_for_meta_properties_to_add{$meta_prop_name})); |
478
|
|
|
|
|
|
|
} |
479
|
11
|
|
|
|
|
18
|
$meta_properties_to_add{$meta_prop_name} = $role->$meta_prop_name; |
480
|
11
|
|
|
|
|
18
|
$source_for_meta_properties_to_add{$meta_prop_name} = $role->role_name; |
481
|
|
|
|
|
|
|
} else { |
482
|
4
|
|
50
|
|
|
15
|
$meta_properties_to_add{valid_signals} ||= []; |
483
|
4
|
|
|
|
|
5
|
push @{ $meta_properties_to_add{valid_signals} }, @{ $role->valid_signals }; |
|
4
|
|
|
|
|
5
|
|
|
4
|
|
|
|
|
6
|
|
484
|
|
|
|
|
|
|
} |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
} |
487
|
42
|
|
|
|
|
104
|
return UR::Util::deep_copy(\%meta_properties_to_add); |
488
|
|
|
|
|
|
|
} |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
sub _validate_role_requirements { |
491
|
54
|
|
|
54
|
|
80
|
my($desc, @role_objs) = @_; |
492
|
|
|
|
|
|
|
|
493
|
54
|
|
|
|
|
92
|
my $class_name = $desc->{class_name}; |
494
|
54
|
|
|
|
|
60
|
my %found_properties_and_methods = map { $_ => 1 } keys %{ $desc->{has} }; |
|
16
|
|
|
|
|
33
|
|
|
54
|
|
|
|
|
101
|
|
495
|
|
|
|
|
|
|
|
496
|
54
|
|
|
|
|
96
|
foreach my $role ( @role_objs ) { |
497
|
74
|
|
|
|
|
88
|
foreach my $requirement ( @{ $role->requires } ) { |
|
74
|
|
|
|
|
157
|
|
498
|
15
|
100
|
100
|
|
|
52
|
unless ($found_properties_and_methods{ $requirement } |
499
|
|
|
|
|
|
|
||= _class_desc_lineage_has_method_or_property($desc, $requirement)) |
500
|
|
|
|
|
|
|
{ |
501
|
3
|
|
|
|
|
8
|
my $role_name = $role->role_name; |
502
|
3
|
|
|
|
|
36
|
Carp::croak("Cannot compose role $role_name: missing required property or method '$requirement'"); |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
# Properties and methods from this role can satisfy requirements for later roles |
507
|
71
|
|
|
|
|
154
|
foreach my $name ( $role->has_property_names, $role->method_names ) { |
508
|
72
|
|
|
|
|
113
|
$found_properties_and_methods{$name} = 1; |
509
|
|
|
|
|
|
|
} |
510
|
|
|
|
|
|
|
} |
511
|
|
|
|
|
|
|
|
512
|
51
|
|
|
|
|
75
|
return 1; |
513
|
|
|
|
|
|
|
} |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
sub _validate_role_exclusions { |
516
|
56
|
|
|
56
|
|
81
|
my($desc, @role_objs) = @_; |
517
|
|
|
|
|
|
|
|
518
|
56
|
|
|
|
|
58
|
my %role_names = map { $_ => $_ } @{ $desc->{roles} }; |
|
78
|
|
|
|
|
174
|
|
|
56
|
|
|
|
|
122
|
|
519
|
56
|
|
|
|
|
90
|
foreach my $role ( @role_objs ) { |
520
|
|
|
|
|
|
|
|
521
|
3
|
|
|
|
|
6
|
my @conflicts = grep { defined } |
522
|
77
|
|
|
|
|
76
|
@role_names{ @{ $role->excludes } }; |
|
77
|
|
|
|
|
192
|
|
523
|
77
|
100
|
|
|
|
161
|
if (@conflicts) { |
524
|
2
|
|
|
|
|
3
|
my $class_name = $desc->{class_name}; |
525
|
2
|
50
|
|
|
|
7
|
my $plural = @conflicts > 1 ? 's' : ''; |
526
|
|
|
|
|
|
|
Carp::croak(sprintf('Cannot compose role%s %s into class %s: Role %s excludes %s', |
527
|
|
|
|
|
|
|
$plural, |
528
|
|
|
|
|
|
|
join(', ', @conflicts), |
529
|
|
|
|
|
|
|
$desc->{class_name}, |
530
|
2
|
50
|
|
|
|
6
|
$role->role_name, |
531
|
|
|
|
|
|
|
$plural ? 'them' : 'it')); |
532
|
|
|
|
|
|
|
} |
533
|
|
|
|
|
|
|
} |
534
|
54
|
|
|
|
|
78
|
return 1; |
535
|
|
|
|
|
|
|
} |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
sub _validate_class_method_overrides_consumed_roles { |
538
|
12763
|
|
|
12763
|
|
14872
|
my $desc = shift; |
539
|
|
|
|
|
|
|
|
540
|
12763
|
|
|
|
|
20294
|
my $class_name = $desc->{class_name}; |
541
|
|
|
|
|
|
|
my %this_class_role_names = $desc->{roles} |
542
|
81
|
100
|
|
|
|
285
|
? map { ref($_) ? ($_->role_name => 1) : ($_ => 1) } |
543
|
12763
|
50
|
|
|
|
27189
|
@{$desc->{roles}} |
|
12763
|
|
|
|
|
27406
|
|
544
|
|
|
|
|
|
|
: (); |
545
|
12763
|
|
|
|
|
36640
|
my $this_class_methods = UR::Util::coderefs_for_package($class_name); |
546
|
12763
|
|
|
|
|
45328
|
while (my($method_name, $subref) = each %$this_class_methods) { |
547
|
79076
|
|
|
|
|
100125
|
my @overrides = UR::AttributeHandlers::get_overrides_for_coderef($subref); |
548
|
79076
|
100
|
|
|
|
172322
|
next unless (@overrides); |
549
|
|
|
|
|
|
|
|
550
|
7
|
|
|
|
|
9
|
my @missing_role_names = grep { ! exists $this_class_role_names{$_} } |
|
8
|
|
|
|
|
20
|
|
551
|
|
|
|
|
|
|
@overrides; |
552
|
7
|
100
|
|
|
|
25
|
if (@missing_role_names) { |
553
|
1
|
|
|
|
|
14
|
Carp::croak("Class method '$method_name' declares Overrides for roles the class does not consume: " |
554
|
|
|
|
|
|
|
. join(', ', @missing_role_names)); |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
} |
557
|
12762
|
|
|
|
|
27758
|
return 1; |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
sub _validate_class_desc_overrides { |
561
|
51
|
|
|
51
|
|
77
|
my($desc, @roles) = @_; |
562
|
|
|
|
|
|
|
|
563
|
51
|
|
|
|
|
66
|
my $class_name = $desc->{class_name}; |
564
|
102
|
|
|
|
|
77
|
my %this_class_methods = map { %{ UR::Util::coderefs_for_package($_) } } |
|
102
|
|
|
|
|
239
|
|
565
|
51
|
|
|
|
|
50
|
(@{$desc->{is}}, $class_name); |
|
51
|
|
|
|
|
86
|
|
566
|
|
|
|
|
|
|
|
567
|
51
|
|
|
|
|
175
|
my %overridden_methods_by_role; |
568
|
51
|
|
|
|
|
246
|
foreach my $method_name ( keys %this_class_methods ) { |
569
|
2573
|
100
|
|
|
|
2884
|
if (my @role_names = UR::AttributeHandlers::get_overrides_for_coderef($this_class_methods{$method_name})) { |
570
|
6
|
|
|
|
|
12
|
foreach my $role_name ( @role_names ) { |
571
|
7
|
|
50
|
|
|
34
|
$overridden_methods_by_role{$role_name} ||= []; |
572
|
7
|
|
|
|
|
7
|
push @{$overridden_methods_by_role{$role_name}}, $method_name; |
|
7
|
|
|
|
|
23
|
|
573
|
|
|
|
|
|
|
} |
574
|
|
|
|
|
|
|
} |
575
|
|
|
|
|
|
|
} |
576
|
|
|
|
|
|
|
|
577
|
51
|
|
|
|
|
133
|
foreach my $role ( @roles ) { |
578
|
71
|
|
|
|
|
213
|
my $role_name = $role->role_name; |
579
|
71
|
|
|
|
|
162
|
my $this_role_methods = $role->methods; |
580
|
71
|
|
|
|
|
138
|
my @this_role_method_names = keys( %$this_role_methods ); |
581
|
|
|
|
|
|
|
|
582
|
71
|
|
|
|
|
75
|
my %method_is_overridden; |
583
|
8
|
|
66
|
|
|
35
|
my @conflict_methods = grep { ! ($method_is_overridden{$_} ||= _coderef_overrides_package($this_class_methods{$_}, $role_name)) } |
584
|
71
|
|
|
|
|
99
|
grep { exists $this_class_methods{$_} } |
|
45
|
|
|
|
|
107
|
|
585
|
|
|
|
|
|
|
@this_role_method_names; |
586
|
71
|
100
|
|
|
|
138
|
if (@conflict_methods) { |
587
|
3
|
50
|
|
|
|
11
|
my $plural = scalar(@conflict_methods) > 1 ? 's' : ''; |
588
|
3
|
50
|
|
|
|
8
|
my $conflicts = scalar(@conflict_methods) > 1 ? 'conflict' : 'conflicts'; |
589
|
|
|
|
|
|
|
|
590
|
3
|
|
|
|
|
3
|
my %conflicting_sources; |
591
|
|
|
|
|
|
|
CONFLICTING_METHOD_NAME: |
592
|
3
|
|
|
|
|
4
|
foreach my $conflicting_method_name ( @conflict_methods ) { |
593
|
3
|
|
|
|
|
4
|
foreach my $source_class_name ( $class_name, @{$desc->{is}} ) { |
|
3
|
|
|
|
|
8
|
|
594
|
4
|
100
|
|
|
|
80
|
if ($source_class_name->can($conflicting_method_name)) { |
595
|
3
|
|
|
|
|
37
|
$conflicting_sources{$conflicting_method_name} = $source_class_name; |
596
|
3
|
|
|
|
|
7
|
next CONFLICTING_METHOD_NAME; |
597
|
|
|
|
|
|
|
} |
598
|
|
|
|
|
|
|
} |
599
|
0
|
|
|
|
|
0
|
$conflicting_sources{$conflicting_method_name} = ''; |
600
|
|
|
|
|
|
|
} |
601
|
|
|
|
|
|
|
Carp::croak("Cannot compose role $role_name: " |
602
|
|
|
|
|
|
|
. "Method name${plural} $conflicts with class $class_name:\n" |
603
|
3
|
|
|
|
|
17
|
. join("\n", map { sprintf("\t%s (from %s)\n", $_, $conflicting_sources{$_}) } |
|
3
|
|
|
|
|
71
|
|
604
|
|
|
|
|
|
|
keys %conflicting_sources) |
605
|
|
|
|
|
|
|
. "Did you forget to add the 'Overrides' attribute?"); |
606
|
|
|
|
|
|
|
} |
607
|
|
|
|
|
|
|
|
608
|
7
|
|
100
|
|
|
26
|
my @missing_methods = grep { ! exists $this_role_methods->{$_} and ! exists $role->has->{$_} } |
609
|
68
|
|
|
|
|
61
|
@{$overridden_methods_by_role{$role_name}}; |
|
68
|
|
|
|
|
144
|
|
610
|
68
|
100
|
|
|
|
175
|
if (@missing_methods) { |
611
|
1
|
50
|
|
|
|
4
|
my $plural = scalar(@missing_methods) > 1 ? 's' : ''; |
612
|
1
|
|
|
|
|
3
|
my $method_list = join(q(', '), @missing_methods); |
613
|
1
|
|
|
|
|
26
|
Carp::croak("Cannot compose role $role_name: " |
614
|
|
|
|
|
|
|
. "Class method${plural} '$method_list' declares it Overrides non-existant method in the role."); |
615
|
|
|
|
|
|
|
} |
616
|
|
|
|
|
|
|
} |
617
|
|
|
|
|
|
|
|
618
|
47
|
|
|
|
|
211
|
return 1; |
619
|
|
|
|
|
|
|
} |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
sub _class_desc_lineage_has_method_or_property { |
622
|
10
|
|
|
10
|
|
12
|
my($desc, $requirement) = @_; |
623
|
|
|
|
|
|
|
|
624
|
10
|
|
|
|
|
15
|
my $class_name = $desc->{class_name}; |
625
|
10
|
100
|
|
|
|
50
|
if (my $can = $class_name->can($requirement)) { |
626
|
5
|
|
|
|
|
73
|
return $can; |
627
|
|
|
|
|
|
|
} |
628
|
|
|
|
|
|
|
|
629
|
5
|
|
|
|
|
167
|
my @is = @{ $desc->{is} }; |
|
5
|
|
|
|
|
9
|
|
630
|
5
|
|
|
|
|
7
|
my %seen; |
631
|
5
|
|
|
|
|
10
|
while(my $parent = shift @is) { |
632
|
5
|
50
|
|
|
|
13
|
next if $seen{$parent}++; |
633
|
|
|
|
|
|
|
|
634
|
5
|
100
|
|
|
|
12
|
if (my $can = $parent->can($requirement)) { |
635
|
2
|
|
|
|
|
19
|
return $can; |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
|
638
|
3
|
|
|
|
|
91
|
my $parent_meta = $parent->__meta__; |
639
|
3
|
50
|
|
|
|
10
|
if (my $prop_meta = $parent_meta->property($requirement)) { |
640
|
0
|
|
|
|
|
0
|
return $prop_meta; |
641
|
|
|
|
|
|
|
} |
642
|
|
|
|
|
|
|
} |
643
|
3
|
|
|
|
|
12
|
return; |
644
|
|
|
|
|
|
|
} |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
sub _import_methods_from_roles_into_namespace { |
647
|
36
|
|
|
36
|
|
46
|
my($class_name, $roles) = @_; |
648
|
|
|
|
|
|
|
|
649
|
36
|
|
|
|
|
86
|
my $this_class_methods = UR::Util::coderefs_for_package($class_name); |
650
|
|
|
|
|
|
|
|
651
|
36
|
|
|
|
|
45
|
my(%all_imported_methods, %method_sources); |
652
|
36
|
|
|
|
|
61
|
foreach my $role ( @$roles ) { |
653
|
49
|
|
|
|
|
110
|
my $this_role_methods = $role->methods; |
654
|
49
|
|
|
|
|
99
|
my @this_role_method_names = keys( %$this_role_methods ); |
655
|
|
|
|
|
|
|
|
656
|
2
|
|
|
|
|
4
|
my @conflicting = grep { ! exists($this_class_methods->{$_}) } # not a conflict if the class overrides |
657
|
49
|
|
|
|
|
73
|
grep { exists $all_imported_methods{$_} } |
|
30
|
|
|
|
|
60
|
|
658
|
|
|
|
|
|
|
@this_role_method_names; |
659
|
|
|
|
|
|
|
|
660
|
49
|
100
|
|
|
|
97
|
if (@conflicting) { |
661
|
1
|
50
|
|
|
|
3
|
my $plural = scalar(@conflicting) > 1 ? 's' : ''; |
662
|
1
|
50
|
|
|
|
3
|
my $conflicts = scalar(@conflicting) > 1 ? 'conflict' : 'conflicts'; |
663
|
|
|
|
|
|
|
Carp::croak('Cannot compose role ' . $role->role_name |
664
|
|
|
|
|
|
|
. ": method${plural} $conflicts with those defined in other roles\n\t" |
665
|
1
|
|
|
|
|
3
|
. join("\n\t", join('::', map { ( $method_sources{$_}, $_ ) } @conflicting))); |
|
1
|
|
|
|
|
12
|
|
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
|
668
|
48
|
|
|
|
|
118
|
@method_sources{ @this_role_method_names } = ($role->role_name) x @this_role_method_names; |
669
|
48
|
|
|
|
|
95
|
@all_imported_methods{ @this_role_method_names } = @$this_role_methods{ @this_role_method_names }; |
670
|
|
|
|
|
|
|
} |
671
|
|
|
|
|
|
|
|
672
|
35
|
|
|
|
|
62
|
delete @all_imported_methods{ keys %$this_class_methods }; # Don't import roles' methods already defined on the class |
673
|
35
|
|
|
|
|
87
|
foreach my $name ( keys %all_imported_methods ) { |
674
|
|
|
|
|
|
|
Sub::Install::install_sub({ |
675
|
24
|
|
|
|
|
604
|
code => $all_imported_methods{$name}, |
676
|
|
|
|
|
|
|
as => $name, |
677
|
|
|
|
|
|
|
into => $class_name, |
678
|
|
|
|
|
|
|
}); |
679
|
|
|
|
|
|
|
} |
680
|
|
|
|
|
|
|
} |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
sub _coderef_overrides_package { |
683
|
8
|
|
|
8
|
|
14
|
my($coderef, $package) = @_; |
684
|
|
|
|
|
|
|
|
685
|
8
|
|
|
|
|
17
|
my @overrides = UR::AttributeHandlers::get_overrides_for_coderef($coderef); |
686
|
8
|
|
|
7
|
|
54
|
return any { $_ eq $package } @overrides; |
|
7
|
|
|
|
|
32
|
|
687
|
|
|
|
|
|
|
} |
688
|
|
|
|
|
|
|
|
689
|
|
|
|
|
|
|
sub _apply_overloads_to_namespace { |
690
|
35
|
|
|
35
|
|
48
|
my($class_name, $overloads) = @_; |
691
|
|
|
|
|
|
|
|
692
|
35
|
|
|
|
|
37
|
my(%cooked_overloads); |
693
|
35
|
|
|
|
|
116
|
while( my($op, $impl) = each %$overloads) { |
694
|
16
|
100
|
|
|
|
53
|
$cooked_overloads{$op} = ref $impl |
695
|
|
|
|
|
|
|
? sprintf(q($overloads->{'%s'}), $op) |
696
|
|
|
|
|
|
|
: qq('$impl'); |
697
|
|
|
|
|
|
|
} |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
my $string = "package $class_name;\n" |
700
|
|
|
|
|
|
|
. 'use overload ' |
701
|
35
|
|
|
|
|
131
|
. join(",\n\t", map { sprintf(q('%s' => %s), $_, $cooked_overloads{$_}) } keys %cooked_overloads) |
|
16
|
|
|
|
|
50
|
|
702
|
|
|
|
|
|
|
. ';'; |
703
|
|
|
|
|
|
|
|
704
|
35
|
|
|
|
|
35
|
my $exception; |
705
|
35
|
|
|
|
|
33
|
do { |
706
|
35
|
|
|
|
|
40
|
local $@; |
707
|
35
|
|
|
79
|
|
2833
|
eval $string; |
|
1
|
|
|
79
|
|
5
|
|
|
1
|
|
|
79
|
|
2
|
|
|
1
|
|
|
79
|
|
3
|
|
|
1
|
|
|
79
|
|
5
|
|
|
1
|
|
|
79
|
|
2
|
|
|
1
|
|
|
79
|
|
4
|
|
|
1
|
|
|
79
|
|
6
|
|
|
1
|
|
|
79
|
|
2
|
|
|
1
|
|
|
79
|
|
5
|
|
|
1
|
|
|
79
|
|
6
|
|
|
1
|
|
|
79
|
|
1
|
|
|
1
|
|
|
79
|
|
5
|
|
|
1
|
|
|
79
|
|
6
|
|
|
1
|
|
|
79
|
|
2
|
|
|
1
|
|
|
79
|
|
5
|
|
|
1
|
|
|
79
|
|
6
|
|
|
1
|
|
|
79
|
|
1
|
|
|
1
|
|
|
79
|
|
4
|
|
|
1
|
|
|
79
|
|
7
|
|
|
1
|
|
|
79
|
|
1
|
|
|
1
|
|
|
79
|
|
7
|
|
|
1
|
|
|
79
|
|
7
|
|
|
1
|
|
|
79
|
|
1
|
|
|
1
|
|
|
79
|
|
5
|
|
|
1
|
|
|
79
|
|
6
|
|
|
1
|
|
|
79
|
|
1
|
|
|
1
|
|
|
79
|
|
5
|
|
|
1
|
|
|
79
|
|
5
|
|
|
1
|
|
|
79
|
|
1
|
|
|
1
|
|
|
79
|
|
5
|
|
|
1
|
|
|
79
|
|
7
|
|
|
1
|
|
|
79
|
|
1
|
|
|
1
|
|
|
79
|
|
7
|
|
|
1
|
|
|
78
|
|
6
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
6
|
|
708
|
35
|
|
|
|
|
1759
|
$exception = $@; |
709
|
|
|
|
|
|
|
}; |
710
|
|
|
|
|
|
|
|
711
|
35
|
50
|
|
|
|
82
|
if ($exception) { |
712
|
0
|
|
|
|
|
0
|
Carp::croak("Failed to apply overloads to package $class_name: $exception"); |
713
|
|
|
|
|
|
|
} |
714
|
35
|
|
|
|
|
66
|
return 1; |
715
|
|
|
|
|
|
|
} |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
sub _apply_method_modifiers_to_namespace { |
718
|
35
|
|
|
35
|
|
46
|
my($desc, $modifiers_list) = @_; |
719
|
|
|
|
|
|
|
|
720
|
35
|
|
|
|
|
65
|
my $class_name = $desc->{class_name}; |
721
|
|
|
|
|
|
|
|
722
|
35
|
|
|
|
|
83
|
my $isa = join('::', $class_name, 'ISA'); |
723
|
266
|
|
|
266
|
|
1428
|
no strict 'refs'; |
|
266
|
|
|
|
|
417
|
|
|
266
|
|
|
|
|
9898
|
|
724
|
35
|
|
|
|
|
81
|
local @$isa = (@$isa, @{$desc->{is}}); |
|
35
|
|
|
|
|
535
|
|
725
|
266
|
|
|
266
|
|
1088
|
use strict 'refs'; |
|
266
|
|
|
|
|
451
|
|
|
266
|
|
|
|
|
82637
|
|
726
|
|
|
|
|
|
|
|
727
|
35
|
|
|
|
|
133
|
foreach my $mod ( @$modifiers_list ) { |
728
|
5
|
|
|
|
|
35
|
$mod->apply_to_package($class_name); |
729
|
|
|
|
|
|
|
} |
730
|
35
|
|
|
|
|
540
|
1; |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
|
733
|
|
|
|
|
|
|
sub _define_role { |
734
|
0
|
|
|
0
|
|
0
|
my($role_name, $func, @params) = @_; |
735
|
|
|
|
|
|
|
|
736
|
0
|
0
|
0
|
|
|
0
|
if (defined($func) and $func eq "role" and @params > 1 and $role_name ne "UR::Role") { |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
737
|
0
|
|
|
|
|
0
|
my @role_params; |
738
|
0
|
0
|
0
|
|
|
0
|
if (@params == 2 and ref($params[1]) eq 'HASH') { |
|
|
0
|
0
|
|
|
|
|
739
|
0
|
|
|
|
|
0
|
@role_params = %{ $params[1] }; |
|
0
|
|
|
|
|
0
|
|
740
|
|
|
|
|
|
|
} |
741
|
|
|
|
|
|
|
elsif (@params == 2 and ref($params[1]) eq 'ARRAY') { |
742
|
0
|
|
|
|
|
0
|
@role_params = @{ $params[1] }; |
|
0
|
|
|
|
|
0
|
|
743
|
|
|
|
|
|
|
} |
744
|
|
|
|
|
|
|
else { |
745
|
0
|
|
|
|
|
0
|
@role_params = @params[1..$#params]; |
746
|
|
|
|
|
|
|
} |
747
|
0
|
|
|
|
|
0
|
my $role = UR::Role->define(role_name => $role_name, @role_params); |
748
|
0
|
0
|
|
|
|
0
|
unless ($role) { |
749
|
0
|
|
|
|
|
0
|
Carp::croak "error defining role $role_name!"; |
750
|
|
|
|
|
|
|
} |
751
|
0
|
|
|
0
|
|
0
|
return sub { $role_name }; |
|
0
|
|
|
|
|
0
|
|
752
|
|
|
|
|
|
|
} else { |
753
|
0
|
|
|
|
|
0
|
return; |
754
|
|
|
|
|
|
|
} |
755
|
|
|
|
|
|
|
} |
756
|
|
|
|
|
|
|
|
757
|
|
|
|
|
|
|
sub _inject_instance_constructor_into_namespace { |
758
|
41
|
|
|
41
|
|
56
|
my $self = shift; |
759
|
|
|
|
|
|
|
|
760
|
41
|
|
|
|
|
126
|
my $package = $self->role_name; |
761
|
41
|
|
|
|
|
94
|
my $full_name = join('::', $package, 'create'); |
762
|
|
|
|
|
|
|
my $sub = Sub::Name::subname $full_name => sub { |
763
|
78
|
|
|
78
|
|
2837
|
my($class, %params) = @_; |
|
|
|
|
79
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
|
78
|
|
|
|
764
|
78
|
|
|
|
|
296
|
return UR::Role::PrototypeWithParams->create(prototype => $self, role_params => \%params); |
765
|
41
|
|
|
|
|
347
|
}; |
766
|
41
|
|
|
|
|
214
|
Sub::Install::reinstall_sub({ |
767
|
|
|
|
|
|
|
into => $package, |
768
|
|
|
|
|
|
|
as => 'create', |
769
|
|
|
|
|
|
|
code => $sub, |
770
|
|
|
|
|
|
|
}); |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
Sub::Install::reinstall_sub({ |
773
|
|
|
|
|
|
|
into => $package, |
774
|
|
|
|
|
|
|
as => '__role__', |
775
|
74
|
|
|
74
|
|
197
|
code => sub { $package->create() }, |
776
|
41
|
|
|
|
|
2191
|
}); |
777
|
|
|
|
|
|
|
} |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
1; |
780
|
|
|
|
|
|
|
|
781
|
|
|
|
|
|
|
__END__ |