line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MOP::Internal::Util; |
2
|
|
|
|
|
|
|
# ABSTRACT: For MOP Internal Use Only |
3
|
|
|
|
|
|
|
|
4
|
35
|
|
|
35
|
|
241
|
use strict; |
|
35
|
|
|
|
|
81
|
|
|
35
|
|
|
|
|
1078
|
|
5
|
35
|
|
|
35
|
|
205
|
use warnings; |
|
35
|
|
|
|
|
76
|
|
|
35
|
|
|
|
|
1039
|
|
6
|
|
|
|
|
|
|
|
7
|
35
|
|
|
35
|
|
213
|
use B (); # nasty stuff, all nasty stuff |
|
35
|
|
|
|
|
163
|
|
|
35
|
|
|
|
|
594
|
|
8
|
35
|
|
|
35
|
|
185
|
use Carp (); # errors and stuff |
|
35
|
|
|
|
|
69
|
|
|
35
|
|
|
|
|
599
|
|
9
|
35
|
|
|
35
|
|
10817
|
use Sub::Name (); # handling some sub stuff |
|
35
|
|
|
|
|
17358
|
|
|
35
|
|
|
|
|
1134
|
|
10
|
35
|
|
|
35
|
|
10586
|
use Sub::Metadata (); # handling other sub stuff |
|
35
|
|
|
|
|
38480
|
|
|
35
|
|
|
|
|
897
|
|
11
|
35
|
|
|
35
|
|
10381
|
use Symbol (); # creating the occasional symbol |
|
35
|
|
|
|
|
26977
|
|
|
35
|
|
|
|
|
871
|
|
12
|
35
|
|
|
35
|
|
254
|
use Scalar::Util (); # I think I use blessed somewhere in here ... |
|
35
|
|
|
|
|
363
|
|
|
35
|
|
|
|
|
638
|
|
13
|
35
|
|
|
35
|
|
11196
|
use Devel::OverloadInfo (); # Sometimes I need to know about overloading |
|
35
|
|
|
|
|
433559
|
|
|
35
|
|
|
|
|
1063
|
|
14
|
35
|
|
|
35
|
|
10981
|
use Devel::Hook (); # for scheduling UNITCHECK blocks ... |
|
35
|
|
|
|
|
33751
|
|
|
35
|
|
|
|
|
19849
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our $VERSION = '0.12'; |
17
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:STEVAN'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
20
|
|
|
|
|
|
|
## Basic Glob access |
21
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub IS_VALID_MODULE_NAME { |
24
|
112
|
|
|
112
|
0
|
242
|
my ($name) = @_; |
25
|
112
|
|
|
|
|
828
|
$name =~ /[A-Z_a-z][0-9A-Z_a-z]*(?:::[0-9A-Z_a-z]+)*/ |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub IS_STASH_REF { |
29
|
4
|
|
|
4
|
0
|
9
|
my ($stash) = @_; |
30
|
4
|
50
|
|
|
|
11
|
Carp::confess('[ARGS] You must specify a stash') |
31
|
|
|
|
|
|
|
unless defined $stash; |
32
|
4
|
100
|
|
|
|
33
|
if ( my $name = B::svref_2object( $stash )->NAME ) { |
33
|
2
|
|
|
|
|
6
|
return IS_VALID_MODULE_NAME( $name ); |
34
|
|
|
|
|
|
|
} |
35
|
2
|
|
|
|
|
8
|
return; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub GET_NAME { |
39
|
1117
|
|
|
1117
|
0
|
1967
|
my ($stash) = @_; |
40
|
1117
|
50
|
|
|
|
2495
|
Carp::confess('[ARGS] You must specify a stash') |
41
|
|
|
|
|
|
|
unless defined $stash; |
42
|
1117
|
|
|
|
|
5732
|
B::svref_2object( $stash )->NAME |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub GET_STASH_NAME { |
46
|
81
|
|
|
81
|
0
|
146
|
my ($stash) = @_; |
47
|
81
|
50
|
|
|
|
189
|
Carp::confess('[ARGS] You must specify a stash') |
48
|
|
|
|
|
|
|
unless defined $stash; |
49
|
81
|
|
|
|
|
1249
|
B::svref_2object( $stash )->STASH->NAME |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub GET_GLOB_NAME { |
53
|
546
|
|
|
546
|
0
|
895
|
my ($stash) = @_; |
54
|
546
|
50
|
|
|
|
1083
|
Carp::confess('[ARGS] You must specify a stash') |
55
|
|
|
|
|
|
|
unless defined $stash; |
56
|
546
|
|
|
|
|
2678
|
B::svref_2object( $stash )->GV->NAME |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub GET_GLOB_STASH_NAME { |
60
|
605
|
|
|
605
|
0
|
1011
|
my ($stash) = @_; |
61
|
605
|
50
|
|
|
|
1233
|
Carp::confess('[ARGS] You must specify a stash') |
62
|
|
|
|
|
|
|
unless defined $stash; |
63
|
605
|
|
|
|
|
4346
|
B::svref_2object( $stash )->GV->STASH->NAME |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub GET_GLOB_SLOT { |
67
|
1591
|
|
|
1591
|
0
|
3551
|
my ($stash, $name, $slot) = @_; |
68
|
|
|
|
|
|
|
|
69
|
1591
|
50
|
|
|
|
3322
|
Carp::confess('[ARGS] You must specify a stash') |
70
|
|
|
|
|
|
|
unless defined $stash; |
71
|
1591
|
50
|
|
|
|
2771
|
Carp::confess('[ARGS] You must specify a name') |
72
|
|
|
|
|
|
|
unless defined $name; |
73
|
1591
|
50
|
|
|
|
2700
|
Carp::confess('[ARGS] You must specify a slot') |
74
|
|
|
|
|
|
|
unless defined $slot; |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# do my best to not autovivify, and |
77
|
|
|
|
|
|
|
# return undef if not |
78
|
1591
|
100
|
|
|
|
3320
|
return unless exists $stash->{ $name }; |
79
|
|
|
|
|
|
|
# occasionally we need to auto-inflate |
80
|
|
|
|
|
|
|
# the optimized version of a required |
81
|
|
|
|
|
|
|
# method, its annoying, but the XS side |
82
|
|
|
|
|
|
|
# should not have to care about this so |
83
|
|
|
|
|
|
|
# it can be removed eventually. |
84
|
1441
|
50
|
100
|
|
|
9041
|
if (( $slot eq 'CODE' && $stash->{ $name } eq "-1" ) || ref $stash->{ $name } ne 'GLOB') { |
|
|
|
66
|
|
|
|
|
85
|
1441
|
|
|
|
|
7991
|
B::svref_2object( $stash )->NAME->can( $name ); |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# return the reference stored in the glob |
90
|
|
|
|
|
|
|
# which might be undef, but that can be |
91
|
|
|
|
|
|
|
# handled by the caller |
92
|
1441
|
|
|
|
|
3539
|
return *{ $stash->{ $name } }{ $slot }; |
|
1441
|
|
|
|
|
7492
|
|
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub SET_GLOB_SLOT { |
96
|
4
|
|
|
4
|
0
|
14
|
my ($stash, $name, $value_ref) = @_; |
97
|
|
|
|
|
|
|
|
98
|
4
|
50
|
|
|
|
18
|
Carp::confess('[ARGS] You must specify a stash') |
99
|
|
|
|
|
|
|
unless defined $stash; |
100
|
4
|
50
|
|
|
|
22
|
Carp::confess('[ARGS] You must specify a name') |
101
|
|
|
|
|
|
|
unless defined $name; |
102
|
4
|
50
|
|
|
|
17
|
Carp::confess('[ARGS] You must specify a value REF') |
103
|
|
|
|
|
|
|
unless defined $value_ref; |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
{ |
106
|
35
|
|
|
35
|
|
315
|
no strict 'refs'; |
|
35
|
|
|
|
|
108
|
|
|
35
|
|
|
|
|
1375
|
|
|
4
|
|
|
|
|
11
|
|
107
|
35
|
|
|
35
|
|
250
|
no warnings 'once'; |
|
35
|
|
|
|
|
87
|
|
|
35
|
|
|
|
|
22651
|
|
108
|
|
|
|
|
|
|
# get the name of the stash, we could have |
109
|
|
|
|
|
|
|
# passed this in, but it is easy to get in |
110
|
|
|
|
|
|
|
# XS, and so we can punt that down the road |
111
|
|
|
|
|
|
|
# for the time being |
112
|
4
|
|
|
|
|
32
|
my $pkg = B::svref_2object( $stash )->NAME; |
113
|
4
|
|
|
|
|
14
|
*{ $pkg . '::' . $name } = $value_ref; |
|
4
|
|
|
|
|
40
|
|
114
|
|
|
|
|
|
|
} |
115
|
4
|
|
|
|
|
14
|
return; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
119
|
|
|
|
|
|
|
## UNITCHECK hook |
120
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub ADD_UNITCHECK_HOOK { |
123
|
5
|
|
|
5
|
0
|
12
|
my ($cv) = @_; |
124
|
5
|
50
|
|
|
|
18
|
Carp::confess('[ARGS] You must specify a CODE reference') |
125
|
|
|
|
|
|
|
unless $cv; |
126
|
5
|
50
|
33
|
|
|
38
|
Carp::confess('[ARGS] You must specify a CODE reference') |
127
|
|
|
|
|
|
|
unless $cv && ref $cv eq 'CODE'; |
128
|
5
|
|
|
|
|
30
|
Devel::Hook->push_UNITCHECK_hook( $cv ); |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
132
|
|
|
|
|
|
|
## CV/Glob introspection |
133
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub CAN_COERCE_TO_CODE_REF { |
136
|
109
|
|
|
109
|
0
|
182
|
my ($object) = @_; |
137
|
109
|
100
|
66
|
|
|
898
|
return 0 unless $object && Scalar::Util::blessed( $object ); |
138
|
|
|
|
|
|
|
# might be just a blessed CODE ref ... |
139
|
26
|
50
|
|
|
|
105
|
return 1 if Scalar::Util::reftype( $object ) eq 'CODE'; |
140
|
|
|
|
|
|
|
# or might be overloaded object ... |
141
|
0
|
0
|
|
|
|
0
|
return 0 unless Devel::OverloadInfo::is_overloaded( $object ); |
142
|
0
|
|
|
|
|
0
|
return exists Devel::OverloadInfo::overload_info( $object )->{'&{}'}; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
sub IS_CV_NULL { |
146
|
926
|
|
|
926
|
0
|
1561
|
my ($cv) = @_; |
147
|
926
|
50
|
|
|
|
1795
|
Carp::confess('[ARGS] You must specify a CODE reference') |
148
|
|
|
|
|
|
|
unless $cv; |
149
|
926
|
50
|
33
|
|
|
3688
|
Carp::confess('[ARGS] You must specify a CODE reference') |
|
|
|
33
|
|
|
|
|
150
|
|
|
|
|
|
|
unless $cv && ref $cv eq 'CODE' |
151
|
|
|
|
|
|
|
|| CAN_COERCE_TO_CODE_REF( $cv ); |
152
|
926
|
|
|
|
|
3559
|
return Sub::Metadata::sub_body_type( $cv ) eq 'UNDEF'; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub DOES_GLOB_HAVE_NULL_CV { |
156
|
160
|
|
|
160
|
0
|
558
|
my ($glob) = @_; |
157
|
160
|
50
|
|
|
|
686
|
Carp::confess('[ARGS] You must specify a GLOB') |
158
|
|
|
|
|
|
|
unless $glob; |
159
|
|
|
|
|
|
|
# NOTE: |
160
|
|
|
|
|
|
|
# If the glob eq -1 that means it may well be a null sub |
161
|
|
|
|
|
|
|
# this seems to be some kind of artifact of an optimization |
162
|
|
|
|
|
|
|
# perhaps, I really don't know, it is odd. It should not |
163
|
|
|
|
|
|
|
# need to be dealt with in XS, it seems to be a Perl language |
164
|
|
|
|
|
|
|
# level thing. |
165
|
|
|
|
|
|
|
# - SL |
166
|
160
|
100
|
|
|
|
617
|
return 1 if $glob eq '-1'; |
167
|
|
|
|
|
|
|
# next lets see if we have a CODE slot ... |
168
|
159
|
100
|
|
|
|
311
|
if ( my $code = *{ $glob }{CODE} ) { |
|
159
|
|
|
|
|
691
|
|
169
|
136
|
|
|
|
|
1166
|
return Sub::Metadata::sub_body_type( $code ) eq 'UNDEF'; |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
# if we had no CODE slot, it can't be a NULL CV ... |
172
|
23
|
|
|
|
|
94
|
return 0; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub CREATE_NULL_CV { |
176
|
3
|
|
|
3
|
0
|
10
|
my ($in_pkg, $name) = @_; |
177
|
3
|
50
|
|
|
|
10
|
Carp::confess('[ARGS] You must specify a package name') |
178
|
|
|
|
|
|
|
unless defined $in_pkg; |
179
|
3
|
50
|
|
|
|
11
|
Carp::confess('[ARGS] You must specify a name') |
180
|
|
|
|
|
|
|
unless defined $name; |
181
|
|
|
|
|
|
|
# this just tries to eval the NULL CV into |
182
|
|
|
|
|
|
|
# place, it is ugly, but works for now |
183
|
3
|
100
|
|
|
|
177
|
eval "sub ${in_pkg}::${name}; 1;" or do { Carp::confess($@) }; |
|
1
|
|
|
|
|
260
|
|
184
|
2
|
|
|
|
|
9
|
return; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub SET_COMP_STASH_FOR_CV { |
188
|
3
|
|
|
3
|
0
|
7
|
my ($cv, $in_pkg) = @_; |
189
|
3
|
50
|
|
|
|
9
|
Carp::confess('[ARGS] You must specify a CODE reference') |
190
|
|
|
|
|
|
|
unless $cv; |
191
|
3
|
50
|
|
|
|
9
|
Carp::confess('[ARGS] You must specify a package name') |
192
|
|
|
|
|
|
|
unless defined $in_pkg; |
193
|
3
|
50
|
66
|
|
|
20
|
Carp::confess('[ARGS] You must specify a CODE reference') |
|
|
|
66
|
|
|
|
|
194
|
|
|
|
|
|
|
unless $cv && ref $cv eq 'CODE' |
195
|
|
|
|
|
|
|
|| CAN_COERCE_TO_CODE_REF( $cv ); |
196
|
3
|
|
|
|
|
18
|
Sub::Metadata::mutate_sub_package( $cv, $in_pkg ); |
197
|
|
|
|
|
|
|
} |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub INSTALL_CV { |
200
|
421
|
|
|
421
|
0
|
1309
|
my ($in_pkg, $name, $cv, %opts) = @_; |
201
|
|
|
|
|
|
|
|
202
|
421
|
50
|
|
|
|
892
|
Carp::confess('[ARGS] You must specify a package name') |
203
|
|
|
|
|
|
|
unless defined $in_pkg; |
204
|
421
|
50
|
|
|
|
828
|
Carp::confess('[ARGS] You must specify a name') |
205
|
|
|
|
|
|
|
unless defined $name; |
206
|
421
|
50
|
33
|
|
|
1609
|
Carp::confess('[ARGS] You must specify a CODE reference') |
|
|
|
33
|
|
|
|
|
207
|
|
|
|
|
|
|
unless $cv && ref $cv eq 'CODE' |
208
|
|
|
|
|
|
|
|| CAN_COERCE_TO_CODE_REF( $cv ); |
209
|
|
|
|
|
|
|
Carp::confess("[ARGS] You must specify a boolean value for `set_subname` option") |
210
|
421
|
50
|
|
|
|
1014
|
if not exists $opts{set_subname}; |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
{ |
213
|
35
|
|
|
35
|
|
281
|
no strict 'refs'; |
|
35
|
|
|
|
|
87
|
|
|
35
|
|
|
|
|
1316
|
|
|
421
|
|
|
|
|
644
|
|
214
|
35
|
|
|
35
|
|
233
|
no warnings 'once', 'redefine'; |
|
35
|
|
|
|
|
95
|
|
|
35
|
|
|
|
|
7120
|
|
215
|
|
|
|
|
|
|
|
216
|
421
|
|
|
|
|
971
|
my $fullname = $in_pkg.'::'.$name; |
217
|
421
|
100
|
|
|
|
857
|
*{$fullname} = $opts{set_subname} ? Sub::Name::subname($fullname, $cv) : $cv; |
|
421
|
|
|
|
|
2306
|
|
218
|
|
|
|
|
|
|
} |
219
|
421
|
|
|
|
|
1289
|
return; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
sub REMOVE_CV_FROM_GLOB { |
223
|
3
|
|
|
3
|
0
|
7
|
my ($stash, $name) = @_; |
224
|
|
|
|
|
|
|
|
225
|
3
|
50
|
33
|
|
|
20
|
Carp::confess('[ARGS] You must specify a stash') |
226
|
|
|
|
|
|
|
unless $stash && ref $stash eq 'HASH'; |
227
|
3
|
50
|
|
|
|
9
|
Carp::confess('[ARGS] You must specify a name') |
228
|
|
|
|
|
|
|
unless defined $name; |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# find the glob we are looking for |
231
|
|
|
|
|
|
|
# which might not exist, in which |
232
|
|
|
|
|
|
|
# case we do nothing .... |
233
|
3
|
50
|
|
|
|
12
|
if ( my $glob = $stash->{ $name } ) { |
234
|
|
|
|
|
|
|
# once we find it, extract all the |
235
|
|
|
|
|
|
|
# slots we need, note the missing |
236
|
|
|
|
|
|
|
# CODE slot since we don't need |
237
|
|
|
|
|
|
|
# that in our new glob ... |
238
|
3
|
|
|
|
|
5
|
my %to_save; |
239
|
3
|
|
|
|
|
8
|
foreach my $slot (qw[ SCALAR ARRAY HASH FORMAT IO ]) { |
240
|
15
|
100
|
|
|
|
24
|
if ( my $val = *{ $glob }{ $slot } ) { |
|
15
|
|
|
|
|
45
|
|
241
|
3
|
|
|
|
|
9
|
$to_save{ $slot } = $val; |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
# replace the old glob with a new one ... |
245
|
3
|
|
|
|
|
16
|
$stash->{ $name } = Symbol::gensym(); |
246
|
|
|
|
|
|
|
# now go about constructing our new |
247
|
|
|
|
|
|
|
# glob by restoring the other slots |
248
|
|
|
|
|
|
|
{ |
249
|
35
|
|
|
35
|
|
278
|
no strict 'refs'; |
|
35
|
|
|
|
|
102
|
|
|
35
|
|
|
|
|
1262
|
|
|
3
|
|
|
|
|
59
|
|
250
|
35
|
|
|
35
|
|
252
|
no warnings 'once'; |
|
35
|
|
|
|
|
87
|
|
|
35
|
|
|
|
|
33144
|
|
251
|
|
|
|
|
|
|
# get the name of the stash, we could have |
252
|
|
|
|
|
|
|
# passed this in, but it is easy to get in |
253
|
|
|
|
|
|
|
# XS, and so we can punt that down the road |
254
|
|
|
|
|
|
|
# for the time being |
255
|
3
|
|
|
|
|
15
|
my $pkg = B::svref_2object( $stash )->NAME; |
256
|
3
|
|
|
|
|
13
|
foreach my $type ( keys %to_save ) { |
257
|
3
|
|
|
|
|
8
|
*{ $pkg . '::' . $name } = $to_save{ $type }; |
|
3
|
|
|
|
|
13
|
|
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
# ... the end |
262
|
3
|
|
|
|
|
11
|
return; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
266
|
|
|
|
|
|
|
## Role application and composition |
267
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
sub APPLY_ROLES { |
270
|
16
|
|
|
16
|
0
|
437
|
my ($meta, $roles) = @_; |
271
|
|
|
|
|
|
|
|
272
|
16
|
50
|
|
|
|
106
|
Carp::confess('[ARGS] You must specify a metaclass to apply roles to') |
273
|
|
|
|
|
|
|
unless Scalar::Util::blessed( $meta ); |
274
|
16
|
50
|
33
|
|
|
171
|
Carp::confess('[ARGS] You must specify a least one roles to apply as an ARRAY ref') |
|
|
|
33
|
|
|
|
|
275
|
|
|
|
|
|
|
unless $roles && ref $roles eq 'ARRAY' && scalar( @$roles ) != 0; |
276
|
|
|
|
|
|
|
|
277
|
16
|
|
|
|
|
177
|
foreach my $r ( $meta->roles ) { |
278
|
|
|
|
|
|
|
Carp::confess("[ERROR] Could not find role ($_) in the set of roles in $meta (" . $meta->name . ")") |
279
|
18
|
50
|
|
|
|
45
|
unless scalar grep { $r eq $_ } @$roles; |
|
22
|
|
|
|
|
118
|
|
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
16
|
|
|
|
|
56
|
my @meta_roles = map { MOP::Role->new( name => $_ ) } @$roles; |
|
18
|
|
|
|
|
150
|
|
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
my ( |
285
|
16
|
|
|
|
|
344
|
$slots, |
286
|
|
|
|
|
|
|
$slot_conflicts |
287
|
|
|
|
|
|
|
) = COMPOSE_ALL_ROLE_SLOTS( @meta_roles ); |
288
|
|
|
|
|
|
|
|
289
|
16
|
50
|
|
|
|
83
|
Carp::confess("[CONFLICT] There should be no conflicting slots when composing (" . (join ', ' => @$roles) . ") into (" . $meta->name . ")") |
290
|
|
|
|
|
|
|
if scalar keys %$slot_conflicts; |
291
|
|
|
|
|
|
|
|
292
|
16
|
|
|
|
|
55
|
foreach my $name ( keys %$slots ) { |
293
|
|
|
|
|
|
|
# if we have a slot already by that name ... |
294
|
0
|
0
|
|
|
|
0
|
Carp::confess("[CONFLICT] Role Conflict, cannot compose slot ($name) into (" . $meta->name . ") because ($name) already exists") |
295
|
|
|
|
|
|
|
if $meta->has_slot( $name ); |
296
|
|
|
|
|
|
|
# otherwise alias it ... |
297
|
0
|
|
|
|
|
0
|
$meta->alias_slot( $name, $slots->{ $name } ); |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
my ( |
301
|
16
|
|
|
|
|
61
|
$methods, |
302
|
|
|
|
|
|
|
$method_conflicts, |
303
|
|
|
|
|
|
|
$required_methods |
304
|
|
|
|
|
|
|
) = COMPOSE_ALL_ROLE_METHODS( @meta_roles ); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Carp::confess("[CONFLICT] There should be no conflicting methods when composing (" . (join ', ' => @$roles) . ") into (" . $meta->name . ") but instead we found (" . (join ', ' => keys %$method_conflicts) . ")") |
307
|
|
|
|
|
|
|
if (scalar keys %$method_conflicts) # do we have any conflicts ... |
308
|
|
|
|
|
|
|
# and the conflicts are not satisfied by the composing item ... |
309
|
16
|
0
|
50
|
|
|
95
|
&& (scalar grep { !$meta->has_method( $_ ) } keys %$method_conflicts); |
|
0
|
|
|
|
|
0
|
|
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
# check the required method set and |
312
|
|
|
|
|
|
|
# see if what we are composing into |
313
|
|
|
|
|
|
|
# happens to fulfill them |
314
|
16
|
|
|
|
|
57
|
foreach my $name ( keys %$required_methods ) { |
315
|
3
|
50
|
|
|
|
8
|
delete $required_methods->{ $name } |
316
|
|
|
|
|
|
|
if $meta->name->can( $name ); |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
16
|
50
|
|
|
|
70
|
Carp::confess("[CONFLICT] There should be no required methods when composing (" . (join ', ' => @$roles) . ") into (" . $meta->name . ") but instead we found (" . (join ', ' => keys %$required_methods) . ")") |
320
|
|
|
|
|
|
|
if scalar keys %$required_methods; # do we have required methods ... |
321
|
|
|
|
|
|
|
|
322
|
16
|
|
|
|
|
120
|
foreach my $name ( keys %$methods ) { |
323
|
|
|
|
|
|
|
# if we have a method already by that name ... |
324
|
419
|
50
|
|
|
|
1030
|
next if $meta->has_method( $name ); |
325
|
|
|
|
|
|
|
# otherwise, alias it ... |
326
|
419
|
|
|
|
|
1101
|
$meta->alias_method( $name, $methods->{ $name } ); |
327
|
|
|
|
|
|
|
} |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
# if we still have keys in $required, it is |
330
|
|
|
|
|
|
|
# because we are a role (class would have |
331
|
|
|
|
|
|
|
# died above), so we can just stuff in the |
332
|
|
|
|
|
|
|
# required methods ... |
333
|
16
|
|
|
|
|
105
|
$meta->add_required_method( $_ ) for keys %$required_methods; |
334
|
|
|
|
|
|
|
|
335
|
16
|
|
|
|
|
190
|
return; |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
sub COMPOSE_ALL_ROLE_SLOTS { |
339
|
16
|
|
|
16
|
0
|
48
|
my @roles = @_; |
340
|
|
|
|
|
|
|
|
341
|
16
|
50
|
|
|
|
86
|
Carp::confess('[ARGS] You must specify a least one role to compose slots in') |
342
|
|
|
|
|
|
|
if scalar( @roles ) == 0; |
343
|
|
|
|
|
|
|
|
344
|
16
|
|
|
|
|
40
|
my (%slots, %conflicts); |
345
|
|
|
|
|
|
|
|
346
|
16
|
|
|
|
|
45
|
foreach my $role ( @roles ) { |
347
|
18
|
|
|
|
|
79
|
foreach my $slot ( $role->slots ) { |
348
|
0
|
|
|
|
|
0
|
my $name = $slot->name; |
349
|
|
|
|
|
|
|
# if we have one already, but |
350
|
|
|
|
|
|
|
# it is not the same refaddr ... |
351
|
0
|
0
|
0
|
|
|
0
|
if ( exists $slots{ $name } && $slots{ $name } != $slot->initializer ) { |
352
|
|
|
|
|
|
|
# mark it as a conflict ... |
353
|
0
|
|
|
|
|
0
|
$conflicts{ $name } = undef; |
354
|
|
|
|
|
|
|
# and remove it from our slot set ... |
355
|
0
|
|
|
|
|
0
|
delete $slots{ $name }; |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
# if we don't have it already ... |
358
|
|
|
|
|
|
|
else { |
359
|
|
|
|
|
|
|
# make a note of it |
360
|
0
|
|
|
|
|
0
|
$slots{ $name } = $slot->initializer; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
} |
364
|
|
|
|
|
|
|
|
365
|
16
|
|
|
|
|
91
|
return \%slots, \%conflicts; |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# TODO: |
370
|
|
|
|
|
|
|
# We should track the name of the role |
371
|
|
|
|
|
|
|
# where the required method was composed |
372
|
|
|
|
|
|
|
# from, as well as the two classes in |
373
|
|
|
|
|
|
|
# which a method conflicted. |
374
|
|
|
|
|
|
|
# - SL |
375
|
|
|
|
|
|
|
sub COMPOSE_ALL_ROLE_METHODS { |
376
|
16
|
|
|
16
|
0
|
45
|
my @roles = @_; |
377
|
|
|
|
|
|
|
|
378
|
16
|
50
|
|
|
|
61
|
Carp::confess('[ARGS] You must specify a least one role to compose methods in') |
379
|
|
|
|
|
|
|
if scalar( @roles ) == 0; |
380
|
|
|
|
|
|
|
|
381
|
16
|
|
|
|
|
37
|
my (%methods, %conflicts, %required); |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
# flatten the set of required methods ... |
384
|
16
|
|
|
|
|
38
|
foreach my $r ( @roles ) { |
385
|
18
|
|
|
|
|
106
|
foreach my $m ( $r->required_methods ) { |
386
|
3
|
|
|
|
|
9
|
$required{ $m->name } = undef; |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
# for every role ... |
391
|
16
|
|
|
|
|
1949
|
foreach my $r ( @roles ) { |
392
|
|
|
|
|
|
|
# and every method in that role ... |
393
|
18
|
|
|
|
|
92
|
foreach my $m ( $r->methods ) { |
394
|
419
|
|
|
|
|
979
|
my $name = $m->name; |
395
|
|
|
|
|
|
|
# if we have already seen the method, |
396
|
|
|
|
|
|
|
# but it is not the same refaddr |
397
|
|
|
|
|
|
|
# it is a conflict, which means: |
398
|
419
|
50
|
33
|
|
|
1198
|
if ( exists $methods{ $name } && $methods{ $name } != $m->body ) { |
399
|
|
|
|
|
|
|
# we need to add it to our required-method map |
400
|
0
|
|
|
|
|
0
|
$required{ $name } = undef; |
401
|
|
|
|
|
|
|
# and note that it is also a conflict ... |
402
|
0
|
|
|
|
|
0
|
$conflicts{ $name } = undef; |
403
|
|
|
|
|
|
|
# and remove it from our method map |
404
|
0
|
|
|
|
|
0
|
delete $methods{ $name }; |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
# if we haven't seen the method ... |
407
|
|
|
|
|
|
|
else { |
408
|
|
|
|
|
|
|
# add it to the method map |
409
|
419
|
|
|
|
|
950
|
$methods{ $name } = $m->body; |
410
|
|
|
|
|
|
|
# and remove it from the required-method map |
411
|
|
|
|
|
|
|
delete $required{ $name } |
412
|
|
|
|
|
|
|
# if it actually exists in it, and ... |
413
|
|
|
|
|
|
|
if exists $required{ $name } |
414
|
|
|
|
|
|
|
# is not also a conflict ... |
415
|
419
|
50
|
33
|
|
|
1156
|
&& !exists $conflicts{ $name }; |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
#use Data::Dumper; |
421
|
|
|
|
|
|
|
#warn Dumper [ [ map { $_->name } @roles ], \%methods, \%conflicts, \%required ]; |
422
|
|
|
|
|
|
|
|
423
|
16
|
|
|
|
|
2019
|
return \%methods, \%conflicts, \%required; |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
1; |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
__END__ |