line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package MOP::Internal::Util; |
2
|
|
|
|
|
|
|
# ABSTRACT: For MOP Internal Use Only |
3
|
|
|
|
|
|
|
|
4
|
35
|
|
|
35
|
|
199
|
use strict; |
|
35
|
|
|
|
|
65
|
|
|
35
|
|
|
|
|
941
|
|
5
|
35
|
|
|
35
|
|
161
|
use warnings; |
|
35
|
|
|
|
|
55
|
|
|
35
|
|
|
|
|
796
|
|
6
|
|
|
|
|
|
|
|
7
|
35
|
|
|
35
|
|
170
|
use B (); # nasty stuff, all nasty stuff |
|
35
|
|
|
|
|
130
|
|
|
35
|
|
|
|
|
428
|
|
8
|
35
|
|
|
35
|
|
140
|
use Carp (); # errors and stuff |
|
35
|
|
|
|
|
51
|
|
|
35
|
|
|
|
|
401
|
|
9
|
35
|
|
|
35
|
|
8563
|
use Sub::Name (); # handling some sub stuff |
|
35
|
|
|
|
|
13873
|
|
|
35
|
|
|
|
|
886
|
|
10
|
35
|
|
|
35
|
|
8806
|
use Sub::Metadata (); # handling other sub stuff |
|
35
|
|
|
|
|
30389
|
|
|
35
|
|
|
|
|
755
|
|
11
|
35
|
|
|
35
|
|
8554
|
use Symbol (); # creating the occasional symbol |
|
35
|
|
|
|
|
21915
|
|
|
35
|
|
|
|
|
787
|
|
12
|
35
|
|
|
35
|
|
201
|
use Scalar::Util (); # I think I use blessed somewhere in here ... |
|
35
|
|
|
|
|
63
|
|
|
35
|
|
|
|
|
467
|
|
13
|
35
|
|
|
35
|
|
9114
|
use Devel::OverloadInfo (); # Sometimes I need to know about overloading |
|
35
|
|
|
|
|
329853
|
|
|
35
|
|
|
|
|
679
|
|
14
|
35
|
|
|
35
|
|
8179
|
use Devel::Hook (); # for scheduling UNITCHECK blocks ... |
|
35
|
|
|
|
|
23868
|
|
|
35
|
|
|
|
|
14585
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
our $VERSION = '0.11'; |
17
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:STEVAN'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
20
|
|
|
|
|
|
|
## Basic Glob access |
21
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
sub IS_VALID_MODULE_NAME { |
24
|
112
|
|
|
112
|
0
|
206
|
my ($name) = @_; |
25
|
112
|
|
|
|
|
762
|
$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
|
10
|
my ($stash) = @_; |
30
|
4
|
50
|
|
|
|
11
|
Carp::croak('[ARGS] You must specify a stash') |
31
|
|
|
|
|
|
|
unless defined $stash; |
32
|
4
|
100
|
|
|
|
44
|
if ( my $name = B::svref_2object( $stash )->NAME ) { |
33
|
2
|
|
|
|
|
7
|
return IS_VALID_MODULE_NAME( $name ); |
34
|
|
|
|
|
|
|
} |
35
|
2
|
|
|
|
|
7
|
return; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
sub GET_NAME { |
39
|
1117
|
|
|
1117
|
0
|
1588
|
my ($stash) = @_; |
40
|
1117
|
50
|
|
|
|
1977
|
Carp::croak('[ARGS] You must specify a stash') |
41
|
|
|
|
|
|
|
unless defined $stash; |
42
|
1117
|
|
|
|
|
4279
|
B::svref_2object( $stash )->NAME |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub GET_STASH_NAME { |
46
|
81
|
|
|
81
|
0
|
130
|
my ($stash) = @_; |
47
|
81
|
50
|
|
|
|
153
|
Carp::croak('[ARGS] You must specify a stash') |
48
|
|
|
|
|
|
|
unless defined $stash; |
49
|
81
|
|
|
|
|
1090
|
B::svref_2object( $stash )->STASH->NAME |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub GET_GLOB_NAME { |
53
|
544
|
|
|
544
|
0
|
749
|
my ($stash) = @_; |
54
|
544
|
50
|
|
|
|
900
|
Carp::croak('[ARGS] You must specify a stash') |
55
|
|
|
|
|
|
|
unless defined $stash; |
56
|
544
|
|
|
|
|
2217
|
B::svref_2object( $stash )->GV->NAME |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub GET_GLOB_STASH_NAME { |
60
|
605
|
|
|
605
|
0
|
809
|
my ($stash) = @_; |
61
|
605
|
50
|
|
|
|
1153
|
Carp::croak('[ARGS] You must specify a stash') |
62
|
|
|
|
|
|
|
unless defined $stash; |
63
|
605
|
|
|
|
|
3478
|
B::svref_2object( $stash )->GV->STASH->NAME |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
sub GET_GLOB_SLOT { |
67
|
1587
|
|
|
1587
|
0
|
2669
|
my ($stash, $name, $slot) = @_; |
68
|
|
|
|
|
|
|
|
69
|
1587
|
50
|
|
|
|
2747
|
Carp::croak('[ARGS] You must specify a stash') |
70
|
|
|
|
|
|
|
unless defined $stash; |
71
|
1587
|
50
|
|
|
|
2277
|
Carp::croak('[ARGS] You must specify a name') |
72
|
|
|
|
|
|
|
unless defined $name; |
73
|
1587
|
50
|
|
|
|
2265
|
Carp::croak('[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
|
1587
|
100
|
|
|
|
2800
|
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
|
1437
|
50
|
100
|
|
|
7189
|
if (( $slot eq 'CODE' && $stash->{ $name } eq "-1" ) || ref $stash->{ $name } ne 'GLOB') { |
|
|
|
66
|
|
|
|
|
85
|
1437
|
|
|
|
|
6311
|
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
|
1437
|
|
|
|
|
2764
|
return *{ $stash->{ $name } }{ $slot }; |
|
1437
|
|
|
|
|
5847
|
|
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
sub SET_GLOB_SLOT { |
96
|
4
|
|
|
4
|
0
|
11
|
my ($stash, $name, $value_ref) = @_; |
97
|
|
|
|
|
|
|
|
98
|
4
|
50
|
|
|
|
14
|
Carp::croak('[ARGS] You must specify a stash') |
99
|
|
|
|
|
|
|
unless defined $stash; |
100
|
4
|
50
|
|
|
|
16
|
Carp::croak('[ARGS] You must specify a name') |
101
|
|
|
|
|
|
|
unless defined $name; |
102
|
4
|
50
|
|
|
|
10
|
Carp::croak('[ARGS] You must specify a value REF') |
103
|
|
|
|
|
|
|
unless defined $value_ref; |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
{ |
106
|
35
|
|
|
35
|
|
249
|
no strict 'refs'; |
|
35
|
|
|
|
|
71
|
|
|
35
|
|
|
|
|
1027
|
|
|
4
|
|
|
|
|
6
|
|
107
|
35
|
|
|
35
|
|
170
|
no warnings 'once'; |
|
35
|
|
|
|
|
61
|
|
|
35
|
|
|
|
|
16376
|
|
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
|
|
|
|
|
24
|
my $pkg = B::svref_2object( $stash )->NAME; |
113
|
4
|
|
|
|
|
10
|
*{ $pkg . '::' . $name } = $value_ref; |
|
4
|
|
|
|
|
30
|
|
114
|
|
|
|
|
|
|
} |
115
|
4
|
|
|
|
|
11
|
return; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
119
|
|
|
|
|
|
|
## UNITCHECK hook |
120
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub ADD_UNITCHECK_HOOK { |
123
|
5
|
|
|
5
|
0
|
8
|
my ($cv) = @_; |
124
|
5
|
50
|
|
|
|
15
|
Carp::croak('[ARGS] You must specify a CODE reference') |
125
|
|
|
|
|
|
|
unless $cv; |
126
|
5
|
50
|
33
|
|
|
30
|
Carp::croak('[ARGS] You must specify a CODE reference') |
127
|
|
|
|
|
|
|
unless $cv && ref $cv eq 'CODE'; |
128
|
5
|
|
|
|
|
23
|
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
|
154
|
my ($object) = @_; |
137
|
109
|
100
|
66
|
|
|
813
|
return 0 unless $object && Scalar::Util::blessed( $object ); |
138
|
|
|
|
|
|
|
# might be just a blessed CODE ref ... |
139
|
26
|
50
|
|
|
|
120
|
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
|
1235
|
my ($cv) = @_; |
147
|
926
|
50
|
|
|
|
1506
|
Carp::croak('[ARGS] You must specify a CODE reference') |
148
|
|
|
|
|
|
|
unless $cv; |
149
|
926
|
50
|
33
|
|
|
2642
|
Carp::croak('[ARGS] You must specify a CODE reference') |
|
|
|
33
|
|
|
|
|
150
|
|
|
|
|
|
|
unless $cv && ref $cv eq 'CODE' |
151
|
|
|
|
|
|
|
|| CAN_COERCE_TO_CODE_REF( $cv ); |
152
|
926
|
|
|
|
|
2626
|
return Sub::Metadata::sub_body_type( $cv ) eq 'UNDEF'; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub DOES_GLOB_HAVE_NULL_CV { |
156
|
160
|
|
|
160
|
0
|
518
|
my ($glob) = @_; |
157
|
160
|
50
|
|
|
|
352
|
Carp::croak('[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
|
|
|
|
530
|
return 1 if $glob eq '-1'; |
167
|
|
|
|
|
|
|
# next lets see if we have a CODE slot ... |
168
|
159
|
100
|
|
|
|
261
|
if ( my $code = *{ $glob }{CODE} ) { |
|
159
|
|
|
|
|
598
|
|
169
|
136
|
|
|
|
|
949
|
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
|
|
|
|
|
71
|
return 0; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub CREATE_NULL_CV { |
176
|
3
|
|
|
3
|
0
|
6
|
my ($in_pkg, $name) = @_; |
177
|
3
|
50
|
|
|
|
7
|
Carp::croak('[ARGS] You must specify a package name') |
178
|
|
|
|
|
|
|
unless defined $in_pkg; |
179
|
3
|
50
|
|
|
|
6
|
Carp::croak('[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
|
|
|
|
156
|
eval "sub ${in_pkg}::${name}; 1;" or do { Carp::croak($@) }; |
|
1
|
|
|
|
|
115
|
|
184
|
2
|
|
|
|
|
5
|
return; |
185
|
|
|
|
|
|
|
} |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
sub SET_COMP_STASH_FOR_CV { |
188
|
3
|
|
|
3
|
0
|
9
|
my ($cv, $in_pkg) = @_; |
189
|
3
|
50
|
|
|
|
11
|
Carp::croak('[ARGS] You must specify a CODE reference') |
190
|
|
|
|
|
|
|
unless $cv; |
191
|
3
|
50
|
|
|
|
8
|
Carp::croak('[ARGS] You must specify a package name') |
192
|
|
|
|
|
|
|
unless defined $in_pkg; |
193
|
3
|
50
|
66
|
|
|
21
|
Carp::croak('[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
|
821
|
my ($in_pkg, $name, $cv, %opts) = @_; |
201
|
|
|
|
|
|
|
|
202
|
421
|
50
|
|
|
|
634
|
Carp::croak('[ARGS] You must specify a package name') |
203
|
|
|
|
|
|
|
unless defined $in_pkg; |
204
|
421
|
50
|
|
|
|
586
|
Carp::croak('[ARGS] You must specify a name') |
205
|
|
|
|
|
|
|
unless defined $name; |
206
|
421
|
50
|
33
|
|
|
1184
|
Carp::croak('[ARGS] You must specify a CODE reference') |
|
|
|
33
|
|
|
|
|
207
|
|
|
|
|
|
|
unless $cv && ref $cv eq 'CODE' |
208
|
|
|
|
|
|
|
|| CAN_COERCE_TO_CODE_REF( $cv ); |
209
|
|
|
|
|
|
|
Carp::croak("[ARGS] You must specify a boolean value for `set_subname` option") |
210
|
421
|
50
|
|
|
|
647
|
if not exists $opts{set_subname}; |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
{ |
213
|
35
|
|
|
35
|
|
224
|
no strict 'refs'; |
|
35
|
|
|
|
|
62
|
|
|
35
|
|
|
|
|
1030
|
|
|
421
|
|
|
|
|
456
|
|
214
|
35
|
|
|
35
|
|
170
|
no warnings 'once', 'redefine'; |
|
35
|
|
|
|
|
82
|
|
|
35
|
|
|
|
|
5469
|
|
215
|
|
|
|
|
|
|
|
216
|
421
|
|
|
|
|
719
|
my $fullname = $in_pkg.'::'.$name; |
217
|
421
|
100
|
|
|
|
640
|
*{$fullname} = $opts{set_subname} ? Sub::Name::subname($fullname, $cv) : $cv; |
|
421
|
|
|
|
|
1619
|
|
218
|
|
|
|
|
|
|
} |
219
|
421
|
|
|
|
|
900
|
return; |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
sub REMOVE_CV_FROM_GLOB { |
223
|
3
|
|
|
3
|
0
|
8
|
my ($stash, $name) = @_; |
224
|
|
|
|
|
|
|
|
225
|
3
|
50
|
33
|
|
|
16
|
Carp::croak('[ARGS] You must specify a stash') |
226
|
|
|
|
|
|
|
unless $stash && ref $stash eq 'HASH'; |
227
|
3
|
50
|
|
|
|
8
|
Carp::croak('[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
|
|
|
|
|
7
|
foreach my $slot (qw[ SCALAR ARRAY HASH FORMAT IO ]) { |
240
|
15
|
100
|
|
|
|
23
|
if ( my $val = *{ $glob }{ $slot } ) { |
|
15
|
|
|
|
|
43
|
|
241
|
3
|
|
|
|
|
12
|
$to_save{ $slot } = $val; |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
# replace the old glob with a new one ... |
245
|
3
|
|
|
|
|
13
|
$stash->{ $name } = Symbol::gensym(); |
246
|
|
|
|
|
|
|
# now go about constructing our new |
247
|
|
|
|
|
|
|
# glob by restoring the other slots |
248
|
|
|
|
|
|
|
{ |
249
|
35
|
|
|
35
|
|
215
|
no strict 'refs'; |
|
35
|
|
|
|
|
70
|
|
|
35
|
|
|
|
|
931
|
|
|
3
|
|
|
|
|
50
|
|
250
|
35
|
|
|
35
|
|
162
|
no warnings 'once'; |
|
35
|
|
|
|
|
59
|
|
|
35
|
|
|
|
|
24671
|
|
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
|
|
|
|
|
9
|
foreach my $type ( keys %to_save ) { |
257
|
3
|
|
|
|
|
7
|
*{ $pkg . '::' . $name } = $to_save{ $type }; |
|
3
|
|
|
|
|
14
|
|
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
# ... the end |
262
|
3
|
|
|
|
|
9
|
return; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
266
|
|
|
|
|
|
|
## Role application and composition |
267
|
|
|
|
|
|
|
## ------------------------------------------------------------------ |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
sub APPLY_ROLES { |
270
|
16
|
|
|
16
|
0
|
318
|
my ($meta, $roles) = @_; |
271
|
|
|
|
|
|
|
|
272
|
16
|
50
|
|
|
|
83
|
Carp::croak('[ARGS] You must specify a metaclass to apply roles to') |
273
|
|
|
|
|
|
|
unless Scalar::Util::blessed( $meta ); |
274
|
16
|
50
|
33
|
|
|
135
|
Carp::croak('[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
|
|
|
|
|
122
|
foreach my $r ( $meta->roles ) { |
278
|
|
|
|
|
|
|
Carp::croak("[ERROR] Could not find role ($_) in the set of roles in $meta (" . $meta->name . ")") |
279
|
18
|
50
|
|
|
|
32
|
unless scalar grep { $r eq $_ } @$roles; |
|
22
|
|
|
|
|
91
|
|
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
16
|
|
|
|
|
38
|
my @meta_roles = map { MOP::Role->new( name => $_ ) } @$roles; |
|
18
|
|
|
|
|
105
|
|
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
my ( |
285
|
16
|
|
|
|
|
257
|
$slots, |
286
|
|
|
|
|
|
|
$slot_conflicts |
287
|
|
|
|
|
|
|
) = COMPOSE_ALL_ROLE_SLOTS( @meta_roles ); |
288
|
|
|
|
|
|
|
|
289
|
16
|
50
|
|
|
|
60
|
Carp::croak("[CONFLICT] There should be no conflicting slots when composing (" . (join ', ' => @$roles) . ") into (" . $meta->name . ")") |
290
|
|
|
|
|
|
|
if scalar keys %$slot_conflicts; |
291
|
|
|
|
|
|
|
|
292
|
16
|
|
|
|
|
46
|
foreach my $name ( keys %$slots ) { |
293
|
|
|
|
|
|
|
# if we have a slot already by that name ... |
294
|
0
|
0
|
|
|
|
0
|
Carp::croak("[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
|
|
|
|
|
40
|
$methods, |
302
|
|
|
|
|
|
|
$method_conflicts, |
303
|
|
|
|
|
|
|
$required_methods |
304
|
|
|
|
|
|
|
) = COMPOSE_ALL_ROLE_METHODS( @meta_roles ); |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Carp::croak("[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
|
|
|
69
|
&& (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
|
|
|
|
|
44
|
foreach my $name ( keys %$required_methods ) { |
315
|
3
|
50
|
|
|
|
9
|
delete $required_methods->{ $name } |
316
|
|
|
|
|
|
|
if $meta->name->can( $name ); |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
16
|
50
|
|
|
|
54
|
Carp::croak("[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
|
|
|
|
|
80
|
foreach my $name ( keys %$methods ) { |
323
|
|
|
|
|
|
|
# if we have a method already by that name ... |
324
|
419
|
50
|
|
|
|
745
|
next if $meta->has_method( $name ); |
325
|
|
|
|
|
|
|
# otherwise, alias it ... |
326
|
419
|
|
|
|
|
767
|
$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
|
|
|
|
|
63
|
$meta->add_required_method( $_ ) for keys %$required_methods; |
334
|
|
|
|
|
|
|
|
335
|
16
|
|
|
|
|
134
|
return; |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
sub COMPOSE_ALL_ROLE_SLOTS { |
339
|
16
|
|
|
16
|
0
|
39
|
my @roles = @_; |
340
|
|
|
|
|
|
|
|
341
|
16
|
50
|
|
|
|
58
|
Carp::croak('[ARGS] You must specify a least one role to compose slots in') |
342
|
|
|
|
|
|
|
if scalar( @roles ) == 0; |
343
|
|
|
|
|
|
|
|
344
|
16
|
|
|
|
|
27
|
my (%slots, %conflicts); |
345
|
|
|
|
|
|
|
|
346
|
16
|
|
|
|
|
34
|
foreach my $role ( @roles ) { |
347
|
18
|
|
|
|
|
57
|
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
|
|
|
|
|
50
|
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
|
34
|
my @roles = @_; |
377
|
|
|
|
|
|
|
|
378
|
16
|
50
|
|
|
|
48
|
Carp::croak('[ARGS] You must specify a least one role to compose methods in') |
379
|
|
|
|
|
|
|
if scalar( @roles ) == 0; |
380
|
|
|
|
|
|
|
|
381
|
16
|
|
|
|
|
23
|
my (%methods, %conflicts, %required); |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
# flatten the set of required methods ... |
384
|
16
|
|
|
|
|
31
|
foreach my $r ( @roles ) { |
385
|
18
|
|
|
|
|
87
|
foreach my $m ( $r->required_methods ) { |
386
|
3
|
|
|
|
|
9
|
$required{ $m->name } = undef; |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
# for every role ... |
391
|
16
|
|
|
|
|
1453
|
foreach my $r ( @roles ) { |
392
|
|
|
|
|
|
|
# and every method in that role ... |
393
|
18
|
|
|
|
|
75
|
foreach my $m ( $r->methods ) { |
394
|
419
|
|
|
|
|
664
|
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
|
|
|
863
|
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
|
|
|
|
|
685
|
$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
|
|
|
915
|
&& !exists $conflicts{ $name }; |
416
|
|
|
|
|
|
|
} |
417
|
|
|
|
|
|
|
} |
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
#use Data::Dumper; |
421
|
|
|
|
|
|
|
#warn Dumper [ [ map { $_->name } @roles ], \%methods, \%conflicts, \%required ]; |
422
|
|
|
|
|
|
|
|
423
|
16
|
|
|
|
|
1458
|
return \%methods, \%conflicts, \%required; |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
1; |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
__END__ |