line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# This file was generated by Scalar::Random::PP::OO::Maker 0.07 from Mouse 0.70. |
2
|
|
|
|
|
|
|
# |
3
|
|
|
|
|
|
|
# ANY CHANGES MADE HERE WILL BE LOST! |
4
|
2
|
|
|
2
|
|
10
|
use strict; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
70
|
|
5
|
2
|
|
|
2
|
|
10
|
use warnings; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
436
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
# tell Perl we already have all of the Scalar::Random::PP::OO files loaded: |
8
|
|
|
|
|
|
|
BEGIN { |
9
|
2
|
|
|
2
|
|
11
|
$INC{'Scalar/Random/PP/OO.pm'} = __FILE__; |
10
|
2
|
|
|
|
|
4
|
$INC{'Scalar/Random/PP/OO/Exporter.pm'} = __FILE__; |
11
|
2
|
|
|
|
|
4
|
$INC{'Scalar/Random/PP/OO/Object.pm'} = __FILE__; |
12
|
2
|
|
|
|
|
4
|
$INC{'Scalar/Random/PP/OO/PurePerl.pm'} = __FILE__; |
13
|
2
|
|
|
|
|
4
|
$INC{'Scalar/Random/PP/OO/Role.pm'} = __FILE__; |
14
|
2
|
|
|
|
|
5
|
$INC{'Scalar/Random/PP/OO/Util.pm'} = __FILE__; |
15
|
2
|
|
|
|
|
3
|
$INC{'Scalar/Random/PP/OO/Meta/Attribute.pm'} = __FILE__; |
16
|
2
|
|
|
|
|
8
|
$INC{'Scalar/Random/PP/OO/Meta/Class.pm'} = __FILE__; |
17
|
2
|
|
|
|
|
4
|
$INC{'Scalar/Random/PP/OO/Meta/Method.pm'} = __FILE__; |
18
|
2
|
|
|
|
|
2
|
$INC{'Scalar/Random/PP/OO/Meta/Module.pm'} = __FILE__; |
19
|
2
|
|
|
|
|
4
|
$INC{'Scalar/Random/PP/OO/Meta/Role.pm'} = __FILE__; |
20
|
2
|
|
|
|
|
4
|
$INC{'Scalar/Random/PP/OO/Meta/TypeConstraint.pm'} = __FILE__; |
21
|
2
|
|
|
|
|
5
|
$INC{'Scalar/Random/PP/OO/Meta/Method/Accessor.pm'} = __FILE__; |
22
|
2
|
|
|
|
|
4
|
$INC{'Scalar/Random/PP/OO/Meta/Method/Constructor.pm'} = __FILE__; |
23
|
2
|
|
|
|
|
5
|
$INC{'Scalar/Random/PP/OO/Meta/Method/Delegation.pm'} = __FILE__; |
24
|
2
|
|
|
|
|
4
|
$INC{'Scalar/Random/PP/OO/Meta/Method/Destructor.pm'} = __FILE__; |
25
|
2
|
|
|
|
|
3
|
$INC{'Scalar/Random/PP/OO/Meta/Role/Composite.pm'} = __FILE__; |
26
|
2
|
|
|
|
|
4
|
$INC{'Scalar/Random/PP/OO/Meta/Role/Method.pm'} = __FILE__; |
27
|
2
|
|
|
|
|
3
|
$INC{'Scalar/Random/PP/OO/Util/MetaRole.pm'} = __FILE__; |
28
|
2
|
|
|
|
|
160
|
$INC{'Scalar/Random/PP/OO/Util/TypeConstraints.pm'} = __FILE__; |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# and now their contents |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# Contents of Mouse::PurePerl |
34
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::PurePerl; |
35
|
|
|
|
|
|
|
# The pure Perl backend for Mousse |
36
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Util; |
37
|
2
|
|
|
2
|
|
20
|
use strict; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
72
|
|
38
|
2
|
|
|
2
|
|
10
|
use warnings; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
155
|
|
39
|
2
|
|
|
2
|
|
9
|
use warnings FATAL => 'redefine'; # to avoid to load Scalar::Random::PP::OO::PurePerl twice |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
88
|
|
40
|
|
|
|
|
|
|
|
41
|
2
|
|
|
2
|
|
9
|
use B (); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
1658
|
|
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
require Scalar::Random::PP::OO::Util; |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# taken from Class/MOP.pm |
47
|
|
|
|
|
|
|
sub is_valid_class_name { |
48
|
2
|
|
|
2
|
0
|
2
|
my $class = shift; |
49
|
|
|
|
|
|
|
|
50
|
2
|
50
|
|
|
|
7
|
return 0 if ref($class); |
51
|
2
|
50
|
|
|
|
5
|
return 0 unless defined($class); |
52
|
|
|
|
|
|
|
|
53
|
2
|
50
|
|
|
|
40
|
return 1 if $class =~ /\A \w+ (?: :: \w+ )* \z/xms; |
54
|
|
|
|
|
|
|
|
55
|
0
|
|
|
|
|
0
|
return 0; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub is_class_loaded { |
59
|
2
|
|
|
2
|
0
|
4
|
my $class = shift; |
60
|
|
|
|
|
|
|
|
61
|
2
|
50
|
33
|
|
|
20
|
return 0 if ref($class) || !defined($class) || !length($class); |
|
|
|
33
|
|
|
|
|
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# walk the symbol table tree to avoid autovififying |
64
|
|
|
|
|
|
|
# \*{${main::}{"Foo::"}{"Bar::"}} == \*main::Foo::Bar:: |
65
|
|
|
|
|
|
|
|
66
|
2
|
|
|
|
|
4
|
my $pack = \%::; |
67
|
2
|
|
|
|
|
13
|
foreach my $part (split('::', $class)) { |
68
|
10
|
|
|
|
|
11
|
$part .= '::'; |
69
|
10
|
50
|
|
|
|
24
|
return 0 if !exists $pack->{$part}; |
70
|
|
|
|
|
|
|
|
71
|
10
|
|
|
|
|
13
|
my $entry = \$pack->{$part}; |
72
|
10
|
50
|
|
|
|
29
|
return 0 if ref($entry) ne 'GLOB'; |
73
|
10
|
|
|
|
|
10
|
$pack = *{$entry}{HASH}; |
|
10
|
|
|
|
|
23
|
|
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
2
|
50
|
|
|
|
6
|
return 0 if !%{$pack}; |
|
2
|
|
|
|
|
16
|
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
# check for $VERSION or @ISA |
79
|
0
|
|
|
|
|
0
|
return 1 if exists $pack->{VERSION} |
80
|
2
|
0
|
33
|
|
|
12
|
&& defined *{$pack->{VERSION}}{SCALAR} && defined ${ $pack->{VERSION} }; |
|
0
|
|
33
|
|
|
0
|
|
81
|
0
|
|
|
|
|
0
|
return 1 if exists $pack->{ISA} |
82
|
2
|
0
|
33
|
|
|
14
|
&& defined *{$pack->{ISA}}{ARRAY} && @{ $pack->{ISA} } != 0; |
|
0
|
|
33
|
|
|
0
|
|
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# check for any method |
85
|
2
|
|
|
|
|
4
|
foreach my $name( keys %{$pack} ) { |
|
2
|
|
|
|
|
9
|
|
86
|
2
|
|
|
|
|
4
|
my $entry = \$pack->{$name}; |
87
|
2
|
50
|
33
|
|
|
10
|
return 1 if ref($entry) ne 'GLOB' || defined *{$entry}{CODE}; |
|
2
|
|
|
|
|
18
|
|
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# fail |
91
|
0
|
|
|
|
|
0
|
return 0; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
# taken from Sub::Identify |
96
|
|
|
|
|
|
|
sub get_code_info { |
97
|
14
|
|
|
14
|
0
|
22
|
my ($coderef) = @_; |
98
|
14
|
50
|
|
|
|
35
|
ref($coderef) or return; |
99
|
|
|
|
|
|
|
|
100
|
14
|
|
|
|
|
75
|
my $cv = B::svref_2object($coderef); |
101
|
14
|
50
|
|
|
|
82
|
$cv->isa('B::CV') or return; |
102
|
|
|
|
|
|
|
|
103
|
14
|
|
|
|
|
42
|
my $gv = $cv->GV; |
104
|
14
|
50
|
|
|
|
59
|
$gv->isa('B::GV') or return; |
105
|
|
|
|
|
|
|
|
106
|
14
|
|
|
|
|
111
|
return ($gv->STASH->NAME, $gv->NAME); |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub get_code_package{ |
110
|
0
|
|
|
0
|
0
|
0
|
my($coderef) = @_; |
111
|
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
0
|
my $cv = B::svref_2object($coderef); |
113
|
0
|
0
|
|
|
|
0
|
$cv->isa('B::CV') or return ''; |
114
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
0
|
my $gv = $cv->GV; |
116
|
0
|
0
|
|
|
|
0
|
$gv->isa('B::GV') or return ''; |
117
|
|
|
|
|
|
|
|
118
|
0
|
|
|
|
|
0
|
return $gv->STASH->NAME; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub get_code_ref{ |
122
|
0
|
|
|
0
|
0
|
0
|
my($package, $name) = @_; |
123
|
2
|
|
|
2
|
|
19
|
no strict 'refs'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
69
|
|
124
|
2
|
|
|
2
|
|
10
|
no warnings 'once'; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
79
|
|
125
|
2
|
|
|
2
|
|
8
|
use warnings FATAL => 'uninitialized'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
756
|
|
126
|
0
|
|
|
|
|
0
|
return *{$package . '::' . $name}{CODE}; |
|
0
|
|
|
|
|
0
|
|
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub generate_isa_predicate_for { |
130
|
2
|
|
|
2
|
0
|
4
|
my($for_class, $name) = @_; |
131
|
|
|
|
|
|
|
|
132
|
2
|
0
|
|
0
|
|
12
|
my $predicate = sub{ Scalar::Util::blessed($_[0]) && $_[0]->isa($for_class) }; |
|
0
|
|
|
|
|
0
|
|
133
|
|
|
|
|
|
|
|
134
|
2
|
50
|
|
|
|
8
|
if(defined $name){ |
135
|
0
|
|
|
|
|
0
|
Scalar::Random::PP::OO::Util::install_subroutines(scalar caller, $name => $predicate); |
136
|
0
|
|
|
|
|
0
|
return; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
2
|
|
|
|
|
10
|
return $predicate; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
sub generate_can_predicate_for { |
143
|
6
|
|
|
6
|
0
|
14
|
my($methods_ref, $name) = @_; |
144
|
|
|
|
|
|
|
|
145
|
6
|
|
|
|
|
5
|
my @methods = @{$methods_ref}; |
|
6
|
|
|
|
|
13
|
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
my $predicate = sub{ |
148
|
4
|
|
|
4
|
|
7
|
my($instance) = @_; |
149
|
4
|
50
|
|
|
|
16
|
if(Scalar::Util::blessed($instance)){ |
150
|
0
|
|
|
|
|
0
|
foreach my $method(@methods){ |
151
|
0
|
0
|
|
|
|
0
|
if(!$instance->can($method)){ |
152
|
0
|
|
|
|
|
0
|
return 0; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
} |
155
|
0
|
|
|
|
|
0
|
return 1; |
156
|
|
|
|
|
|
|
} |
157
|
4
|
|
|
|
|
30
|
return 0; |
158
|
6
|
|
|
|
|
24
|
}; |
159
|
|
|
|
|
|
|
|
160
|
6
|
50
|
|
|
|
15
|
if(defined $name){ |
161
|
6
|
|
|
|
|
15
|
Scalar::Random::PP::OO::Util::install_subroutines(scalar caller, $name => $predicate); |
162
|
6
|
|
|
|
|
11
|
return; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
0
|
|
|
|
|
0
|
return $predicate; |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Util::TypeConstraints; |
169
|
|
|
|
|
|
|
|
170
|
2
|
|
|
2
|
|
12
|
use Scalar::Util qw(blessed looks_like_number openhandle); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
2402
|
|
171
|
|
|
|
|
|
|
|
172
|
0
|
|
|
0
|
0
|
0
|
sub Any { 1 } |
173
|
0
|
|
|
0
|
0
|
0
|
sub Item { 1 } |
174
|
|
|
|
|
|
|
|
175
|
0
|
0
|
|
0
|
0
|
0
|
sub Bool { $_[0] ? $_[0] eq '1' : 1 } |
176
|
0
|
|
|
0
|
0
|
0
|
sub Undef { !defined($_[0]) } |
177
|
0
|
|
|
0
|
0
|
0
|
sub Defined { defined($_[0]) } |
178
|
0
|
0
|
|
0
|
0
|
0
|
sub Value { defined($_[0]) && !ref($_[0]) } |
179
|
0
|
|
|
0
|
0
|
0
|
sub Num { looks_like_number($_[0]) } |
180
|
|
|
|
|
|
|
sub Int { |
181
|
0
|
|
|
0
|
0
|
0
|
my($value) = @_; |
182
|
0
|
0
|
|
|
|
0
|
looks_like_number($value) && $value =~ /\A [+-]? [0-9]+ \z/xms; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
sub Str { |
185
|
0
|
|
|
0
|
0
|
0
|
my($value) = @_; |
186
|
0
|
|
0
|
|
|
0
|
return defined($value) && ref(\$value) eq 'SCALAR'; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
0
|
|
|
0
|
0
|
0
|
sub Ref { ref($_[0]) } |
190
|
|
|
|
|
|
|
sub ScalarRef { |
191
|
0
|
|
|
0
|
0
|
0
|
my($value) = @_; |
192
|
0
|
|
|
|
|
0
|
return ref($value) eq 'SCALAR' |
193
|
|
|
|
|
|
|
} |
194
|
0
|
|
|
0
|
0
|
0
|
sub ArrayRef { ref($_[0]) eq 'ARRAY' } |
195
|
0
|
|
|
0
|
0
|
0
|
sub HashRef { ref($_[0]) eq 'HASH' } |
196
|
0
|
|
|
0
|
0
|
0
|
sub CodeRef { ref($_[0]) eq 'CODE' } |
197
|
0
|
|
|
0
|
0
|
0
|
sub RegexpRef { ref($_[0]) eq 'Regexp' } |
198
|
0
|
|
|
0
|
0
|
0
|
sub GlobRef { ref($_[0]) eq 'GLOB' } |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
sub FileHandle { |
201
|
0
|
|
0
|
0
|
0
|
0
|
return openhandle($_[0]) || (blessed($_[0]) && $_[0]->isa("IO::Handle")) |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
0
|
0
|
|
0
|
0
|
0
|
sub Object { blessed($_[0]) && blessed($_[0]) ne 'Regexp' } |
205
|
|
|
|
|
|
|
|
206
|
0
|
|
|
0
|
0
|
0
|
sub ClassName { Scalar::Random::PP::OO::Util::is_class_loaded($_[0]) } |
207
|
0
|
|
0
|
0
|
0
|
0
|
sub RoleName { (Scalar::Random::PP::OO::Util::class_of($_[0]) || return 0)->isa('Scalar::Random::PP::OO::Meta::Role') } |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
sub _parameterize_ArrayRef_for { |
210
|
0
|
|
|
0
|
|
0
|
my($type_parameter) = @_; |
211
|
0
|
|
|
|
|
0
|
my $check = $type_parameter->_compiled_type_constraint; |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
return sub { |
214
|
0
|
|
|
0
|
|
0
|
foreach my $value (@{$_}) { |
|
0
|
|
|
|
|
0
|
|
215
|
0
|
0
|
|
|
|
0
|
return undef unless $check->($value); |
216
|
|
|
|
|
|
|
} |
217
|
0
|
|
|
|
|
0
|
return 1; |
218
|
|
|
|
|
|
|
} |
219
|
0
|
|
|
|
|
0
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub _parameterize_HashRef_for { |
222
|
0
|
|
|
0
|
|
0
|
my($type_parameter) = @_; |
223
|
0
|
|
|
|
|
0
|
my $check = $type_parameter->_compiled_type_constraint; |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
return sub { |
226
|
0
|
|
|
0
|
|
0
|
foreach my $value(values %{$_}){ |
|
0
|
|
|
|
|
0
|
|
227
|
0
|
0
|
|
|
|
0
|
return undef unless $check->($value); |
228
|
|
|
|
|
|
|
} |
229
|
0
|
|
|
|
|
0
|
return 1; |
230
|
0
|
|
|
|
|
0
|
}; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# 'Maybe' type accepts 'Any', so it requires parameters |
234
|
|
|
|
|
|
|
sub _parameterize_Maybe_for { |
235
|
0
|
|
|
0
|
|
0
|
my($type_parameter) = @_; |
236
|
0
|
|
|
|
|
0
|
my $check = $type_parameter->_compiled_type_constraint; |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
return sub{ |
239
|
0
|
|
0
|
0
|
|
0
|
return !defined($_) || $check->($_); |
240
|
0
|
|
|
|
|
0
|
}; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Module; |
244
|
|
|
|
|
|
|
|
245
|
10
|
|
|
10
|
0
|
56
|
sub name { $_[0]->{package} } |
246
|
|
|
|
|
|
|
|
247
|
0
|
|
|
0
|
|
0
|
sub _method_map { $_[0]->{methods} } |
248
|
0
|
|
|
0
|
|
0
|
sub _attribute_map{ $_[0]->{attributes} } |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
sub namespace{ |
251
|
0
|
|
|
0
|
0
|
0
|
my $name = $_[0]->{package}; |
252
|
2
|
|
|
2
|
|
14
|
no strict 'refs'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
347
|
|
253
|
0
|
|
|
|
|
0
|
return \%{ $name . '::' }; |
|
0
|
|
|
|
|
0
|
|
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
sub add_method { |
257
|
4
|
|
|
4
|
0
|
10
|
my($self, $name, $code) = @_; |
258
|
|
|
|
|
|
|
|
259
|
4
|
50
|
|
|
|
10
|
if(!defined $name){ |
260
|
0
|
|
|
|
|
0
|
$self->throw_error('You must pass a defined name'); |
261
|
|
|
|
|
|
|
} |
262
|
4
|
50
|
|
|
|
10
|
if(!defined $code){ |
263
|
0
|
|
|
|
|
0
|
$self->throw_error('You must pass a defined code'); |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
4
|
50
|
|
|
|
13
|
if(ref($code) ne 'CODE'){ |
267
|
0
|
|
|
|
|
0
|
$code = \&{$code}; # coerce |
|
0
|
|
|
|
|
0
|
|
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
|
270
|
4
|
|
|
|
|
12
|
$self->{methods}->{$name} = $code; # Moose stores meta object here. |
271
|
|
|
|
|
|
|
|
272
|
4
|
|
|
|
|
20
|
Scalar::Random::PP::OO::Util::install_subroutines($self->name, |
273
|
|
|
|
|
|
|
$name => $code, |
274
|
|
|
|
|
|
|
); |
275
|
4
|
|
|
|
|
8
|
return; |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Class; |
279
|
|
|
|
|
|
|
|
280
|
2
|
|
|
2
|
|
10
|
use Scalar::Random::PP::OO::Meta::Method::Constructor; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
44
|
|
281
|
2
|
|
|
2
|
|
9
|
use Scalar::Random::PP::OO::Meta::Method::Destructor; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
6958
|
|
282
|
|
|
|
|
|
|
|
283
|
0
|
0
|
|
0
|
0
|
0
|
sub method_metaclass { $_[0]->{method_metaclass} || 'Scalar::Random::PP::OO::Meta::Method' } |
284
|
2
|
50
|
|
2
|
0
|
25
|
sub attribute_metaclass { $_[0]->{attribute_metaclass} || 'Scalar::Random::PP::OO::Meta::Attribute' } |
285
|
|
|
|
|
|
|
|
286
|
0
|
0
|
|
0
|
0
|
0
|
sub constructor_class { $_[0]->{constructor_class} || 'Scalar::Random::PP::OO::Meta::Method::Constructor' } |
287
|
0
|
0
|
|
0
|
0
|
0
|
sub destructor_class { $_[0]->{destructor_class} || 'Scalar::Random::PP::OO::Meta::Method::Destructor' } |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub is_anon_class{ |
290
|
4
|
|
|
4
|
0
|
35
|
return exists $_[0]->{anon_serial_id}; |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
|
293
|
0
|
|
|
0
|
0
|
0
|
sub roles { $_[0]->{roles} } |
294
|
|
|
|
|
|
|
|
295
|
4
|
|
|
4
|
0
|
8
|
sub linearized_isa { @{ get_linear_isa($_[0]->{package}) } } |
|
4
|
|
|
|
|
57
|
|
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
sub get_all_attributes { |
298
|
4
|
|
|
4
|
0
|
8
|
my($self) = @_; |
299
|
4
|
|
|
|
|
21
|
my %attrs = map { %{ $self->initialize($_)->{attributes} } } reverse $self->linearized_isa; |
|
8
|
|
|
|
|
12
|
|
|
8
|
|
|
|
|
19
|
|
300
|
4
|
|
|
|
|
24
|
return values %attrs; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
sub new_object { |
304
|
4
|
|
|
4
|
0
|
9
|
my $meta = shift; |
305
|
4
|
50
|
|
|
|
27
|
my %args = (@_ == 1 ? %{$_[0]} : @_); |
|
4
|
|
|
|
|
26
|
|
306
|
|
|
|
|
|
|
|
307
|
4
|
|
|
|
|
28
|
my $object = bless {}, $meta->name; |
308
|
|
|
|
|
|
|
|
309
|
4
|
|
|
|
|
26
|
$meta->_initialize_object($object, \%args); |
310
|
|
|
|
|
|
|
# BUILDALL |
311
|
4
|
50
|
|
|
|
44
|
if( $object->can('BUILD') ) { |
312
|
0
|
|
|
|
|
0
|
for my $class (reverse $meta->linearized_isa) { |
313
|
0
|
|
0
|
|
|
0
|
my $build = Scalar::Random::PP::OO::Util::get_code_ref($class, 'BUILD') |
314
|
|
|
|
|
|
|
|| next; |
315
|
|
|
|
|
|
|
|
316
|
0
|
|
|
|
|
0
|
$object->$build(\%args); |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
} |
319
|
4
|
|
|
|
|
24
|
return $object; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub clone_object { |
323
|
0
|
|
|
0
|
0
|
0
|
my $class = shift; |
324
|
0
|
|
|
|
|
0
|
my $object = shift; |
325
|
0
|
|
|
|
|
0
|
my $args = $object->Scalar::Random::PP::OO::Object::BUILDARGS(@_); |
326
|
|
|
|
|
|
|
|
327
|
0
|
0
|
0
|
|
|
0
|
(blessed($object) && $object->isa($class->name)) |
328
|
|
|
|
|
|
|
|| $class->throw_error("You must pass an instance of the metaclass (" . $class->name . "), not ($object)"); |
329
|
|
|
|
|
|
|
|
330
|
0
|
|
|
|
|
0
|
my $cloned = bless { %$object }, ref $object; |
331
|
0
|
|
|
|
|
0
|
$class->_initialize_object($cloned, $args, 1); |
332
|
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
0
|
return $cloned; |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
sub _initialize_object{ |
337
|
4
|
|
|
4
|
|
9
|
my($self, $object, $args, $is_cloning) = @_; |
338
|
|
|
|
|
|
|
|
339
|
4
|
|
|
|
|
8
|
my @triggers_queue; |
340
|
|
|
|
|
|
|
|
341
|
4
|
|
|
|
|
11
|
my $used = 0; |
342
|
|
|
|
|
|
|
|
343
|
4
|
|
|
|
|
21
|
foreach my $attribute ($self->get_all_attributes) { |
344
|
4
|
|
|
|
|
20
|
my $init_arg = $attribute->init_arg; |
345
|
4
|
|
|
|
|
17
|
my $slot = $attribute->name; |
346
|
|
|
|
|
|
|
|
347
|
4
|
50
|
33
|
|
|
34
|
if (defined($init_arg) && exists($args->{$init_arg})) { |
348
|
4
|
|
|
|
|
24
|
$object->{$slot} = $attribute->_coerce_and_verify($args->{$init_arg}, $object); |
349
|
|
|
|
|
|
|
|
350
|
4
|
50
|
33
|
|
|
23
|
weaken($object->{$slot}) |
351
|
|
|
|
|
|
|
if ref($object->{$slot}) && $attribute->is_weak_ref; |
352
|
|
|
|
|
|
|
|
353
|
4
|
50
|
|
|
|
20
|
if ($attribute->has_trigger) { |
354
|
0
|
|
|
|
|
0
|
push @triggers_queue, [ $attribute->trigger, $object->{$slot} ]; |
355
|
|
|
|
|
|
|
} |
356
|
4
|
|
|
|
|
15
|
$used++; |
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
else { # no init arg |
359
|
0
|
0
|
0
|
|
|
0
|
if ($attribute->has_default || $attribute->has_builder) { |
|
|
0
|
0
|
|
|
|
|
360
|
0
|
0
|
0
|
|
|
0
|
if (!$attribute->is_lazy && !exists $object->{$slot}) { |
361
|
0
|
|
|
|
|
0
|
my $default = $attribute->default; |
362
|
0
|
|
|
|
|
0
|
my $builder = $attribute->builder; |
363
|
0
|
0
|
|
|
|
0
|
my $value = $builder ? $object->$builder() |
|
|
0
|
|
|
|
|
|
364
|
|
|
|
|
|
|
: ref($default) eq 'CODE' ? $object->$default() |
365
|
|
|
|
|
|
|
: $default; |
366
|
|
|
|
|
|
|
|
367
|
0
|
|
|
|
|
0
|
$object->{$slot} = $attribute->_coerce_and_verify($value, $object); |
368
|
|
|
|
|
|
|
|
369
|
0
|
0
|
0
|
|
|
0
|
weaken($object->{$slot}) |
370
|
|
|
|
|
|
|
if ref($object->{$slot}) && $attribute->is_weak_ref; |
371
|
|
|
|
|
|
|
} |
372
|
|
|
|
|
|
|
} |
373
|
|
|
|
|
|
|
elsif(!$is_cloning && $attribute->is_required) { |
374
|
0
|
|
|
|
|
0
|
$self->throw_error("Attribute (".$attribute->name.") is required"); |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
|
379
|
4
|
50
|
33
|
|
|
12
|
if($used < keys %{$args} && $self->strict_constructor) { |
|
4
|
|
|
|
|
23
|
|
380
|
0
|
|
|
|
|
0
|
$self->_report_unknown_args([ $self->get_all_attributes ], $args); |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
4
|
50
|
|
|
|
15
|
if(@triggers_queue){ |
384
|
0
|
|
|
|
|
0
|
foreach my $trigger_and_value(@triggers_queue){ |
385
|
0
|
|
|
|
|
0
|
my($trigger, $value) = @{$trigger_and_value}; |
|
0
|
|
|
|
|
0
|
|
386
|
0
|
|
|
|
|
0
|
$trigger->($object, $value); |
387
|
|
|
|
|
|
|
} |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
|
390
|
4
|
50
|
|
|
|
16
|
if($self->is_anon_class){ |
391
|
0
|
|
|
|
|
0
|
$object->{__METACLASS__} = $self; |
392
|
|
|
|
|
|
|
} |
393
|
|
|
|
|
|
|
|
394
|
4
|
|
|
|
|
12
|
return; |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
0
|
|
|
0
|
0
|
0
|
sub is_immutable { $_[0]->{is_immutable} } |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
sub strict_constructor{ |
400
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
401
|
0
|
0
|
|
|
|
0
|
if(@_) { |
402
|
0
|
|
|
|
|
0
|
$self->{strict_constructor} = shift; |
403
|
|
|
|
|
|
|
} |
404
|
|
|
|
|
|
|
|
405
|
0
|
|
|
|
|
0
|
foreach my $class($self->linearized_isa) { |
406
|
0
|
0
|
|
|
|
0
|
my $meta = Scalar::Random::PP::OO::Util::get_metaclass_by_name($class) |
407
|
|
|
|
|
|
|
or next; |
408
|
|
|
|
|
|
|
|
409
|
0
|
0
|
|
|
|
0
|
if(exists $meta->{strict_constructor}) { |
410
|
0
|
|
|
|
|
0
|
return $meta->{strict_constructor}; |
411
|
|
|
|
|
|
|
} |
412
|
|
|
|
|
|
|
} |
413
|
|
|
|
|
|
|
|
414
|
0
|
|
|
|
|
0
|
return 0; # false |
415
|
|
|
|
|
|
|
} |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
sub _report_unknown_args { |
418
|
0
|
|
|
0
|
|
0
|
my($metaclass, $attrs, $args) = @_; |
419
|
|
|
|
|
|
|
|
420
|
0
|
|
|
|
|
0
|
my @unknowns; |
421
|
|
|
|
|
|
|
my %init_args; |
422
|
0
|
|
|
|
|
0
|
foreach my $attr(@{$attrs}){ |
|
0
|
|
|
|
|
0
|
|
423
|
0
|
|
|
|
|
0
|
my $init_arg = $attr->init_arg; |
424
|
0
|
0
|
|
|
|
0
|
if(defined $init_arg){ |
425
|
0
|
|
|
|
|
0
|
$init_args{$init_arg}++; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
} |
428
|
|
|
|
|
|
|
|
429
|
0
|
|
|
|
|
0
|
while(my $key = each %{$args}){ |
|
0
|
|
|
|
|
0
|
|
430
|
0
|
0
|
|
|
|
0
|
if(!exists $init_args{$key}){ |
431
|
0
|
|
|
|
|
0
|
push @unknowns, $key; |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
} |
434
|
|
|
|
|
|
|
|
435
|
0
|
|
|
|
|
0
|
$metaclass->throw_error( sprintf |
436
|
|
|
|
|
|
|
"Unknown attribute passed to the constructor of %s: %s", |
437
|
|
|
|
|
|
|
$metaclass->name, Scalar::Random::PP::OO::Util::english_list(@unknowns), |
438
|
|
|
|
|
|
|
); |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Role; |
442
|
|
|
|
|
|
|
|
443
|
0
|
0
|
|
0
|
0
|
0
|
sub method_metaclass{ $_[0]->{method_metaclass} || 'Scalar::Random::PP::OO::Meta::Role::Method' } |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
sub is_anon_role{ |
446
|
0
|
|
|
0
|
0
|
0
|
return exists $_[0]->{anon_serial_id}; |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
|
449
|
0
|
|
|
0
|
0
|
0
|
sub get_roles { $_[0]->{roles} } |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
sub add_before_method_modifier { |
452
|
0
|
|
|
0
|
0
|
0
|
my ($self, $method_name, $method) = @_; |
453
|
|
|
|
|
|
|
|
454
|
0
|
|
0
|
|
|
0
|
push @{ $self->{before_method_modifiers}{$method_name} ||= [] }, $method; |
|
0
|
|
|
|
|
0
|
|
455
|
0
|
|
|
|
|
0
|
return; |
456
|
|
|
|
|
|
|
} |
457
|
|
|
|
|
|
|
sub add_around_method_modifier { |
458
|
0
|
|
|
0
|
0
|
0
|
my ($self, $method_name, $method) = @_; |
459
|
|
|
|
|
|
|
|
460
|
0
|
|
0
|
|
|
0
|
push @{ $self->{around_method_modifiers}{$method_name} ||= [] }, $method; |
|
0
|
|
|
|
|
0
|
|
461
|
0
|
|
|
|
|
0
|
return; |
462
|
|
|
|
|
|
|
} |
463
|
|
|
|
|
|
|
sub add_after_method_modifier { |
464
|
0
|
|
|
0
|
0
|
0
|
my ($self, $method_name, $method) = @_; |
465
|
|
|
|
|
|
|
|
466
|
0
|
|
0
|
|
|
0
|
push @{ $self->{after_method_modifiers}{$method_name} ||= [] }, $method; |
|
0
|
|
|
|
|
0
|
|
467
|
0
|
|
|
|
|
0
|
return; |
468
|
|
|
|
|
|
|
} |
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
sub get_before_method_modifiers { |
471
|
0
|
|
|
0
|
0
|
0
|
my ($self, $method_name) = @_; |
472
|
0
|
|
0
|
|
|
0
|
return @{ $self->{before_method_modifiers}{$method_name} ||= [] } |
|
0
|
|
|
|
|
0
|
|
473
|
|
|
|
|
|
|
} |
474
|
|
|
|
|
|
|
sub get_around_method_modifiers { |
475
|
0
|
|
|
0
|
0
|
0
|
my ($self, $method_name) = @_; |
476
|
0
|
|
0
|
|
|
0
|
return @{ $self->{around_method_modifiers}{$method_name} ||= [] } |
|
0
|
|
|
|
|
0
|
|
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
sub get_after_method_modifiers { |
479
|
0
|
|
|
0
|
0
|
0
|
my ($self, $method_name) = @_; |
480
|
0
|
|
0
|
|
|
0
|
return @{ $self->{after_method_modifiers}{$method_name} ||= [] } |
|
0
|
|
|
|
|
0
|
|
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Attribute; |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
require Scalar::Random::PP::OO::Meta::Method::Accessor; |
486
|
|
|
|
|
|
|
|
487
|
2
|
50
|
|
2
|
0
|
20
|
sub accessor_metaclass{ $_[0]->{accessor_metaclass} || 'Scalar::Random::PP::OO::Meta::Method::Accessor' } |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
# readers |
490
|
|
|
|
|
|
|
|
491
|
8
|
|
|
8
|
0
|
24
|
sub name { $_[0]->{name} } |
492
|
2
|
|
|
2
|
0
|
5
|
sub associated_class { $_[0]->{associated_class} } |
493
|
|
|
|
|
|
|
|
494
|
0
|
|
|
0
|
0
|
0
|
sub accessor { $_[0]->{accessor} } |
495
|
0
|
|
|
0
|
0
|
0
|
sub reader { $_[0]->{reader} } |
496
|
0
|
|
|
0
|
0
|
0
|
sub writer { $_[0]->{writer} } |
497
|
0
|
|
|
0
|
0
|
0
|
sub predicate { $_[0]->{predicate} } |
498
|
0
|
|
|
0
|
0
|
0
|
sub clearer { $_[0]->{clearer} } |
499
|
0
|
|
|
0
|
0
|
0
|
sub handles { $_[0]->{handles} } |
500
|
|
|
|
|
|
|
|
501
|
0
|
|
|
0
|
|
0
|
sub _is_metadata { $_[0]->{is} } |
502
|
0
|
|
|
0
|
0
|
0
|
sub is_required { $_[0]->{required} } |
503
|
2
|
|
|
2
|
0
|
6
|
sub default { $_[0]->{default} } |
504
|
2
|
|
|
2
|
0
|
11
|
sub is_lazy { $_[0]->{lazy} } |
505
|
0
|
|
|
0
|
0
|
0
|
sub is_lazy_build { $_[0]->{lazy_build} } |
506
|
2
|
|
|
2
|
0
|
6
|
sub is_weak_ref { $_[0]->{weak_ref} } |
507
|
4
|
|
|
4
|
0
|
25
|
sub init_arg { $_[0]->{init_arg} } |
508
|
2
|
|
|
2
|
0
|
5
|
sub type_constraint { $_[0]->{type_constraint} } |
509
|
|
|
|
|
|
|
|
510
|
2
|
|
|
2
|
0
|
4
|
sub trigger { $_[0]->{trigger} } |
511
|
2
|
|
|
2
|
0
|
5
|
sub builder { $_[0]->{builder} } |
512
|
2
|
|
|
2
|
0
|
6
|
sub should_auto_deref { $_[0]->{auto_deref} } |
513
|
0
|
|
|
0
|
0
|
0
|
sub should_coerce { $_[0]->{coerce} } |
514
|
|
|
|
|
|
|
|
515
|
0
|
|
|
0
|
0
|
0
|
sub documentation { $_[0]->{documentation} } |
516
|
0
|
|
|
0
|
0
|
0
|
sub insertion_order { $_[0]->{insertion_order} } |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
# predicates |
519
|
|
|
|
|
|
|
|
520
|
0
|
|
|
0
|
0
|
0
|
sub has_accessor { exists $_[0]->{accessor} } |
521
|
0
|
|
|
0
|
0
|
0
|
sub has_reader { exists $_[0]->{reader} } |
522
|
0
|
|
|
0
|
0
|
0
|
sub has_writer { exists $_[0]->{writer} } |
523
|
0
|
|
|
0
|
0
|
0
|
sub has_predicate { exists $_[0]->{predicate} } |
524
|
0
|
|
|
0
|
0
|
0
|
sub has_clearer { exists $_[0]->{clearer} } |
525
|
0
|
|
|
0
|
0
|
0
|
sub has_handles { exists $_[0]->{handles} } |
526
|
|
|
|
|
|
|
|
527
|
0
|
|
|
0
|
0
|
0
|
sub has_default { exists $_[0]->{default} } |
528
|
0
|
|
|
0
|
0
|
0
|
sub has_type_constraint { exists $_[0]->{type_constraint} } |
529
|
4
|
|
|
4
|
0
|
21
|
sub has_trigger { exists $_[0]->{trigger} } |
530
|
0
|
|
|
0
|
0
|
0
|
sub has_builder { exists $_[0]->{builder} } |
531
|
|
|
|
|
|
|
|
532
|
0
|
|
|
0
|
0
|
0
|
sub has_documentation { exists $_[0]->{documentation} } |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
sub _process_options{ |
535
|
2
|
|
|
2
|
|
5
|
my($class, $name, $args) = @_; |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
# taken from Class::MOP::Attribute::new |
538
|
|
|
|
|
|
|
|
539
|
2
|
50
|
|
|
|
7
|
defined($name) |
540
|
|
|
|
|
|
|
or $class->throw_error('You must provide a name for the attribute'); |
541
|
|
|
|
|
|
|
|
542
|
2
|
50
|
|
|
|
9
|
if(!exists $args->{init_arg}){ |
543
|
2
|
|
|
|
|
10
|
$args->{init_arg} = $name; |
544
|
|
|
|
|
|
|
} |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
# 'required' requires eigher 'init_arg', 'builder', or 'default' |
547
|
2
|
|
|
|
|
5
|
my $can_be_required = defined( $args->{init_arg} ); |
548
|
|
|
|
|
|
|
|
549
|
2
|
50
|
|
|
|
13
|
if(exists $args->{builder}){ |
|
|
50
|
|
|
|
|
|
550
|
|
|
|
|
|
|
# XXX: |
551
|
|
|
|
|
|
|
# Moose refuses a CODE ref builder, but Scalar::Random::PP::OO doesn't for backward compatibility |
552
|
|
|
|
|
|
|
# This feature will be changed in a future. (gfx) |
553
|
0
|
0
|
|
|
|
0
|
$class->throw_error('builder must be a defined scalar value which is a method name') |
554
|
|
|
|
|
|
|
#if ref $args->{builder} || !defined $args->{builder}; |
555
|
|
|
|
|
|
|
if !defined $args->{builder}; |
556
|
|
|
|
|
|
|
|
557
|
0
|
|
|
|
|
0
|
$can_be_required++; |
558
|
|
|
|
|
|
|
} |
559
|
|
|
|
|
|
|
elsif(exists $args->{default}){ |
560
|
0
|
0
|
0
|
|
|
0
|
if(ref $args->{default} && ref($args->{default}) ne 'CODE'){ |
561
|
0
|
|
|
|
|
0
|
$class->throw_error("References are not allowed as default values, you must " |
562
|
|
|
|
|
|
|
. "wrap the default of '$name' in a CODE reference (ex: sub { [] } and not [])"); |
563
|
|
|
|
|
|
|
} |
564
|
0
|
|
|
|
|
0
|
$can_be_required++; |
565
|
|
|
|
|
|
|
} |
566
|
|
|
|
|
|
|
|
567
|
2
|
50
|
33
|
|
|
9
|
if( $args->{required} && !$can_be_required ) { |
568
|
0
|
|
|
|
|
0
|
$class->throw_error("You cannot have a required attribute ($name) without a default, builder, or an init_arg"); |
569
|
|
|
|
|
|
|
} |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
# taken from Scalar::Random::PP::OO::Meta::Attribute->new and ->_process_args |
572
|
|
|
|
|
|
|
|
573
|
2
|
50
|
|
|
|
8
|
if(exists $args->{is}){ |
574
|
2
|
|
|
|
|
4
|
my $is = $args->{is}; |
575
|
|
|
|
|
|
|
|
576
|
2
|
50
|
|
|
|
7
|
if($is eq 'ro'){ |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
577
|
2
|
|
33
|
|
|
15
|
$args->{reader} ||= $name; |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
elsif($is eq 'rw'){ |
580
|
0
|
0
|
|
|
|
0
|
if(exists $args->{writer}){ |
581
|
0
|
|
0
|
|
|
0
|
$args->{reader} ||= $name; |
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
else{ |
584
|
0
|
|
0
|
|
|
0
|
$args->{accessor} ||= $name; |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
} |
587
|
|
|
|
|
|
|
elsif($is eq 'bare'){ |
588
|
|
|
|
|
|
|
# do nothing, but don't complain (later) about missing methods |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
else{ |
591
|
0
|
0
|
|
|
|
0
|
$is = 'undef' if !defined $is; |
592
|
0
|
|
|
|
|
0
|
$class->throw_error("I do not understand this option (is => $is) on attribute ($name)"); |
593
|
|
|
|
|
|
|
} |
594
|
|
|
|
|
|
|
} |
595
|
|
|
|
|
|
|
|
596
|
2
|
|
|
|
|
4
|
my $tc; |
597
|
2
|
50
|
|
|
|
8
|
if(exists $args->{isa}){ |
598
|
0
|
|
|
|
|
0
|
$tc = $args->{type_constraint} = Scalar::Random::PP::OO::Util::TypeConstraints::find_or_create_isa_type_constraint($args->{isa}); |
599
|
|
|
|
|
|
|
} |
600
|
|
|
|
|
|
|
|
601
|
2
|
50
|
|
|
|
7
|
if(exists $args->{does}){ |
602
|
0
|
0
|
|
|
|
0
|
if(defined $tc){ # both isa and does supplied |
603
|
0
|
|
|
|
|
0
|
my $does_ok = do{ |
604
|
0
|
|
|
|
|
0
|
local $@; |
605
|
0
|
|
|
|
|
0
|
eval{ "$tc"->does($args) }; |
|
0
|
|
|
|
|
0
|
|
606
|
|
|
|
|
|
|
}; |
607
|
0
|
0
|
|
|
|
0
|
if(!$does_ok){ |
608
|
0
|
|
|
|
|
0
|
$class->throw_error("Cannot have both an isa option and a does option because '$tc' does not do '$args->{does}' on attribute ($name)"); |
609
|
|
|
|
|
|
|
} |
610
|
|
|
|
|
|
|
} |
611
|
|
|
|
|
|
|
else { |
612
|
0
|
|
|
|
|
0
|
$tc = $args->{type_constraint} = Scalar::Random::PP::OO::Util::TypeConstraints::find_or_create_does_type_constraint($args->{does}); |
613
|
|
|
|
|
|
|
} |
614
|
|
|
|
|
|
|
} |
615
|
|
|
|
|
|
|
|
616
|
2
|
50
|
|
|
|
7
|
if($args->{coerce}){ |
617
|
0
|
0
|
|
|
|
0
|
defined($tc) |
618
|
|
|
|
|
|
|
|| $class->throw_error("You cannot have coercion without specifying a type constraint on attribute ($name)"); |
619
|
|
|
|
|
|
|
|
620
|
0
|
0
|
|
|
|
0
|
$args->{weak_ref} |
621
|
|
|
|
|
|
|
&& $class->throw_error("You cannot have a weak reference to a coerced value on attribute ($name)"); |
622
|
|
|
|
|
|
|
} |
623
|
|
|
|
|
|
|
|
624
|
2
|
50
|
|
|
|
7
|
if ($args->{lazy_build}) { |
625
|
0
|
0
|
|
|
|
0
|
exists($args->{default}) |
626
|
|
|
|
|
|
|
&& $class->throw_error("You can not use lazy_build and default for the same attribute ($name)"); |
627
|
|
|
|
|
|
|
|
628
|
0
|
|
|
|
|
0
|
$args->{lazy} = 1; |
629
|
0
|
|
0
|
|
|
0
|
$args->{builder} ||= "_build_${name}"; |
630
|
0
|
0
|
|
|
|
0
|
if ($name =~ /^_/) { |
631
|
0
|
|
0
|
|
|
0
|
$args->{clearer} ||= "_clear${name}"; |
632
|
0
|
|
0
|
|
|
0
|
$args->{predicate} ||= "_has${name}"; |
633
|
|
|
|
|
|
|
} |
634
|
|
|
|
|
|
|
else { |
635
|
0
|
|
0
|
|
|
0
|
$args->{clearer} ||= "clear_${name}"; |
636
|
0
|
|
0
|
|
|
0
|
$args->{predicate} ||= "has_${name}"; |
637
|
|
|
|
|
|
|
} |
638
|
|
|
|
|
|
|
} |
639
|
|
|
|
|
|
|
|
640
|
2
|
50
|
|
|
|
7
|
if ($args->{auto_deref}) { |
641
|
0
|
0
|
|
|
|
0
|
defined($tc) |
642
|
|
|
|
|
|
|
|| $class->throw_error("You cannot auto-dereference without specifying a type constraint on attribute ($name)"); |
643
|
|
|
|
|
|
|
|
644
|
0
|
0
|
0
|
|
|
0
|
( $tc->is_a_type_of('ArrayRef') || $tc->is_a_type_of('HashRef') ) |
645
|
|
|
|
|
|
|
|| $class->throw_error("You cannot auto-dereference anything other than a ArrayRef or HashRef on attribute ($name)"); |
646
|
|
|
|
|
|
|
} |
647
|
|
|
|
|
|
|
|
648
|
2
|
50
|
|
|
|
7
|
if (exists $args->{trigger}) { |
649
|
0
|
0
|
|
|
|
0
|
('CODE' eq ref $args->{trigger}) |
650
|
|
|
|
|
|
|
|| $class->throw_error("Trigger must be a CODE ref on attribute ($name)"); |
651
|
|
|
|
|
|
|
} |
652
|
|
|
|
|
|
|
|
653
|
2
|
50
|
|
|
|
6
|
if ($args->{lazy}) { |
654
|
0
|
0
|
0
|
|
|
0
|
(exists $args->{default} || defined $args->{builder}) |
655
|
|
|
|
|
|
|
|| $class->throw_error("You cannot have lazy attribute ($name) without specifying a default value for it"); |
656
|
|
|
|
|
|
|
} |
657
|
|
|
|
|
|
|
|
658
|
2
|
|
|
|
|
4
|
return; |
659
|
|
|
|
|
|
|
} |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::TypeConstraint; |
663
|
|
|
|
|
|
|
|
664
|
0
|
|
|
0
|
0
|
0
|
sub name { $_[0]->{name} } |
665
|
0
|
|
|
0
|
0
|
0
|
sub parent { $_[0]->{parent} } |
666
|
0
|
|
|
0
|
0
|
0
|
sub message { $_[0]->{message} } |
667
|
|
|
|
|
|
|
|
668
|
0
|
|
|
0
|
0
|
0
|
sub type_parameter { $_[0]->{type_parameter} } |
669
|
0
|
|
|
0
|
|
0
|
sub _compiled_type_constraint{ $_[0]->{compiled_type_constraint} } |
670
|
0
|
|
|
0
|
|
0
|
sub _compiled_type_coercion { $_[0]->{_compiled_type_coercion} } |
671
|
|
|
|
|
|
|
|
672
|
0
|
|
|
0
|
|
0
|
sub __is_parameterized { exists $_[0]->{type_parameter} } |
673
|
0
|
|
|
0
|
0
|
0
|
sub has_coercion { exists $_[0]->{_compiled_type_coercion} } |
674
|
|
|
|
|
|
|
|
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
sub compile_type_constraint{ |
677
|
6
|
|
|
6
|
0
|
9
|
my($self) = @_; |
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
# add parents first |
680
|
6
|
|
|
|
|
6
|
my @checks; |
681
|
6
|
|
|
|
|
17
|
for(my $parent = $self->{parent}; defined $parent; $parent = $parent->{parent}){ |
682
|
6
|
50
|
|
|
|
38
|
if($parent->{hand_optimized_type_constraint}){ |
|
|
50
|
|
|
|
|
|
683
|
0
|
|
|
|
|
0
|
unshift @checks, $parent->{hand_optimized_type_constraint}; |
684
|
0
|
|
|
|
|
0
|
last; # a hand optimized constraint must include all the parents |
685
|
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
elsif($parent->{constraint}){ |
687
|
0
|
|
|
|
|
0
|
unshift @checks, $parent->{constraint}; |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
} |
690
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
# then add child |
692
|
6
|
50
|
|
|
|
49
|
if($self->{constraint}){ |
693
|
0
|
|
|
|
|
0
|
push @checks, $self->{constraint}; |
694
|
|
|
|
|
|
|
} |
695
|
|
|
|
|
|
|
|
696
|
6
|
50
|
|
|
|
14
|
if($self->{type_constraints}){ # Union |
697
|
0
|
|
|
|
|
0
|
my @types = map{ $_->{compiled_type_constraint} } @{ $self->{type_constraints} }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
698
|
|
|
|
|
|
|
push @checks, sub{ |
699
|
0
|
|
|
0
|
|
0
|
foreach my $c(@types){ |
700
|
0
|
0
|
|
|
|
0
|
return 1 if $c->($_[0]); |
701
|
|
|
|
|
|
|
} |
702
|
0
|
|
|
|
|
0
|
return 0; |
703
|
0
|
|
|
|
|
0
|
}; |
704
|
|
|
|
|
|
|
} |
705
|
|
|
|
|
|
|
|
706
|
6
|
50
|
|
|
|
12
|
if(@checks == 0){ |
707
|
6
|
|
|
|
|
13
|
$self->{compiled_type_constraint} = \&Scalar::Random::PP::OO::Util::TypeConstraints::Any; |
708
|
|
|
|
|
|
|
} |
709
|
|
|
|
|
|
|
else{ |
710
|
|
|
|
|
|
|
$self->{compiled_type_constraint} = sub{ |
711
|
0
|
|
|
0
|
|
0
|
my(@args) = @_; |
712
|
0
|
|
|
|
|
0
|
local $_ = $args[0]; |
713
|
0
|
|
|
|
|
0
|
foreach my $c(@checks){ |
714
|
0
|
0
|
|
|
|
0
|
return undef if !$c->(@args); |
715
|
|
|
|
|
|
|
} |
716
|
0
|
|
|
|
|
0
|
return 1; |
717
|
0
|
|
|
|
|
0
|
}; |
718
|
|
|
|
|
|
|
} |
719
|
6
|
|
|
|
|
10
|
return; |
720
|
|
|
|
|
|
|
} |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
sub check { |
723
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
724
|
0
|
|
|
|
|
0
|
return $self->_compiled_type_constraint->(@_); |
725
|
|
|
|
|
|
|
} |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
|
728
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Object; |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
sub BUILDARGS { |
731
|
6
|
|
|
6
|
0
|
18
|
my $class = shift; |
732
|
|
|
|
|
|
|
|
733
|
6
|
50
|
|
|
|
26
|
if (scalar @_ == 1) { |
734
|
0
|
0
|
|
|
|
0
|
(ref($_[0]) eq 'HASH') |
735
|
|
|
|
|
|
|
|| $class->meta->throw_error("Single parameters to new() must be a HASH ref"); |
736
|
|
|
|
|
|
|
|
737
|
0
|
|
|
|
|
0
|
return {%{$_[0]}}; |
|
0
|
|
|
|
|
0
|
|
738
|
|
|
|
|
|
|
} |
739
|
|
|
|
|
|
|
else { |
740
|
6
|
|
|
|
|
21
|
return {@_}; |
741
|
|
|
|
|
|
|
} |
742
|
|
|
|
|
|
|
} |
743
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
sub new { |
745
|
4
|
|
|
4
|
0
|
12
|
my $class = shift; |
746
|
|
|
|
|
|
|
|
747
|
4
|
50
|
|
|
|
17
|
$class->meta->throw_error('Cannot call new() on an instance') if ref $class; |
748
|
|
|
|
|
|
|
|
749
|
4
|
|
|
|
|
30
|
my $args = $class->BUILDARGS(@_); |
750
|
|
|
|
|
|
|
|
751
|
4
|
|
|
|
|
42
|
my $meta = Scalar::Random::PP::OO::Meta::Class->initialize($class); |
752
|
4
|
|
|
|
|
25
|
return $meta->new_object($args); |
753
|
|
|
|
|
|
|
} |
754
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
sub DESTROY { |
756
|
4
|
|
|
4
|
|
1281
|
my $self = shift; |
757
|
|
|
|
|
|
|
|
758
|
4
|
50
|
|
|
|
284
|
return unless $self->can('DEMOLISH'); # short circuit |
759
|
|
|
|
|
|
|
|
760
|
0
|
|
|
|
|
0
|
local $?; |
761
|
|
|
|
|
|
|
|
762
|
0
|
|
|
|
|
0
|
my $e = do{ |
763
|
0
|
|
|
|
|
0
|
local $@; |
764
|
0
|
|
|
|
|
0
|
eval{ |
765
|
|
|
|
|
|
|
# DEMOLISHALL |
766
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
# We cannot count on being able to retrieve a previously made |
768
|
|
|
|
|
|
|
# metaclass, _or_ being able to make a new one during global |
769
|
|
|
|
|
|
|
# destruction. However, we should still be able to use mro at |
770
|
|
|
|
|
|
|
# that time (at least tests suggest so ;) |
771
|
|
|
|
|
|
|
|
772
|
0
|
|
|
|
|
0
|
foreach my $class (@{ Scalar::Random::PP::OO::Util::get_linear_isa(ref $self) }) { |
|
0
|
|
|
|
|
0
|
|
773
|
0
|
|
0
|
|
|
0
|
my $demolish = Scalar::Random::PP::OO::Util::get_code_ref($class, 'DEMOLISH') |
774
|
|
|
|
|
|
|
|| next; |
775
|
|
|
|
|
|
|
|
776
|
0
|
|
|
|
|
0
|
$self->$demolish($Scalar::Random::PP::OO::Util::in_global_destruction); |
777
|
|
|
|
|
|
|
} |
778
|
|
|
|
|
|
|
}; |
779
|
0
|
|
|
|
|
0
|
$@; |
780
|
|
|
|
|
|
|
}; |
781
|
|
|
|
|
|
|
|
782
|
2
|
|
|
2
|
|
12
|
no warnings 'misc'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
344
|
|
783
|
0
|
0
|
|
|
|
0
|
die $e if $e; # rethrow |
784
|
|
|
|
|
|
|
} |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
sub BUILDALL { |
787
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
788
|
|
|
|
|
|
|
|
789
|
|
|
|
|
|
|
# short circuit |
790
|
0
|
0
|
|
|
|
0
|
return unless $self->can('BUILD'); |
791
|
|
|
|
|
|
|
|
792
|
0
|
|
|
|
|
0
|
for my $class (reverse $self->meta->linearized_isa) { |
793
|
0
|
|
0
|
|
|
0
|
my $build = Scalar::Random::PP::OO::Util::get_code_ref($class, 'BUILD') |
794
|
|
|
|
|
|
|
|| next; |
795
|
|
|
|
|
|
|
|
796
|
0
|
|
|
|
|
0
|
$self->$build(@_); |
797
|
|
|
|
|
|
|
} |
798
|
0
|
|
|
|
|
0
|
return; |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
sub DEMOLISHALL; |
802
|
|
|
|
|
|
|
*DEMOLISHALL = \&DESTROY; |
803
|
|
|
|
|
|
|
|
804
|
|
|
|
|
|
|
# Contents of Mouse::Exporter |
805
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Exporter; |
806
|
2
|
|
|
2
|
|
11
|
use strict; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
66
|
|
807
|
2
|
|
|
2
|
|
8
|
use warnings; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
54
|
|
808
|
|
|
|
|
|
|
|
809
|
2
|
|
|
2
|
|
8
|
use Carp (); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
68
|
|
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
my %SPEC; |
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
my $strict_bits; |
814
|
2
|
|
|
2
|
|
83
|
BEGIN{ $strict_bits = strict::bits(qw(subs refs vars)); } |
815
|
|
|
|
|
|
|
|
816
|
|
|
|
|
|
|
my $warnings_extra_bits; |
817
|
2
|
|
|
2
|
|
984
|
BEGIN{ $warnings_extra_bits = warnings::bits(FATAL => 'recursion') } |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
# it must be "require", because Scalar::Random::PP::OO::Util depends on Scalar::Random::PP::OO::Exporter, |
820
|
|
|
|
|
|
|
# which depends on Scalar::Random::PP::OO::Util::import() |
821
|
|
|
|
|
|
|
require Scalar::Random::PP::OO::Util; |
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
sub import{ |
824
|
|
|
|
|
|
|
# strict->import; |
825
|
8
|
|
|
8
|
|
22
|
$^H |= $strict_bits; |
826
|
|
|
|
|
|
|
# warnings->import('all', FATAL => 'recursion'); |
827
|
8
|
|
|
|
|
28
|
${^WARNING_BITS} |= $warnings::Bits{all}; |
828
|
8
|
|
|
|
|
15
|
${^WARNING_BITS} |= $warnings_extra_bits; |
829
|
8
|
|
|
|
|
7081
|
return; |
830
|
|
|
|
|
|
|
} |
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
sub setup_import_methods{ |
834
|
12
|
|
|
12
|
0
|
39
|
my($class, %args) = @_; |
835
|
|
|
|
|
|
|
|
836
|
12
|
|
33
|
|
|
68
|
my $exporting_package = $args{exporting_package} ||= caller(); |
837
|
|
|
|
|
|
|
|
838
|
12
|
|
|
|
|
46
|
my($import, $unimport) = $class->build_import_methods(%args); |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Util::install_subroutines($exporting_package, |
841
|
|
|
|
|
|
|
import => $import, |
842
|
|
|
|
|
|
|
unimport => $unimport, |
843
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
export_to_level => sub { |
845
|
0
|
|
|
0
|
|
0
|
my($package, $level, undef, @args) = @_; # the third argument is redundant |
846
|
0
|
|
|
|
|
0
|
$package->import({ into_level => $level + 1 }, @args); |
847
|
|
|
|
|
|
|
}, |
848
|
|
|
|
|
|
|
export => sub { |
849
|
0
|
|
|
0
|
|
0
|
my($package, $into, @args) = @_; |
850
|
0
|
|
|
|
|
0
|
$package->import({ into => $into }, @args); |
851
|
|
|
|
|
|
|
}, |
852
|
12
|
|
|
|
|
88
|
); |
853
|
12
|
|
|
|
|
31
|
return; |
854
|
|
|
|
|
|
|
} |
855
|
|
|
|
|
|
|
|
856
|
|
|
|
|
|
|
sub build_import_methods{ |
857
|
12
|
|
|
12
|
0
|
49
|
my($self, %args) = @_; |
858
|
|
|
|
|
|
|
|
859
|
12
|
|
33
|
|
|
38
|
my $exporting_package = $args{exporting_package} ||= caller(); |
860
|
|
|
|
|
|
|
|
861
|
12
|
|
|
|
|
20
|
$SPEC{$exporting_package} = \%args; |
862
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
# canonicalize args |
864
|
12
|
|
|
|
|
12
|
my @export_from; |
865
|
12
|
100
|
|
|
|
28
|
if($args{also}){ |
866
|
2
|
|
|
|
|
4
|
my %seen; |
867
|
2
|
|
|
|
|
5
|
my @stack = ($exporting_package); |
868
|
|
|
|
|
|
|
|
869
|
2
|
|
|
|
|
8
|
while(my $current = shift @stack){ |
870
|
4
|
|
|
|
|
6
|
push @export_from, $current; |
871
|
|
|
|
|
|
|
|
872
|
4
|
100
|
|
|
|
20
|
my $also = $SPEC{$current}{also} or next; |
873
|
2
|
50
|
|
|
|
11
|
push @stack, grep{ !$seen{$_}++ } ref($also) ? @{ $also } : $also; |
|
2
|
|
|
|
|
15
|
|
|
0
|
|
|
|
|
0
|
|
874
|
|
|
|
|
|
|
} |
875
|
|
|
|
|
|
|
} |
876
|
|
|
|
|
|
|
else{ |
877
|
10
|
|
|
|
|
19
|
@export_from = ($exporting_package); |
878
|
|
|
|
|
|
|
} |
879
|
|
|
|
|
|
|
|
880
|
12
|
|
|
|
|
16
|
my %exports; |
881
|
|
|
|
|
|
|
my @removables; |
882
|
0
|
|
|
|
|
0
|
my @all; |
883
|
|
|
|
|
|
|
|
884
|
0
|
|
|
|
|
0
|
my @init_meta_methods; |
885
|
|
|
|
|
|
|
|
886
|
12
|
|
|
|
|
22
|
foreach my $package(@export_from){ |
887
|
14
|
50
|
|
|
|
39
|
my $spec = $SPEC{$package} or next; |
888
|
|
|
|
|
|
|
|
889
|
14
|
100
|
|
|
|
34
|
if(my $as_is = $spec->{as_is}){ |
890
|
12
|
|
|
|
|
14
|
foreach my $thingy (@{$as_is}){ |
|
12
|
|
|
|
|
20
|
|
891
|
138
|
|
|
|
|
131
|
my($code_package, $code_name, $code); |
892
|
|
|
|
|
|
|
|
893
|
138
|
100
|
|
|
|
219
|
if(ref($thingy)){ |
894
|
14
|
|
|
|
|
13
|
$code = $thingy; |
895
|
14
|
|
|
|
|
30
|
($code_package, $code_name) = Scalar::Random::PP::OO::Util::get_code_info($code); |
896
|
|
|
|
|
|
|
} |
897
|
|
|
|
|
|
|
else{ |
898
|
124
|
|
|
|
|
121
|
$code_package = $package; |
899
|
124
|
|
|
|
|
118
|
$code_name = $thingy; |
900
|
2
|
|
|
2
|
|
10
|
no strict 'refs'; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
1874
|
|
901
|
124
|
|
|
|
|
120
|
$code = \&{ $code_package . '::' . $code_name }; |
|
124
|
|
|
|
|
443
|
|
902
|
|
|
|
|
|
|
} |
903
|
|
|
|
|
|
|
|
904
|
138
|
|
|
|
|
239
|
push @all, $code_name; |
905
|
138
|
|
|
|
|
199
|
$exports{$code_name} = $code; |
906
|
138
|
100
|
|
|
|
251
|
if($code_package eq $package){ |
907
|
126
|
|
|
|
|
210
|
push @removables, $code_name; |
908
|
|
|
|
|
|
|
} |
909
|
|
|
|
|
|
|
} |
910
|
|
|
|
|
|
|
} |
911
|
|
|
|
|
|
|
|
912
|
14
|
100
|
|
|
|
195
|
if(my $init_meta = $package->can('init_meta')){ |
913
|
6
|
50
|
|
|
|
17
|
if(!grep{ $_ == $init_meta } @init_meta_methods){ |
|
0
|
|
|
|
|
0
|
|
914
|
6
|
|
|
|
|
14
|
push @init_meta_methods, $init_meta; |
915
|
|
|
|
|
|
|
} |
916
|
|
|
|
|
|
|
} |
917
|
|
|
|
|
|
|
} |
918
|
12
|
|
|
|
|
55
|
$args{EXPORTS} = \%exports; |
919
|
12
|
|
|
|
|
27
|
$args{REMOVABLES} = \@removables; |
920
|
|
|
|
|
|
|
|
921
|
12
|
|
50
|
|
|
60
|
$args{groups}{all} ||= \@all; |
922
|
|
|
|
|
|
|
|
923
|
12
|
100
|
|
|
|
34
|
if(my $default_list = $args{groups}{default}){ |
924
|
2
|
|
|
|
|
3
|
my %default; |
925
|
2
|
|
|
|
|
2
|
foreach my $keyword(@{$default_list}){ |
|
2
|
|
|
|
|
5
|
|
926
|
0
|
|
0
|
|
|
0
|
$default{$keyword} = $exports{$keyword} |
927
|
|
|
|
|
|
|
|| Carp::confess(qq{The $exporting_package package does not export "$keyword"}); |
928
|
|
|
|
|
|
|
} |
929
|
2
|
|
|
|
|
4
|
$args{DEFAULT} = \%default; |
930
|
|
|
|
|
|
|
} |
931
|
|
|
|
|
|
|
else{ |
932
|
10
|
|
50
|
|
|
46
|
$args{groups}{default} ||= \@all; |
933
|
10
|
|
|
|
|
18
|
$args{DEFAULT} = $args{EXPORTS}; |
934
|
|
|
|
|
|
|
} |
935
|
|
|
|
|
|
|
|
936
|
12
|
100
|
|
|
|
29
|
if(@init_meta_methods){ |
937
|
6
|
|
|
|
|
11
|
$args{INIT_META} = \@init_meta_methods; |
938
|
|
|
|
|
|
|
} |
939
|
|
|
|
|
|
|
|
940
|
12
|
|
|
|
|
45
|
return (\&do_import, \&do_unimport); |
941
|
|
|
|
|
|
|
} |
942
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
# the entity of general import() |
945
|
|
|
|
|
|
|
sub do_import { |
946
|
36
|
|
|
36
|
0
|
103
|
my($package, @args) = @_; |
947
|
|
|
|
|
|
|
|
948
|
36
|
|
33
|
|
|
119
|
my $spec = $SPEC{$package} |
949
|
|
|
|
|
|
|
|| Carp::confess("The package $package package does not use Scalar::Random::PP::OO::Exporter"); |
950
|
|
|
|
|
|
|
|
951
|
36
|
50
|
|
|
|
114
|
my $into = _get_caller_package(ref($args[0]) ? shift @args : undef); |
952
|
|
|
|
|
|
|
|
953
|
36
|
|
|
|
|
49
|
my @exports; |
954
|
|
|
|
|
|
|
my @traits; |
955
|
|
|
|
|
|
|
|
956
|
36
|
|
|
|
|
86
|
while(@args){ |
957
|
46
|
|
|
|
|
58
|
my $arg = shift @args; |
958
|
46
|
50
|
|
|
|
213
|
if($arg =~ s/^-//){ |
|
|
100
|
|
|
|
|
|
959
|
0
|
0
|
|
|
|
0
|
if($arg eq 'traits'){ |
960
|
0
|
0
|
|
|
|
0
|
push @traits, ref($args[0]) ? @{shift(@args)} : shift(@args); |
|
0
|
|
|
|
|
0
|
|
961
|
|
|
|
|
|
|
} |
962
|
|
|
|
|
|
|
else { |
963
|
0
|
|
|
|
|
0
|
Scalar::Random::PP::OO::Util::not_supported("-$arg"); |
964
|
|
|
|
|
|
|
} |
965
|
|
|
|
|
|
|
} |
966
|
|
|
|
|
|
|
elsif($arg =~ s/^://){ |
967
|
20
|
|
33
|
|
|
64
|
my $group = $spec->{groups}{$arg} |
968
|
|
|
|
|
|
|
|| Carp::confess(qq{The $package package does not export the group "$arg"}); |
969
|
20
|
|
|
|
|
25
|
push @exports, @{$group}; |
|
20
|
|
|
|
|
87
|
|
970
|
|
|
|
|
|
|
} |
971
|
|
|
|
|
|
|
else{ |
972
|
26
|
|
|
|
|
63
|
push @exports, $arg; |
973
|
|
|
|
|
|
|
} |
974
|
|
|
|
|
|
|
} |
975
|
|
|
|
|
|
|
|
976
|
|
|
|
|
|
|
# strict->import; |
977
|
36
|
|
|
|
|
83
|
$^H |= $strict_bits; |
978
|
|
|
|
|
|
|
# warnings->import('all', FATAL => 'recursion'); |
979
|
36
|
|
|
|
|
102
|
${^WARNING_BITS} |= $warnings::Bits{all}; |
980
|
36
|
|
|
|
|
73
|
${^WARNING_BITS} |= $warnings_extra_bits; |
981
|
|
|
|
|
|
|
|
982
|
36
|
100
|
|
|
|
111
|
if($spec->{INIT_META}){ |
|
|
50
|
|
|
|
|
|
983
|
2
|
|
|
|
|
4
|
my $meta; |
984
|
2
|
|
|
|
|
3
|
foreach my $init_meta(@{$spec->{INIT_META}}){ |
|
2
|
|
|
|
|
7
|
|
985
|
2
|
|
|
|
|
10
|
$meta = $package->$init_meta(for_class => $into); |
986
|
|
|
|
|
|
|
} |
987
|
|
|
|
|
|
|
|
988
|
2
|
50
|
|
|
|
10
|
if(@traits){ |
989
|
0
|
|
|
|
|
0
|
my $type = (split /::/, ref $meta)[-1]; # e.g. "Class" for "My::Meta::Class" |
990
|
0
|
0
|
|
|
|
0
|
@traits = |
991
|
|
|
|
|
|
|
map{ |
992
|
0
|
|
|
|
|
0
|
ref($_) ? $_ |
993
|
|
|
|
|
|
|
: Scalar::Random::PP::OO::Util::resolve_metaclass_alias($type => $_, trait => 1) |
994
|
|
|
|
|
|
|
} @traits; |
995
|
|
|
|
|
|
|
|
996
|
0
|
|
|
|
|
0
|
require Scalar::Random::PP::OO::Util::MetaRole; |
997
|
0
|
0
|
|
|
|
0
|
Scalar::Random::PP::OO::Util::MetaRole::apply_metaroles( |
998
|
|
|
|
|
|
|
for => $into, |
999
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Util::is_a_metarole($into->meta) |
1000
|
|
|
|
|
|
|
? (role_metaroles => { role => \@traits }) |
1001
|
|
|
|
|
|
|
: (class_metaroles => { class => \@traits }), |
1002
|
|
|
|
|
|
|
); |
1003
|
|
|
|
|
|
|
} |
1004
|
|
|
|
|
|
|
} |
1005
|
|
|
|
|
|
|
elsif(@traits){ |
1006
|
0
|
|
|
|
|
0
|
Carp::confess("Cannot provide traits when $package does not have an init_meta() method"); |
1007
|
|
|
|
|
|
|
} |
1008
|
|
|
|
|
|
|
|
1009
|
36
|
100
|
|
|
|
61
|
if(@exports){ |
1010
|
28
|
|
|
|
|
28
|
my @export_table; |
1011
|
28
|
|
|
|
|
47
|
foreach my $keyword(@exports){ |
1012
|
86
|
|
33
|
|
|
311
|
push @export_table, |
1013
|
|
|
|
|
|
|
$keyword => ($spec->{EXPORTS}{$keyword} |
1014
|
|
|
|
|
|
|
|| Carp::confess(qq{The $package package does not export "$keyword"}) |
1015
|
|
|
|
|
|
|
); |
1016
|
|
|
|
|
|
|
} |
1017
|
28
|
|
|
|
|
73
|
Scalar::Random::PP::OO::Util::install_subroutines($into, @export_table); |
1018
|
|
|
|
|
|
|
} |
1019
|
|
|
|
|
|
|
else{ |
1020
|
8
|
|
|
|
|
10
|
Scalar::Random::PP::OO::Util::install_subroutines($into, %{$spec->{DEFAULT}}); |
|
8
|
|
|
|
|
32
|
|
1021
|
|
|
|
|
|
|
} |
1022
|
36
|
|
|
|
|
7997
|
return; |
1023
|
|
|
|
|
|
|
} |
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
# the entity of general unimport() |
1026
|
|
|
|
|
|
|
sub do_unimport { |
1027
|
0
|
|
|
0
|
0
|
0
|
my($package, $arg) = @_; |
1028
|
|
|
|
|
|
|
|
1029
|
0
|
|
0
|
|
|
0
|
my $spec = $SPEC{$package} |
1030
|
|
|
|
|
|
|
|| Carp::confess("The package $package does not use Scalar::Random::PP::OO::Exporter"); |
1031
|
|
|
|
|
|
|
|
1032
|
0
|
|
|
|
|
0
|
my $from = _get_caller_package($arg); |
1033
|
|
|
|
|
|
|
|
1034
|
0
|
|
|
|
|
0
|
my $stash = do{ |
1035
|
2
|
|
|
2
|
|
17
|
no strict 'refs'; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
393
|
|
1036
|
0
|
|
|
|
|
0
|
\%{$from . '::'} |
|
0
|
|
|
|
|
0
|
|
1037
|
|
|
|
|
|
|
}; |
1038
|
|
|
|
|
|
|
|
1039
|
0
|
|
|
|
|
0
|
for my $keyword (@{ $spec->{REMOVABLES} }) { |
|
0
|
|
|
|
|
0
|
|
1040
|
0
|
0
|
|
|
|
0
|
next if !exists $stash->{$keyword}; |
1041
|
0
|
|
|
|
|
0
|
my $gv = \$stash->{$keyword}; |
1042
|
0
|
0
|
0
|
|
|
0
|
if(ref($gv) eq 'GLOB' && *{$gv}{CODE} == $spec->{EXPORTS}{$keyword}){ # make sure it is from us |
|
0
|
|
|
|
|
0
|
|
1043
|
0
|
|
|
|
|
0
|
delete $stash->{$keyword}; |
1044
|
|
|
|
|
|
|
} |
1045
|
|
|
|
|
|
|
} |
1046
|
0
|
|
|
|
|
0
|
return; |
1047
|
|
|
|
|
|
|
} |
1048
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
sub _get_caller_package { |
1050
|
36
|
|
|
36
|
|
45
|
my($arg) = @_; |
1051
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
# We need one extra level because it's called by import so there's a layer |
1053
|
|
|
|
|
|
|
# of indirection |
1054
|
36
|
50
|
|
|
|
58
|
if(ref $arg){ |
1055
|
0
|
0
|
|
|
|
0
|
return defined($arg->{into}) ? $arg->{into} |
|
|
0
|
|
|
|
|
|
1056
|
|
|
|
|
|
|
: defined($arg->{into_level}) ? scalar caller(1 + $arg->{into_level}) |
1057
|
|
|
|
|
|
|
: scalar caller(1); |
1058
|
|
|
|
|
|
|
} |
1059
|
|
|
|
|
|
|
else{ |
1060
|
36
|
|
|
|
|
106
|
return scalar caller(1); |
1061
|
|
|
|
|
|
|
} |
1062
|
|
|
|
|
|
|
} |
1063
|
|
|
|
|
|
|
|
1064
|
|
|
|
|
|
|
#sub _spec{ %SPEC } |
1065
|
|
|
|
|
|
|
|
1066
|
|
|
|
|
|
|
# Contents of Mouse::Util |
1067
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Util; |
1068
|
2
|
|
|
2
|
|
10
|
use Scalar::Random::PP::OO::Exporter; # enables strict and warnings |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
12
|
|
1069
|
2
|
|
|
2
|
|
9
|
no warnings 'once'; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
173
|
|
1070
|
|
|
|
|
|
|
|
1071
|
|
|
|
|
|
|
# must be here because it will be refered by other modules loaded |
1072
|
|
|
|
|
|
|
sub get_linear_isa($;$); ## no critic |
1073
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
# must be here because it will called in Scalar::Random::PP::OO::Exporter |
1075
|
|
|
|
|
|
|
sub install_subroutines { |
1076
|
58
|
|
|
58
|
0
|
76
|
my $into = shift; |
1077
|
|
|
|
|
|
|
|
1078
|
58
|
|
|
|
|
194
|
while(my($name, $code) = splice @_, 0, 2){ |
1079
|
2
|
|
|
2
|
|
9
|
no strict 'refs'; |
|
2
|
|
|
|
|
19
|
|
|
2
|
|
|
|
|
59
|
|
1080
|
2
|
|
|
2
|
|
10
|
no warnings 'once', 'redefine'; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
65
|
|
1081
|
2
|
|
|
2
|
|
7
|
use warnings FATAL => 'uninitialized'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
581
|
|
1082
|
168
|
|
|
|
|
158
|
*{$into . '::' . $name} = \&{$code}; |
|
168
|
|
|
|
|
1174
|
|
|
168
|
|
|
|
|
231
|
|
1083
|
|
|
|
|
|
|
} |
1084
|
58
|
|
|
|
|
110
|
return; |
1085
|
|
|
|
|
|
|
} |
1086
|
|
|
|
|
|
|
|
1087
|
|
|
|
|
|
|
BEGIN{ |
1088
|
|
|
|
|
|
|
# This is used in Scalar::Random::PP::OO::PurePerl |
1089
|
2
|
|
|
2
|
|
16
|
Scalar::Random::PP::OO::Exporter->setup_import_methods( |
1090
|
|
|
|
|
|
|
as_is => [qw( |
1091
|
|
|
|
|
|
|
find_meta |
1092
|
|
|
|
|
|
|
does_role |
1093
|
|
|
|
|
|
|
resolve_metaclass_alias |
1094
|
|
|
|
|
|
|
apply_all_roles |
1095
|
|
|
|
|
|
|
english_list |
1096
|
|
|
|
|
|
|
|
1097
|
|
|
|
|
|
|
load_class |
1098
|
|
|
|
|
|
|
is_class_loaded |
1099
|
|
|
|
|
|
|
|
1100
|
|
|
|
|
|
|
get_linear_isa |
1101
|
|
|
|
|
|
|
get_code_info |
1102
|
|
|
|
|
|
|
|
1103
|
|
|
|
|
|
|
get_code_package |
1104
|
|
|
|
|
|
|
get_code_ref |
1105
|
|
|
|
|
|
|
|
1106
|
|
|
|
|
|
|
not_supported |
1107
|
|
|
|
|
|
|
|
1108
|
|
|
|
|
|
|
does meta dump |
1109
|
|
|
|
|
|
|
)], |
1110
|
|
|
|
|
|
|
groups => { |
1111
|
|
|
|
|
|
|
default => [], # export no functions by default |
1112
|
|
|
|
|
|
|
|
1113
|
|
|
|
|
|
|
# The ':meta' group is 'use metaclass' for Mousse |
1114
|
|
|
|
|
|
|
meta => [qw(does meta dump)], |
1115
|
|
|
|
|
|
|
}, |
1116
|
|
|
|
|
|
|
); |
1117
|
|
|
|
|
|
|
|
1118
|
2
|
|
|
|
|
5
|
our $VERSION = '0.70'; |
1119
|
|
|
|
|
|
|
|
1120
|
2
|
|
33
|
|
|
12
|
my $xs = !(defined(&is_valid_class_name) || $ENV{MOUSE_PUREPERL} || $ENV{PERL_ONLY}); |
1121
|
|
|
|
|
|
|
|
1122
|
|
|
|
|
|
|
# Because Scalar::Random::PP::OO::Util is loaded first in all the Scalar::Random::PP::OO sub-modules, |
1123
|
|
|
|
|
|
|
# XSLoader must be placed here, not in Scalar/Random/PP/OO.pm. |
1124
|
2
|
50
|
|
|
|
7
|
if($xs){ |
1125
|
|
|
|
|
|
|
# XXX: XSLoader tries to get the object path from caller's file name |
1126
|
|
|
|
|
|
|
# $hack_mouse_file fools its mechanism |
1127
|
0
|
|
|
|
|
0
|
(my $hack_mouse_file = __FILE__) =~ s/.Util//; # .../Scalar/Random/PP/OO/Util.pm -> .../Scalar/Random/PP/OO.pm |
1128
|
0
|
|
0
|
|
|
0
|
$xs = eval sprintf("#line %d %s\n", __LINE__, $hack_mouse_file) . q{ |
1129
|
|
|
|
|
|
|
local $^W = 0; # workaround 'redefine' warning to &install_subroutines |
1130
|
|
|
|
|
|
|
require XSLoader; |
1131
|
|
|
|
|
|
|
XSLoader::load('Scalar::Random::PP::OO', $VERSION); |
1132
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Util->import({ into => 'Scalar::Random::PP::OO::Meta::Method::Constructor::XS' }, ':meta'); |
1133
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Util->import({ into => 'Scalar::Random::PP::OO::Meta::Method::Destructor::XS' }, ':meta'); |
1134
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Util->import({ into => 'Scalar::Random::PP::OO::Meta::Method::Accessor::XS' }, ':meta'); |
1135
|
|
|
|
|
|
|
return 1; |
1136
|
|
|
|
|
|
|
} || 0; |
1137
|
|
|
|
|
|
|
#warn $@ if $@; |
1138
|
|
|
|
|
|
|
} |
1139
|
|
|
|
|
|
|
|
1140
|
2
|
50
|
|
|
|
7
|
if(!$xs){ |
1141
|
2
|
|
|
|
|
12
|
require 'Scalar/Random/PP/OO/PurePerl.pm'; # we don't want to create its namespace |
1142
|
|
|
|
|
|
|
} |
1143
|
|
|
|
|
|
|
|
1144
|
2
|
|
|
|
|
69
|
*MOUSE_XS = sub(){ $xs }; |
|
0
|
|
|
|
|
0
|
|
1145
|
|
|
|
|
|
|
} |
1146
|
|
|
|
|
|
|
|
1147
|
2
|
|
|
2
|
|
10
|
use Carp (); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
38
|
|
1148
|
2
|
|
|
2
|
|
9
|
use Scalar::Util (); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
750
|
|
1149
|
|
|
|
|
|
|
|
1150
|
|
|
|
|
|
|
# aliases as public APIs |
1151
|
|
|
|
|
|
|
# it must be 'require', not 'use', because Scalar::Random::PP::OO::Meta::Module depends on Scalar::Random::PP::OO::Util |
1152
|
|
|
|
|
|
|
require Scalar::Random::PP::OO::Meta::Module; # for the entities of metaclass cache utilities |
1153
|
|
|
|
|
|
|
|
1154
|
|
|
|
|
|
|
# aliases |
1155
|
|
|
|
|
|
|
{ |
1156
|
|
|
|
|
|
|
*class_of = \&Scalar::Random::PP::OO::Meta::Module::_class_of; |
1157
|
|
|
|
|
|
|
*get_metaclass_by_name = \&Scalar::Random::PP::OO::Meta::Module::_get_metaclass_by_name; |
1158
|
|
|
|
|
|
|
*get_all_metaclass_instances = \&Scalar::Random::PP::OO::Meta::Module::_get_all_metaclass_instances; |
1159
|
|
|
|
|
|
|
*get_all_metaclass_names = \&Scalar::Random::PP::OO::Meta::Module::_get_all_metaclass_names; |
1160
|
|
|
|
|
|
|
|
1161
|
|
|
|
|
|
|
*Scalar::Random::PP::OO::load_class = \&load_class; |
1162
|
|
|
|
|
|
|
*Scalar::Random::PP::OO::is_class_loaded = \&is_class_loaded; |
1163
|
|
|
|
|
|
|
|
1164
|
|
|
|
|
|
|
# is-a predicates |
1165
|
|
|
|
|
|
|
#generate_isa_predicate_for('Scalar::Random::PP::OO::Meta::TypeConstraint' => 'is_a_type_constraint'); |
1166
|
|
|
|
|
|
|
#generate_isa_predicate_for('Scalar::Random::PP::OO::Meta::Class' => 'is_a_metaclass'); |
1167
|
|
|
|
|
|
|
#generate_isa_predicate_for('Scalar::Random::PP::OO::Meta::Role' => 'is_a_metarole'); |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
# duck type predicates |
1170
|
|
|
|
|
|
|
generate_can_predicate_for(['_compiled_type_constraint'] => 'is_a_type_constraint'); |
1171
|
|
|
|
|
|
|
generate_can_predicate_for(['create_anon_class'] => 'is_a_metaclass'); |
1172
|
|
|
|
|
|
|
generate_can_predicate_for(['create_anon_role'] => 'is_a_metarole'); |
1173
|
|
|
|
|
|
|
} |
1174
|
|
|
|
|
|
|
|
1175
|
|
|
|
|
|
|
our $in_global_destruction = 0; |
1176
|
2
|
|
|
2
|
|
14
|
END{ $in_global_destruction = 1 } |
1177
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
# Moose::Util compatible utilities |
1179
|
|
|
|
|
|
|
|
1180
|
|
|
|
|
|
|
sub find_meta{ |
1181
|
0
|
|
|
0
|
0
|
0
|
return class_of( $_[0] ); |
1182
|
|
|
|
|
|
|
} |
1183
|
|
|
|
|
|
|
|
1184
|
|
|
|
|
|
|
sub does_role{ |
1185
|
0
|
|
|
0
|
0
|
0
|
my ($class_or_obj, $role_name) = @_; |
1186
|
|
|
|
|
|
|
|
1187
|
0
|
|
|
|
|
0
|
my $meta = class_of($class_or_obj); |
1188
|
|
|
|
|
|
|
|
1189
|
0
|
0
|
0
|
|
|
0
|
(defined $role_name) |
1190
|
|
|
|
|
|
|
|| ($meta || 'Scalar::Random::PP::OO::Meta::Class')->throw_error("You must supply a role name to does()"); |
1191
|
|
|
|
|
|
|
|
1192
|
0
|
|
0
|
|
|
0
|
return defined($meta) && $meta->does_role($role_name); |
1193
|
|
|
|
|
|
|
} |
1194
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
BEGIN { |
1196
|
2
|
|
|
2
|
|
4
|
my $get_linear_isa; |
1197
|
2
|
50
|
|
|
|
15
|
if ($] >= 5.009_005) { |
1198
|
2
|
|
|
|
|
1958
|
require mro; |
1199
|
2
|
|
|
|
|
1402
|
$get_linear_isa = \&mro::get_linear_isa; |
1200
|
|
|
|
|
|
|
} else { |
1201
|
|
|
|
|
|
|
# this code is based on MRO::Compat::__get_linear_isa |
1202
|
0
|
|
|
|
|
0
|
my $_get_linear_isa_dfs; # this recurses so it isn't pretty |
1203
|
|
|
|
|
|
|
$_get_linear_isa_dfs = sub { |
1204
|
0
|
|
|
|
|
0
|
my($classname) = @_; |
1205
|
|
|
|
|
|
|
|
1206
|
0
|
|
|
|
|
0
|
my @lin = ($classname); |
1207
|
0
|
|
|
|
|
0
|
my %stored; |
1208
|
|
|
|
|
|
|
|
1209
|
2
|
|
|
2
|
|
11
|
no strict 'refs'; |
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
479
|
|
1210
|
0
|
|
|
|
|
0
|
foreach my $parent (@{"$classname\::ISA"}) { |
|
0
|
|
|
|
|
0
|
|
1211
|
0
|
|
|
|
|
0
|
foreach my $p(@{ $_get_linear_isa_dfs->($parent) }) { |
|
0
|
|
|
|
|
0
|
|
1212
|
0
|
0
|
|
|
|
0
|
next if exists $stored{$p}; |
1213
|
0
|
|
|
|
|
0
|
push(@lin, $p); |
1214
|
0
|
|
|
|
|
0
|
$stored{$p} = 1; |
1215
|
|
|
|
|
|
|
} |
1216
|
|
|
|
|
|
|
} |
1217
|
0
|
|
|
|
|
0
|
return \@lin; |
1218
|
0
|
|
|
|
|
0
|
}; |
1219
|
|
|
|
|
|
|
|
1220
|
|
|
|
|
|
|
{ |
1221
|
0
|
|
|
|
|
0
|
package # hide from PAUSE |
1222
|
|
|
|
|
|
|
Class::C3; |
1223
|
0
|
|
|
|
|
0
|
our %MRO; # avoid 'once' warnings |
1224
|
|
|
|
|
|
|
} |
1225
|
|
|
|
|
|
|
|
1226
|
|
|
|
|
|
|
# MRO::Compat::__get_linear_isa has no prototype, so |
1227
|
|
|
|
|
|
|
# we define a prototyped version for compatibility with core's |
1228
|
|
|
|
|
|
|
# See also MRO::Compat::__get_linear_isa. |
1229
|
|
|
|
|
|
|
$get_linear_isa = sub ($;$){ |
1230
|
0
|
|
|
|
|
0
|
my($classname, $type) = @_; |
1231
|
|
|
|
|
|
|
|
1232
|
0
|
0
|
|
|
|
0
|
if(!defined $type){ |
1233
|
0
|
0
|
|
|
|
0
|
$type = exists $Class::C3::MRO{$classname} ? 'c3' : 'dfs'; |
1234
|
|
|
|
|
|
|
} |
1235
|
0
|
0
|
|
|
|
0
|
if($type eq 'c3'){ |
1236
|
0
|
|
|
|
|
0
|
require Class::C3; |
1237
|
0
|
|
|
|
|
0
|
return [Class::C3::calculateMRO($classname)]; |
1238
|
|
|
|
|
|
|
} |
1239
|
|
|
|
|
|
|
else{ |
1240
|
0
|
|
|
|
|
0
|
return $_get_linear_isa_dfs->($classname); |
1241
|
|
|
|
|
|
|
} |
1242
|
0
|
|
|
|
|
0
|
}; |
1243
|
|
|
|
|
|
|
} |
1244
|
|
|
|
|
|
|
|
1245
|
2
|
|
|
|
|
1932
|
*get_linear_isa = $get_linear_isa; |
1246
|
|
|
|
|
|
|
} |
1247
|
|
|
|
|
|
|
|
1248
|
|
|
|
|
|
|
|
1249
|
|
|
|
|
|
|
# taken from Scalar::Random::PP::OO::Util (0.90) |
1250
|
|
|
|
|
|
|
{ |
1251
|
|
|
|
|
|
|
my %cache; |
1252
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
sub resolve_metaclass_alias { |
1254
|
0
|
|
|
0
|
0
|
0
|
my ( $type, $metaclass_name, %options ) = @_; |
1255
|
|
|
|
|
|
|
|
1256
|
0
|
0
|
|
|
|
0
|
my $cache_key = $type . q{ } . ( $options{trait} ? '-Trait' : '' ); |
1257
|
|
|
|
|
|
|
|
1258
|
0
|
|
0
|
|
|
0
|
return $cache{$cache_key}{$metaclass_name} ||= do{ |
1259
|
|
|
|
|
|
|
|
1260
|
0
|
0
|
|
|
|
0
|
my $possible_full_name = join '::', |
1261
|
|
|
|
|
|
|
'Scalar::Random::PP::OO::Meta', $type, 'Custom', ($options{trait} ? 'Trait' : ()), $metaclass_name |
1262
|
|
|
|
|
|
|
; |
1263
|
|
|
|
|
|
|
|
1264
|
0
|
|
|
|
|
0
|
my $loaded_class = load_first_existing_class( |
1265
|
|
|
|
|
|
|
$possible_full_name, |
1266
|
|
|
|
|
|
|
$metaclass_name |
1267
|
|
|
|
|
|
|
); |
1268
|
|
|
|
|
|
|
|
1269
|
0
|
0
|
|
|
|
0
|
$loaded_class->can('register_implementation') |
1270
|
|
|
|
|
|
|
? $loaded_class->register_implementation |
1271
|
|
|
|
|
|
|
: $loaded_class; |
1272
|
|
|
|
|
|
|
}; |
1273
|
|
|
|
|
|
|
} |
1274
|
|
|
|
|
|
|
} |
1275
|
|
|
|
|
|
|
|
1276
|
|
|
|
|
|
|
# Utilities from Class::MOP |
1277
|
|
|
|
|
|
|
|
1278
|
|
|
|
|
|
|
sub get_code_info; |
1279
|
|
|
|
|
|
|
sub get_code_package; |
1280
|
|
|
|
|
|
|
|
1281
|
|
|
|
|
|
|
sub is_valid_class_name; |
1282
|
|
|
|
|
|
|
|
1283
|
|
|
|
|
|
|
# taken from Class/MOP.pm |
1284
|
|
|
|
|
|
|
sub load_first_existing_class { |
1285
|
0
|
0
|
|
0
|
0
|
0
|
my @classes = @_ |
1286
|
|
|
|
|
|
|
or return; |
1287
|
|
|
|
|
|
|
|
1288
|
0
|
|
|
|
|
0
|
my %exceptions; |
1289
|
0
|
|
|
|
|
0
|
for my $class (@classes) { |
1290
|
0
|
|
|
|
|
0
|
my $e = _try_load_one_class($class); |
1291
|
|
|
|
|
|
|
|
1292
|
0
|
0
|
|
|
|
0
|
if ($e) { |
1293
|
0
|
|
|
|
|
0
|
$exceptions{$class} = $e; |
1294
|
|
|
|
|
|
|
} |
1295
|
|
|
|
|
|
|
else { |
1296
|
0
|
|
|
|
|
0
|
return $class; |
1297
|
|
|
|
|
|
|
} |
1298
|
|
|
|
|
|
|
} |
1299
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
# not found |
1301
|
0
|
|
|
|
|
0
|
Carp::confess join( |
1302
|
|
|
|
|
|
|
"\n", |
1303
|
|
|
|
|
|
|
map { |
1304
|
0
|
|
|
|
|
0
|
sprintf( "Could not load class (%s) because : %s", |
1305
|
|
|
|
|
|
|
$_, $exceptions{$_} ) |
1306
|
|
|
|
|
|
|
} @classes |
1307
|
|
|
|
|
|
|
); |
1308
|
|
|
|
|
|
|
} |
1309
|
|
|
|
|
|
|
|
1310
|
|
|
|
|
|
|
# taken from Class/MOP.pm |
1311
|
|
|
|
|
|
|
sub _try_load_one_class { |
1312
|
2
|
|
|
2
|
|
4
|
my $class = shift; |
1313
|
|
|
|
|
|
|
|
1314
|
2
|
50
|
|
|
|
6
|
unless ( is_valid_class_name($class) ) { |
1315
|
0
|
0
|
|
|
|
0
|
my $display = defined($class) ? $class : 'undef'; |
1316
|
0
|
|
|
|
|
0
|
Carp::confess "Invalid class name ($display)"; |
1317
|
|
|
|
|
|
|
} |
1318
|
|
|
|
|
|
|
|
1319
|
2
|
50
|
|
|
|
9
|
return '' if is_class_loaded($class); |
1320
|
|
|
|
|
|
|
|
1321
|
0
|
|
|
|
|
0
|
$class =~ s{::}{/}g; |
1322
|
0
|
|
|
|
|
0
|
$class .= '.pm'; |
1323
|
|
|
|
|
|
|
|
1324
|
0
|
|
|
|
|
0
|
return do { |
1325
|
0
|
|
|
|
|
0
|
local $@; |
1326
|
0
|
|
|
|
|
0
|
eval { require $class }; |
|
0
|
|
|
|
|
0
|
|
1327
|
0
|
|
|
|
|
0
|
$@; |
1328
|
|
|
|
|
|
|
}; |
1329
|
|
|
|
|
|
|
} |
1330
|
|
|
|
|
|
|
|
1331
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
sub load_class { |
1333
|
2
|
|
|
2
|
0
|
3
|
my $class = shift; |
1334
|
2
|
|
|
|
|
7
|
my $e = _try_load_one_class($class); |
1335
|
2
|
50
|
|
|
|
8
|
Carp::confess "Could not load class ($class) because : $e" if $e; |
1336
|
|
|
|
|
|
|
|
1337
|
2
|
|
|
|
|
3
|
return $class; |
1338
|
|
|
|
|
|
|
} |
1339
|
|
|
|
|
|
|
|
1340
|
|
|
|
|
|
|
sub is_class_loaded; |
1341
|
|
|
|
|
|
|
|
1342
|
|
|
|
|
|
|
sub apply_all_roles { |
1343
|
0
|
0
|
|
0
|
0
|
0
|
my $consumer = Scalar::Util::blessed($_[0]) |
1344
|
|
|
|
|
|
|
? shift # instance |
1345
|
|
|
|
|
|
|
: Scalar::Random::PP::OO::Meta::Class->initialize(shift); # class or role name |
1346
|
|
|
|
|
|
|
|
1347
|
0
|
|
|
|
|
0
|
my @roles; |
1348
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
# Basis of Data::OptList |
1350
|
0
|
|
|
|
|
0
|
my $max = scalar(@_); |
1351
|
0
|
|
|
|
|
0
|
for (my $i = 0; $i < $max ; $i++) { |
1352
|
0
|
0
|
0
|
|
|
0
|
if ($i + 1 < $max && ref($_[$i + 1])) { |
1353
|
0
|
|
|
|
|
0
|
push @roles, [ $_[$i] => $_[++$i] ]; |
1354
|
|
|
|
|
|
|
} else { |
1355
|
0
|
|
|
|
|
0
|
push @roles, [ $_[$i] => undef ]; |
1356
|
|
|
|
|
|
|
} |
1357
|
0
|
|
|
|
|
0
|
my $role_name = $roles[-1][0]; |
1358
|
0
|
|
|
|
|
0
|
load_class($role_name); |
1359
|
|
|
|
|
|
|
|
1360
|
0
|
0
|
|
|
|
0
|
is_a_metarole( get_metaclass_by_name($role_name) ) |
1361
|
|
|
|
|
|
|
|| $consumer->meta->throw_error("You can only consume roles, $role_name is not a Scalar::Random::PP::OO role"); |
1362
|
|
|
|
|
|
|
} |
1363
|
|
|
|
|
|
|
|
1364
|
0
|
0
|
|
|
|
0
|
if ( scalar @roles == 1 ) { |
1365
|
0
|
|
|
|
|
0
|
my ( $role_name, $params ) = @{ $roles[0] }; |
|
0
|
|
|
|
|
0
|
|
1366
|
0
|
0
|
|
|
|
0
|
get_metaclass_by_name($role_name)->apply( $consumer, defined $params ? $params : () ); |
1367
|
|
|
|
|
|
|
} |
1368
|
|
|
|
|
|
|
else { |
1369
|
0
|
|
|
|
|
0
|
Scalar::Random::PP::OO::Meta::Role->combine(@roles)->apply($consumer); |
1370
|
|
|
|
|
|
|
} |
1371
|
0
|
|
|
|
|
0
|
return; |
1372
|
|
|
|
|
|
|
} |
1373
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
# taken from Moose::Util 0.90 |
1375
|
|
|
|
|
|
|
sub english_list { |
1376
|
0
|
0
|
|
0
|
0
|
0
|
return $_[0] if @_ == 1; |
1377
|
|
|
|
|
|
|
|
1378
|
0
|
|
|
|
|
0
|
my @items = sort @_; |
1379
|
|
|
|
|
|
|
|
1380
|
0
|
0
|
|
|
|
0
|
return "$items[0] and $items[1]" if @items == 2; |
1381
|
|
|
|
|
|
|
|
1382
|
0
|
|
|
|
|
0
|
my $tail = pop @items; |
1383
|
|
|
|
|
|
|
|
1384
|
0
|
|
|
|
|
0
|
return join q{, }, @items, "and $tail"; |
1385
|
|
|
|
|
|
|
} |
1386
|
|
|
|
|
|
|
|
1387
|
|
|
|
|
|
|
sub quoted_english_list { |
1388
|
0
|
|
|
0
|
0
|
0
|
return english_list(map { qq{'$_'} } @_); |
|
0
|
|
|
|
|
0
|
|
1389
|
|
|
|
|
|
|
} |
1390
|
|
|
|
|
|
|
|
1391
|
|
|
|
|
|
|
# common utilities |
1392
|
|
|
|
|
|
|
|
1393
|
|
|
|
|
|
|
sub not_supported{ |
1394
|
0
|
|
|
0
|
0
|
0
|
my($feature) = @_; |
1395
|
|
|
|
|
|
|
|
1396
|
0
|
|
0
|
|
|
0
|
$feature ||= ( caller(1) )[3]; # subroutine name |
1397
|
|
|
|
|
|
|
|
1398
|
0
|
|
|
|
|
0
|
local $Carp::CarpLevel = $Carp::CarpLevel + 1; |
1399
|
0
|
|
|
|
|
0
|
Carp::confess("Scalar::Random::PP::OO does not currently support $feature"); |
1400
|
|
|
|
|
|
|
} |
1401
|
|
|
|
|
|
|
|
1402
|
|
|
|
|
|
|
# general meta() method |
1403
|
|
|
|
|
|
|
sub meta :method{ |
1404
|
0
|
|
0
|
0
|
0
|
0
|
return Scalar::Random::PP::OO::Meta::Class->initialize(ref($_[0]) || $_[0]); |
1405
|
|
|
|
|
|
|
} |
1406
|
|
|
|
|
|
|
|
1407
|
|
|
|
|
|
|
# general dump() method |
1408
|
|
|
|
|
|
|
sub dump :method { |
1409
|
0
|
|
|
0
|
0
|
0
|
my($self, $maxdepth) = @_; |
1410
|
|
|
|
|
|
|
|
1411
|
0
|
|
|
|
|
0
|
require 'Data/Dumper.pm'; # we don't want to create its namespace |
1412
|
0
|
|
|
|
|
0
|
my $dd = Data::Dumper->new([$self]); |
1413
|
0
|
0
|
|
|
|
0
|
$dd->Maxdepth(defined($maxdepth) ? $maxdepth : 3); |
1414
|
0
|
|
|
|
|
0
|
$dd->Indent(1); |
1415
|
0
|
|
|
|
|
0
|
return $dd->Dump(); |
1416
|
|
|
|
|
|
|
} |
1417
|
|
|
|
|
|
|
|
1418
|
|
|
|
|
|
|
# general does() method |
1419
|
|
|
|
|
|
|
sub does :method { |
1420
|
0
|
|
|
0
|
0
|
0
|
goto &does_role; |
1421
|
|
|
|
|
|
|
} |
1422
|
|
|
|
|
|
|
|
1423
|
|
|
|
|
|
|
# Contents of Mouse::Meta::TypeConstraint |
1424
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::TypeConstraint; |
1425
|
2
|
|
|
2
|
|
14
|
use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
12
|
|
1426
|
2
|
|
|
2
|
|
9
|
use Scalar::Util (); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
263
|
|
1427
|
|
|
|
|
|
|
|
1428
|
|
|
|
|
|
|
use overload |
1429
|
|
|
|
|
|
|
'bool' => sub (){ 1 }, # always true |
1430
|
0
|
|
|
0
|
|
0
|
'""' => sub { $_[0]->name }, # stringify to tc name |
1431
|
0
|
|
|
0
|
|
0
|
'0+' => sub { Scalar::Util::refaddr($_[0]) }, |
1432
|
|
|
|
|
|
|
'|' => sub { # or-combination |
1433
|
0
|
|
|
0
|
|
0
|
require Scalar::Random::PP::OO::Util::TypeConstraints; |
1434
|
0
|
|
|
|
|
0
|
return Scalar::Random::PP::OO::Util::TypeConstraints::find_or_parse_type_constraint( |
1435
|
|
|
|
|
|
|
"$_[0] | $_[1]", |
1436
|
|
|
|
|
|
|
); |
1437
|
|
|
|
|
|
|
}, |
1438
|
|
|
|
|
|
|
|
1439
|
2
|
|
|
2
|
|
3001
|
fallback => 1; |
|
2
|
|
|
|
|
2234
|
|
|
2
|
|
|
|
|
28
|
|
1440
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
sub new { |
1442
|
44
|
|
|
44
|
0
|
45
|
my $class = shift; |
1443
|
44
|
50
|
|
|
|
150
|
my %args = @_ == 1 ? %{$_[0]} : @_; |
|
0
|
|
|
|
|
0
|
|
1444
|
|
|
|
|
|
|
|
1445
|
44
|
50
|
|
|
|
91
|
$args{name} = '__ANON__' if !defined $args{name}; |
1446
|
|
|
|
|
|
|
|
1447
|
44
|
|
|
|
|
59
|
my $check = delete $args{optimized}; |
1448
|
|
|
|
|
|
|
|
1449
|
44
|
100
|
|
|
|
75
|
if($check){ |
1450
|
38
|
|
|
|
|
48
|
$args{hand_optimized_type_constraint} = $check; |
1451
|
38
|
|
|
|
|
45
|
$args{compiled_type_constraint} = $check; |
1452
|
|
|
|
|
|
|
} |
1453
|
|
|
|
|
|
|
|
1454
|
44
|
|
|
|
|
44
|
$check = $args{constraint}; |
1455
|
|
|
|
|
|
|
|
1456
|
44
|
50
|
33
|
|
|
92
|
if(defined($check) && ref($check) ne 'CODE'){ |
1457
|
0
|
|
|
|
|
0
|
$class->throw_error("Constraint for $args{name} is not a CODE reference"); |
1458
|
|
|
|
|
|
|
} |
1459
|
|
|
|
|
|
|
|
1460
|
44
|
|
|
|
|
105
|
my $self = bless \%args, $class; |
1461
|
44
|
100
|
|
|
|
161
|
$self->compile_type_constraint() if !$self->{hand_optimized_type_constraint}; |
1462
|
|
|
|
|
|
|
|
1463
|
44
|
50
|
|
|
|
83
|
$self->_compile_union_type_coercion() if $self->{type_constraints}; |
1464
|
44
|
|
|
|
|
158
|
return $self; |
1465
|
|
|
|
|
|
|
} |
1466
|
|
|
|
|
|
|
|
1467
|
|
|
|
|
|
|
sub create_child_type{ |
1468
|
2
|
|
|
2
|
0
|
5
|
my $self = shift; |
1469
|
2
|
|
|
|
|
23
|
return ref($self)->new( |
1470
|
|
|
|
|
|
|
# a child inherits its parent's attributes |
1471
|
2
|
|
|
|
|
6
|
%{$self}, |
1472
|
|
|
|
|
|
|
|
1473
|
|
|
|
|
|
|
# but does not inherit 'compiled_type_constraint' and 'hand_optimized_type_constraint' |
1474
|
|
|
|
|
|
|
compiled_type_constraint => undef, |
1475
|
|
|
|
|
|
|
hand_optimized_type_constraint => undef, |
1476
|
|
|
|
|
|
|
|
1477
|
|
|
|
|
|
|
# and is given child-specific args, of course. |
1478
|
|
|
|
|
|
|
@_, |
1479
|
|
|
|
|
|
|
|
1480
|
|
|
|
|
|
|
# and its parent |
1481
|
|
|
|
|
|
|
parent => $self, |
1482
|
|
|
|
|
|
|
); |
1483
|
|
|
|
|
|
|
} |
1484
|
|
|
|
|
|
|
|
1485
|
|
|
|
|
|
|
sub name; |
1486
|
|
|
|
|
|
|
sub parent; |
1487
|
|
|
|
|
|
|
sub message; |
1488
|
|
|
|
|
|
|
sub has_coercion; |
1489
|
|
|
|
|
|
|
|
1490
|
|
|
|
|
|
|
sub check; |
1491
|
|
|
|
|
|
|
|
1492
|
|
|
|
|
|
|
sub type_parameter; |
1493
|
|
|
|
|
|
|
sub __is_parameterized; |
1494
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
sub _compiled_type_constraint; |
1496
|
|
|
|
|
|
|
sub _compiled_type_coercion; |
1497
|
|
|
|
|
|
|
|
1498
|
|
|
|
|
|
|
sub compile_type_constraint; |
1499
|
|
|
|
|
|
|
|
1500
|
|
|
|
|
|
|
|
1501
|
|
|
|
|
|
|
sub _add_type_coercions{ |
1502
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
1503
|
|
|
|
|
|
|
|
1504
|
0
|
|
0
|
|
|
0
|
my $coercions = ($self->{coercion_map} ||= []); |
1505
|
0
|
|
|
|
|
0
|
my %has = map{ $_->[0] => undef } @{$coercions}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1506
|
|
|
|
|
|
|
|
1507
|
0
|
|
|
|
|
0
|
for(my $i = 0; $i < @_; $i++){ |
1508
|
0
|
|
|
|
|
0
|
my $from = $_[ $i]; |
1509
|
0
|
|
|
|
|
0
|
my $action = $_[++$i]; |
1510
|
|
|
|
|
|
|
|
1511
|
0
|
0
|
|
|
|
0
|
if(exists $has{$from}){ |
1512
|
0
|
|
|
|
|
0
|
$self->throw_error("A coercion action already exists for '$from'"); |
1513
|
|
|
|
|
|
|
} |
1514
|
|
|
|
|
|
|
|
1515
|
0
|
0
|
|
|
|
0
|
my $type = Scalar::Random::PP::OO::Util::TypeConstraints::find_or_parse_type_constraint($from) |
1516
|
|
|
|
|
|
|
or $self->throw_error("Could not find the type constraint ($from) to coerce from"); |
1517
|
|
|
|
|
|
|
|
1518
|
0
|
|
|
|
|
0
|
push @{$coercions}, [ $type => $action ]; |
|
0
|
|
|
|
|
0
|
|
1519
|
|
|
|
|
|
|
} |
1520
|
|
|
|
|
|
|
|
1521
|
|
|
|
|
|
|
# compile |
1522
|
0
|
0
|
|
|
|
0
|
if(exists $self->{type_constraints}){ # union type |
1523
|
0
|
|
|
|
|
0
|
$self->throw_error("Cannot add additional type coercions to Union types"); |
1524
|
|
|
|
|
|
|
} |
1525
|
|
|
|
|
|
|
else{ |
1526
|
0
|
|
|
|
|
0
|
$self->_compile_type_coercion(); |
1527
|
|
|
|
|
|
|
} |
1528
|
0
|
|
|
|
|
0
|
return; |
1529
|
|
|
|
|
|
|
} |
1530
|
|
|
|
|
|
|
|
1531
|
|
|
|
|
|
|
sub _compile_type_coercion { |
1532
|
0
|
|
|
0
|
|
0
|
my($self) = @_; |
1533
|
|
|
|
|
|
|
|
1534
|
0
|
|
|
|
|
0
|
my @coercions = @{$self->{coercion_map}}; |
|
0
|
|
|
|
|
0
|
|
1535
|
|
|
|
|
|
|
|
1536
|
|
|
|
|
|
|
$self->{_compiled_type_coercion} = sub { |
1537
|
0
|
|
|
0
|
|
0
|
my($thing) = @_; |
1538
|
0
|
|
|
|
|
0
|
foreach my $pair (@coercions) { |
1539
|
|
|
|
|
|
|
#my ($constraint, $converter) = @$pair; |
1540
|
0
|
0
|
|
|
|
0
|
if ($pair->[0]->check($thing)) { |
1541
|
0
|
|
|
|
|
0
|
local $_ = $thing; |
1542
|
0
|
|
|
|
|
0
|
return $pair->[1]->($thing); |
1543
|
|
|
|
|
|
|
} |
1544
|
|
|
|
|
|
|
} |
1545
|
0
|
|
|
|
|
0
|
return $thing; |
1546
|
0
|
|
|
|
|
0
|
}; |
1547
|
0
|
|
|
|
|
0
|
return; |
1548
|
|
|
|
|
|
|
} |
1549
|
|
|
|
|
|
|
|
1550
|
|
|
|
|
|
|
sub _compile_union_type_coercion { |
1551
|
0
|
|
|
0
|
|
0
|
my($self) = @_; |
1552
|
|
|
|
|
|
|
|
1553
|
0
|
|
|
|
|
0
|
my @coercions; |
1554
|
0
|
|
|
|
|
0
|
foreach my $type(@{$self->{type_constraints}}){ |
|
0
|
|
|
|
|
0
|
|
1555
|
0
|
0
|
|
|
|
0
|
if($type->has_coercion){ |
1556
|
0
|
|
|
|
|
0
|
push @coercions, $type; |
1557
|
|
|
|
|
|
|
} |
1558
|
|
|
|
|
|
|
} |
1559
|
0
|
0
|
|
|
|
0
|
if(@coercions){ |
1560
|
|
|
|
|
|
|
$self->{_compiled_type_coercion} = sub { |
1561
|
0
|
|
|
0
|
|
0
|
my($thing) = @_; |
1562
|
0
|
|
|
|
|
0
|
foreach my $type(@coercions){ |
1563
|
0
|
|
|
|
|
0
|
my $value = $type->coerce($thing); |
1564
|
0
|
0
|
|
|
|
0
|
return $value if $self->check($value); |
1565
|
|
|
|
|
|
|
} |
1566
|
0
|
|
|
|
|
0
|
return $thing; |
1567
|
0
|
|
|
|
|
0
|
}; |
1568
|
|
|
|
|
|
|
} |
1569
|
0
|
|
|
|
|
0
|
return; |
1570
|
|
|
|
|
|
|
} |
1571
|
|
|
|
|
|
|
|
1572
|
|
|
|
|
|
|
sub coerce { |
1573
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
1574
|
|
|
|
|
|
|
|
1575
|
0
|
|
|
|
|
0
|
my $coercion = $self->_compiled_type_coercion; |
1576
|
0
|
0
|
|
|
|
0
|
if(!$coercion){ |
1577
|
0
|
|
|
|
|
0
|
$self->throw_error("Cannot coerce without a type coercion"); |
1578
|
|
|
|
|
|
|
} |
1579
|
|
|
|
|
|
|
|
1580
|
0
|
0
|
|
|
|
0
|
return $_[0] if $self->check(@_); |
1581
|
|
|
|
|
|
|
|
1582
|
0
|
|
|
|
|
0
|
return $coercion->(@_); |
1583
|
|
|
|
|
|
|
} |
1584
|
|
|
|
|
|
|
|
1585
|
|
|
|
|
|
|
sub get_message { |
1586
|
0
|
|
|
0
|
0
|
0
|
my ($self, $value) = @_; |
1587
|
0
|
0
|
|
|
|
0
|
if ( my $msg = $self->message ) { |
1588
|
0
|
|
|
|
|
0
|
local $_ = $value; |
1589
|
0
|
|
|
|
|
0
|
return $msg->($value); |
1590
|
|
|
|
|
|
|
} |
1591
|
|
|
|
|
|
|
else { |
1592
|
0
|
0
|
|
|
|
0
|
$value = ( defined $value ? overload::StrVal($value) : 'undef' ); |
1593
|
0
|
|
|
|
|
0
|
return "Validation failed for '$self' with value $value"; |
1594
|
|
|
|
|
|
|
} |
1595
|
|
|
|
|
|
|
} |
1596
|
|
|
|
|
|
|
|
1597
|
|
|
|
|
|
|
sub is_a_type_of{ |
1598
|
0
|
|
|
0
|
0
|
0
|
my($self, $other) = @_; |
1599
|
|
|
|
|
|
|
|
1600
|
|
|
|
|
|
|
# ->is_a_type_of('__ANON__') is always false |
1601
|
0
|
0
|
0
|
|
|
0
|
return 0 if !ref($other) && $other eq '__ANON__'; |
1602
|
|
|
|
|
|
|
|
1603
|
0
|
|
|
|
|
0
|
(my $other_name = $other) =~ s/\s+//g; |
1604
|
|
|
|
|
|
|
|
1605
|
0
|
0
|
|
|
|
0
|
return 1 if $self->name eq $other_name; |
1606
|
|
|
|
|
|
|
|
1607
|
0
|
0
|
|
|
|
0
|
if(exists $self->{type_constraints}){ # union |
1608
|
0
|
|
|
|
|
0
|
foreach my $type(@{$self->{type_constraints}}){ |
|
0
|
|
|
|
|
0
|
|
1609
|
0
|
0
|
|
|
|
0
|
return 1 if $type->name eq $other_name; |
1610
|
|
|
|
|
|
|
} |
1611
|
|
|
|
|
|
|
} |
1612
|
|
|
|
|
|
|
|
1613
|
0
|
|
|
|
|
0
|
for(my $parent = $self->parent; defined $parent; $parent = $parent->parent){ |
1614
|
0
|
0
|
|
|
|
0
|
return 1 if $parent->name eq $other_name; |
1615
|
|
|
|
|
|
|
} |
1616
|
|
|
|
|
|
|
|
1617
|
0
|
|
|
|
|
0
|
return 0; |
1618
|
|
|
|
|
|
|
} |
1619
|
|
|
|
|
|
|
|
1620
|
|
|
|
|
|
|
# See also Moose::Meta::TypeConstraint::Parameterizable |
1621
|
|
|
|
|
|
|
sub parameterize{ |
1622
|
0
|
|
|
0
|
0
|
0
|
my($self, $param, $name) = @_; |
1623
|
|
|
|
|
|
|
|
1624
|
0
|
0
|
|
|
|
0
|
if(!ref $param){ |
1625
|
0
|
|
|
|
|
0
|
require Scalar::Random::PP::OO::Util::TypeConstraints; |
1626
|
0
|
|
|
|
|
0
|
$param = Scalar::Random::PP::OO::Util::TypeConstraints::find_or_create_isa_type_constraint($param); |
1627
|
|
|
|
|
|
|
} |
1628
|
|
|
|
|
|
|
|
1629
|
0
|
|
0
|
|
|
0
|
$name ||= sprintf '%s[%s]', $self->name, $param->name; |
1630
|
|
|
|
|
|
|
|
1631
|
0
|
|
0
|
|
|
0
|
my $generator = $self->{constraint_generator} |
1632
|
|
|
|
|
|
|
|| $self->throw_error("The $name constraint cannot be used, because $param doesn't subtype from a parameterizable type"); |
1633
|
|
|
|
|
|
|
|
1634
|
0
|
|
|
|
|
0
|
return Scalar::Random::PP::OO::Meta::TypeConstraint->new( |
1635
|
|
|
|
|
|
|
name => $name, |
1636
|
|
|
|
|
|
|
parent => $self, |
1637
|
|
|
|
|
|
|
type_parameter => $param, |
1638
|
|
|
|
|
|
|
constraint => $generator->($param), # must be 'constraint', not 'optimized' |
1639
|
|
|
|
|
|
|
); |
1640
|
|
|
|
|
|
|
} |
1641
|
|
|
|
|
|
|
|
1642
|
|
|
|
|
|
|
sub assert_valid { |
1643
|
0
|
|
|
0
|
0
|
0
|
my ($self, $value) = @_; |
1644
|
|
|
|
|
|
|
|
1645
|
0
|
0
|
|
|
|
0
|
if(!$self->check($value)){ |
1646
|
0
|
|
|
|
|
0
|
$self->throw_error($self->get_message($value)); |
1647
|
|
|
|
|
|
|
} |
1648
|
0
|
|
|
|
|
0
|
return 1; |
1649
|
|
|
|
|
|
|
} |
1650
|
|
|
|
|
|
|
|
1651
|
|
|
|
|
|
|
sub throw_error { |
1652
|
0
|
|
|
0
|
0
|
0
|
require Scalar::Random::PP::OO::Meta::Module; |
1653
|
0
|
|
|
|
|
0
|
goto &Scalar::Random::PP::OO::Meta::Module::throw_error; |
1654
|
|
|
|
|
|
|
} |
1655
|
|
|
|
|
|
|
|
1656
|
|
|
|
|
|
|
# Contents of Mouse::Util::TypeConstraints |
1657
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Util::TypeConstraints; |
1658
|
2
|
|
|
2
|
|
2815
|
use Scalar::Random::PP::OO::Util qw(does_role not_supported); # enables strict and warnings |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
14
|
|
1659
|
|
|
|
|
|
|
|
1660
|
2
|
|
|
2
|
|
12
|
use Carp (); |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
58
|
|
1661
|
2
|
|
|
2
|
|
11
|
use Scalar::Util (); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
36
|
|
1662
|
|
|
|
|
|
|
|
1663
|
2
|
|
|
2
|
|
12
|
use Scalar::Random::PP::OO::Meta::TypeConstraint; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
71
|
|
1664
|
2
|
|
|
2
|
|
11
|
use Scalar::Random::PP::OO::Exporter; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
14
|
|
1665
|
|
|
|
|
|
|
|
1666
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Exporter->setup_import_methods( |
1667
|
|
|
|
|
|
|
as_is => [qw( |
1668
|
|
|
|
|
|
|
as where message optimize_as |
1669
|
|
|
|
|
|
|
from via |
1670
|
|
|
|
|
|
|
|
1671
|
|
|
|
|
|
|
type subtype class_type role_type duck_type |
1672
|
|
|
|
|
|
|
enum |
1673
|
|
|
|
|
|
|
coerce |
1674
|
|
|
|
|
|
|
|
1675
|
|
|
|
|
|
|
find_type_constraint |
1676
|
|
|
|
|
|
|
register_type_constraint |
1677
|
|
|
|
|
|
|
)], |
1678
|
|
|
|
|
|
|
); |
1679
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
our @CARP_NOT = qw(Scalar::Random::PP::OO::Meta::Attribute); |
1681
|
|
|
|
|
|
|
|
1682
|
|
|
|
|
|
|
my %TYPE; |
1683
|
|
|
|
|
|
|
|
1684
|
|
|
|
|
|
|
# The root type |
1685
|
|
|
|
|
|
|
$TYPE{Any} = Scalar::Random::PP::OO::Meta::TypeConstraint->new( |
1686
|
|
|
|
|
|
|
name => 'Any', |
1687
|
|
|
|
|
|
|
); |
1688
|
|
|
|
|
|
|
|
1689
|
|
|
|
|
|
|
my @builtins = ( |
1690
|
|
|
|
|
|
|
# $name => $parent, $code, |
1691
|
|
|
|
|
|
|
|
1692
|
|
|
|
|
|
|
# the base type |
1693
|
|
|
|
|
|
|
Item => 'Any', undef, |
1694
|
|
|
|
|
|
|
|
1695
|
|
|
|
|
|
|
# the maybe[] type |
1696
|
|
|
|
|
|
|
Maybe => 'Item', undef, |
1697
|
|
|
|
|
|
|
|
1698
|
|
|
|
|
|
|
# value types |
1699
|
|
|
|
|
|
|
Undef => 'Item', \&Undef, |
1700
|
|
|
|
|
|
|
Defined => 'Item', \&Defined, |
1701
|
|
|
|
|
|
|
Bool => 'Item', \&Bool, |
1702
|
|
|
|
|
|
|
Value => 'Defined', \&Value, |
1703
|
|
|
|
|
|
|
Str => 'Value', \&Str, |
1704
|
|
|
|
|
|
|
Num => 'Str', \&Num, |
1705
|
|
|
|
|
|
|
Int => 'Num', \&Int, |
1706
|
|
|
|
|
|
|
|
1707
|
|
|
|
|
|
|
# ref types |
1708
|
|
|
|
|
|
|
Ref => 'Defined', \&Ref, |
1709
|
|
|
|
|
|
|
ScalarRef => 'Ref', \&ScalarRef, |
1710
|
|
|
|
|
|
|
ArrayRef => 'Ref', \&ArrayRef, |
1711
|
|
|
|
|
|
|
HashRef => 'Ref', \&HashRef, |
1712
|
|
|
|
|
|
|
CodeRef => 'Ref', \&CodeRef, |
1713
|
|
|
|
|
|
|
RegexpRef => 'Ref', \&RegexpRef, |
1714
|
|
|
|
|
|
|
GlobRef => 'Ref', \&GlobRef, |
1715
|
|
|
|
|
|
|
|
1716
|
|
|
|
|
|
|
# object types |
1717
|
|
|
|
|
|
|
FileHandle => 'GlobRef', \&FileHandle, |
1718
|
|
|
|
|
|
|
Object => 'Ref', \&Object, |
1719
|
|
|
|
|
|
|
|
1720
|
|
|
|
|
|
|
# special string types |
1721
|
|
|
|
|
|
|
ClassName => 'Str', \&ClassName, |
1722
|
|
|
|
|
|
|
RoleName => 'ClassName', \&RoleName, |
1723
|
|
|
|
|
|
|
); |
1724
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
|
1726
|
|
|
|
|
|
|
while (my ($name, $parent, $code) = splice @builtins, 0, 3) { |
1727
|
|
|
|
|
|
|
$TYPE{$name} = Scalar::Random::PP::OO::Meta::TypeConstraint->new( |
1728
|
|
|
|
|
|
|
name => $name, |
1729
|
|
|
|
|
|
|
parent => $TYPE{$parent}, |
1730
|
|
|
|
|
|
|
optimized => $code, |
1731
|
|
|
|
|
|
|
); |
1732
|
|
|
|
|
|
|
} |
1733
|
|
|
|
|
|
|
|
1734
|
|
|
|
|
|
|
# make it parametarizable |
1735
|
|
|
|
|
|
|
|
1736
|
|
|
|
|
|
|
$TYPE{Maybe} {constraint_generator} = \&_parameterize_Maybe_for; |
1737
|
|
|
|
|
|
|
$TYPE{ArrayRef}{constraint_generator} = \&_parameterize_ArrayRef_for; |
1738
|
|
|
|
|
|
|
$TYPE{HashRef} {constraint_generator} = \&_parameterize_HashRef_for; |
1739
|
|
|
|
|
|
|
|
1740
|
|
|
|
|
|
|
# sugars |
1741
|
|
|
|
|
|
|
|
1742
|
0
|
|
|
0
|
0
|
0
|
sub as ($) { (as => $_[0]) } ## no critic |
1743
|
0
|
|
|
0
|
0
|
0
|
sub where (&) { (where => $_[0]) } ## no critic |
1744
|
0
|
|
|
0
|
0
|
0
|
sub message (&) { (message => $_[0]) } ## no critic |
1745
|
0
|
|
|
0
|
0
|
0
|
sub optimize_as (&) { (optimize_as => $_[0]) } ## no critic |
1746
|
|
|
|
|
|
|
|
1747
|
0
|
|
|
0
|
0
|
0
|
sub from { @_ } |
1748
|
0
|
|
|
0
|
0
|
0
|
sub via (&) { $_[0] } ## no critic |
1749
|
|
|
|
|
|
|
|
1750
|
|
|
|
|
|
|
# type utilities |
1751
|
|
|
|
|
|
|
|
1752
|
|
|
|
|
|
|
sub optimized_constraints { # DEPRECATED |
1753
|
0
|
|
|
0
|
0
|
0
|
Carp::cluck('optimized_constraints() has been deprecated'); |
1754
|
0
|
|
|
|
|
0
|
return \%TYPE; |
1755
|
|
|
|
|
|
|
} |
1756
|
|
|
|
|
|
|
|
1757
|
|
|
|
|
|
|
undef @builtins; # free the allocated memory |
1758
|
|
|
|
|
|
|
@builtins = keys %TYPE; # reuse it |
1759
|
0
|
|
|
0
|
0
|
0
|
sub list_all_builtin_type_constraints { @builtins } |
1760
|
|
|
|
|
|
|
|
1761
|
0
|
|
|
0
|
0
|
0
|
sub list_all_type_constraints { keys %TYPE } |
1762
|
|
|
|
|
|
|
|
1763
|
|
|
|
|
|
|
sub _create_type{ |
1764
|
2
|
|
|
2
|
|
5
|
my $mode = shift; |
1765
|
|
|
|
|
|
|
|
1766
|
2
|
|
|
|
|
4
|
my $name; |
1767
|
|
|
|
|
|
|
my %args; |
1768
|
|
|
|
|
|
|
|
1769
|
2
|
50
|
33
|
|
|
27
|
if(@_ == 1 && ref $_[0]){ # @_ : { name => $name, where => ... } |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1770
|
0
|
|
|
|
|
0
|
%args = %{$_[0]}; |
|
0
|
|
|
|
|
0
|
|
1771
|
|
|
|
|
|
|
} |
1772
|
|
|
|
|
|
|
elsif(@_ == 2 && ref $_[1]){ # @_ : $name => { where => ... } |
1773
|
0
|
|
|
|
|
0
|
$name = $_[0]; |
1774
|
0
|
|
|
|
|
0
|
%args = %{$_[1]}; |
|
0
|
|
|
|
|
0
|
|
1775
|
|
|
|
|
|
|
} |
1776
|
|
|
|
|
|
|
elsif(@_ % 2){ # @_ : $name => ( where => ... ) |
1777
|
2
|
|
|
|
|
10
|
($name, %args) = @_; |
1778
|
|
|
|
|
|
|
} |
1779
|
|
|
|
|
|
|
else{ # @_ : (name => $name, where => ...) |
1780
|
0
|
|
|
|
|
0
|
%args = @_; |
1781
|
|
|
|
|
|
|
} |
1782
|
|
|
|
|
|
|
|
1783
|
2
|
50
|
|
|
|
9
|
if(!defined $name){ |
1784
|
0
|
|
|
|
|
0
|
$name = $args{name}; |
1785
|
|
|
|
|
|
|
} |
1786
|
|
|
|
|
|
|
|
1787
|
2
|
|
|
|
|
5
|
$args{name} = $name; |
1788
|
2
|
|
|
|
|
4
|
my $parent; |
1789
|
2
|
50
|
|
|
|
6
|
if($mode eq 'subtype'){ |
1790
|
2
|
|
|
|
|
6
|
$parent = delete $args{as}; |
1791
|
2
|
50
|
|
|
|
8
|
if(!$parent){ |
1792
|
0
|
|
|
|
|
0
|
$parent = delete $args{name}; |
1793
|
0
|
|
|
|
|
0
|
$name = undef; |
1794
|
|
|
|
|
|
|
} |
1795
|
|
|
|
|
|
|
} |
1796
|
|
|
|
|
|
|
|
1797
|
2
|
50
|
|
|
|
7
|
if(defined $name){ |
1798
|
|
|
|
|
|
|
# set 'package_defined_in' only if it is not a core package |
1799
|
2
|
|
|
|
|
7
|
my $this = $args{package_defined_in}; |
1800
|
2
|
50
|
|
|
|
9
|
if(!$this){ |
1801
|
2
|
|
|
|
|
4
|
$this = caller(1); |
1802
|
2
|
50
|
|
|
|
15
|
if($this !~ /\A Scalar::Random::PP::OO \b/xms){ |
1803
|
0
|
|
|
|
|
0
|
$args{package_defined_in} = $this; |
1804
|
|
|
|
|
|
|
} |
1805
|
|
|
|
|
|
|
} |
1806
|
|
|
|
|
|
|
|
1807
|
2
|
50
|
|
|
|
11
|
if($TYPE{$name}){ |
1808
|
0
|
|
0
|
|
|
0
|
my $that = $TYPE{$name}->{package_defined_in} || __PACKAGE__; |
1809
|
0
|
0
|
|
|
|
0
|
if($this ne $that) { |
1810
|
0
|
|
|
|
|
0
|
my $note = ''; |
1811
|
0
|
0
|
|
|
|
0
|
if($that eq __PACKAGE__) { |
1812
|
0
|
|
|
|
|
0
|
$note = sprintf " ('%s' is %s type constraint)", |
1813
|
|
|
|
|
|
|
$name, |
1814
|
0
|
0
|
|
|
|
0
|
scalar(grep { $name eq $_ } list_all_builtin_type_constraints()) |
1815
|
|
|
|
|
|
|
? 'a builtin' |
1816
|
|
|
|
|
|
|
: 'an implicitly created'; |
1817
|
|
|
|
|
|
|
} |
1818
|
0
|
|
|
|
|
0
|
Carp::croak("The type constraint '$name' has already been created in $that" |
1819
|
|
|
|
|
|
|
. " and cannot be created again in $this" . $note); |
1820
|
|
|
|
|
|
|
} |
1821
|
|
|
|
|
|
|
} |
1822
|
|
|
|
|
|
|
} |
1823
|
|
|
|
|
|
|
else{ |
1824
|
0
|
|
|
|
|
0
|
$args{name} = '__ANON__'; |
1825
|
|
|
|
|
|
|
} |
1826
|
|
|
|
|
|
|
|
1827
|
2
|
50
|
|
|
|
10
|
$args{constraint} = delete $args{where} if exists $args{where}; |
1828
|
2
|
50
|
|
|
|
10
|
$args{optimized} = delete $args{optimized_as} if exists $args{optimized_as}; |
1829
|
|
|
|
|
|
|
|
1830
|
2
|
|
|
|
|
3
|
my $constraint; |
1831
|
2
|
50
|
|
|
|
7
|
if($mode eq 'subtype'){ |
1832
|
2
|
|
|
|
|
9
|
$constraint = find_or_create_isa_type_constraint($parent)->create_child_type(%args); |
1833
|
|
|
|
|
|
|
} |
1834
|
|
|
|
|
|
|
else{ |
1835
|
0
|
|
|
|
|
0
|
$constraint = Scalar::Random::PP::OO::Meta::TypeConstraint->new(%args); |
1836
|
|
|
|
|
|
|
} |
1837
|
|
|
|
|
|
|
|
1838
|
2
|
50
|
|
|
|
8
|
if(defined $name){ |
1839
|
2
|
|
|
|
|
12
|
return $TYPE{$name} = $constraint; |
1840
|
|
|
|
|
|
|
} |
1841
|
|
|
|
|
|
|
else{ |
1842
|
0
|
|
|
|
|
0
|
return $constraint; |
1843
|
|
|
|
|
|
|
} |
1844
|
|
|
|
|
|
|
} |
1845
|
|
|
|
|
|
|
|
1846
|
|
|
|
|
|
|
sub type { |
1847
|
0
|
|
|
0
|
0
|
0
|
return _create_type('type', @_); |
1848
|
|
|
|
|
|
|
} |
1849
|
|
|
|
|
|
|
|
1850
|
|
|
|
|
|
|
sub subtype { |
1851
|
0
|
|
|
0
|
0
|
0
|
return _create_type('subtype', @_); |
1852
|
|
|
|
|
|
|
} |
1853
|
|
|
|
|
|
|
|
1854
|
|
|
|
|
|
|
sub coerce { |
1855
|
0
|
|
|
0
|
0
|
0
|
my $type_name = shift; |
1856
|
|
|
|
|
|
|
|
1857
|
0
|
0
|
|
|
|
0
|
my $type = find_type_constraint($type_name) |
1858
|
|
|
|
|
|
|
or Carp::croak("Cannot find type '$type_name', perhaps you forgot to load it."); |
1859
|
|
|
|
|
|
|
|
1860
|
0
|
|
|
|
|
0
|
$type->_add_type_coercions(@_); |
1861
|
0
|
|
|
|
|
0
|
return; |
1862
|
|
|
|
|
|
|
} |
1863
|
|
|
|
|
|
|
|
1864
|
|
|
|
|
|
|
sub class_type { |
1865
|
2
|
|
|
2
|
0
|
4
|
my($name, $options) = @_; |
1866
|
2
|
|
33
|
|
|
13
|
my $class = $options->{class} || $name; |
1867
|
|
|
|
|
|
|
|
1868
|
|
|
|
|
|
|
# ClassType |
1869
|
2
|
|
|
|
|
10
|
return _create_type 'subtype', $name => ( |
1870
|
|
|
|
|
|
|
as => 'Object', |
1871
|
|
|
|
|
|
|
optimized_as => Scalar::Random::PP::OO::Util::generate_isa_predicate_for($class), |
1872
|
|
|
|
|
|
|
); |
1873
|
|
|
|
|
|
|
} |
1874
|
|
|
|
|
|
|
|
1875
|
|
|
|
|
|
|
sub role_type { |
1876
|
0
|
|
|
0
|
0
|
0
|
my($name, $options) = @_; |
1877
|
0
|
|
0
|
|
|
0
|
my $role = $options->{role} || $name; |
1878
|
|
|
|
|
|
|
|
1879
|
|
|
|
|
|
|
# RoleType |
1880
|
|
|
|
|
|
|
return _create_type 'subtype', $name => ( |
1881
|
|
|
|
|
|
|
as => 'Object', |
1882
|
0
|
0
|
|
0
|
|
0
|
optimized_as => sub { Scalar::Util::blessed($_[0]) && does_role($_[0], $role) }, |
1883
|
0
|
|
|
|
|
0
|
); |
1884
|
|
|
|
|
|
|
} |
1885
|
|
|
|
|
|
|
|
1886
|
|
|
|
|
|
|
sub duck_type { |
1887
|
0
|
|
|
0
|
0
|
0
|
my($name, @methods); |
1888
|
|
|
|
|
|
|
|
1889
|
0
|
0
|
0
|
|
|
0
|
if(!(@_ == 1 && ref($_[0]) eq 'ARRAY')){ |
1890
|
0
|
|
|
|
|
0
|
$name = shift; |
1891
|
|
|
|
|
|
|
} |
1892
|
|
|
|
|
|
|
|
1893
|
0
|
0
|
0
|
|
|
0
|
@methods = (@_ == 1 && ref($_[0]) eq 'ARRAY') ? @{$_[0]} : @_; |
|
0
|
|
|
|
|
0
|
|
1894
|
|
|
|
|
|
|
|
1895
|
|
|
|
|
|
|
# DuckType |
1896
|
0
|
|
|
|
|
0
|
return _create_type 'subtype', $name => ( |
1897
|
|
|
|
|
|
|
as => 'Object', |
1898
|
|
|
|
|
|
|
optimized_as => Scalar::Random::PP::OO::Util::generate_can_predicate_for(\@methods), |
1899
|
|
|
|
|
|
|
); |
1900
|
|
|
|
|
|
|
} |
1901
|
|
|
|
|
|
|
|
1902
|
|
|
|
|
|
|
sub enum { |
1903
|
0
|
|
|
0
|
0
|
0
|
my($name, %valid); |
1904
|
|
|
|
|
|
|
|
1905
|
0
|
0
|
0
|
|
|
0
|
if(!(@_ == 1 && ref($_[0]) eq 'ARRAY')){ |
1906
|
0
|
|
|
|
|
0
|
$name = shift; |
1907
|
|
|
|
|
|
|
} |
1908
|
|
|
|
|
|
|
|
1909
|
0
|
0
|
0
|
|
|
0
|
%valid = map{ $_ => undef } (@_ == 1 && ref($_[0]) eq 'ARRAY' ? @{$_[0]} : @_); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1910
|
|
|
|
|
|
|
|
1911
|
|
|
|
|
|
|
# EnumType |
1912
|
|
|
|
|
|
|
return _create_type 'subtype', $name => ( |
1913
|
|
|
|
|
|
|
as => 'Str', |
1914
|
0
|
0
|
0
|
0
|
|
0
|
optimized_as => sub{ defined($_[0]) && !ref($_[0]) && exists $valid{$_[0]} }, |
1915
|
0
|
|
|
|
|
0
|
); |
1916
|
|
|
|
|
|
|
} |
1917
|
|
|
|
|
|
|
|
1918
|
|
|
|
|
|
|
sub _find_or_create_regular_type{ |
1919
|
0
|
|
|
0
|
|
0
|
my($spec, $create) = @_; |
1920
|
|
|
|
|
|
|
|
1921
|
0
|
0
|
|
|
|
0
|
return $TYPE{$spec} if exists $TYPE{$spec}; |
1922
|
|
|
|
|
|
|
|
1923
|
0
|
|
|
|
|
0
|
my $meta = Scalar::Random::PP::OO::Util::get_metaclass_by_name($spec); |
1924
|
|
|
|
|
|
|
|
1925
|
0
|
0
|
|
|
|
0
|
if(!defined $meta){ |
1926
|
0
|
0
|
|
|
|
0
|
return $create ? class_type($spec) : undef; |
1927
|
|
|
|
|
|
|
} |
1928
|
|
|
|
|
|
|
|
1929
|
0
|
0
|
|
|
|
0
|
if(Scalar::Random::PP::OO::Util::is_a_metarole($meta)){ |
1930
|
0
|
|
|
|
|
0
|
return role_type($spec); |
1931
|
|
|
|
|
|
|
} |
1932
|
|
|
|
|
|
|
else{ |
1933
|
0
|
|
|
|
|
0
|
return class_type($spec); |
1934
|
|
|
|
|
|
|
} |
1935
|
|
|
|
|
|
|
} |
1936
|
|
|
|
|
|
|
|
1937
|
|
|
|
|
|
|
sub _find_or_create_parameterized_type{ |
1938
|
0
|
|
|
0
|
|
0
|
my($base, $param) = @_; |
1939
|
|
|
|
|
|
|
|
1940
|
0
|
|
|
|
|
0
|
my $name = sprintf '%s[%s]', $base->name, $param->name; |
1941
|
|
|
|
|
|
|
|
1942
|
0
|
|
0
|
|
|
0
|
$TYPE{$name} ||= $base->parameterize($param, $name); |
1943
|
|
|
|
|
|
|
} |
1944
|
|
|
|
|
|
|
|
1945
|
|
|
|
|
|
|
sub _find_or_create_union_type{ |
1946
|
0
|
0
|
|
0
|
|
0
|
return if grep{ not defined } @_; |
|
0
|
|
|
|
|
0
|
|
1947
|
0
|
0
|
|
|
|
0
|
my @types = sort map{ $_->{type_constraints} ? @{$_->{type_constraints}} : $_ } @_; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1948
|
|
|
|
|
|
|
|
1949
|
0
|
|
|
|
|
0
|
my $name = join '|', @types; |
1950
|
|
|
|
|
|
|
|
1951
|
|
|
|
|
|
|
# UnionType |
1952
|
0
|
|
0
|
|
|
0
|
$TYPE{$name} ||= Scalar::Random::PP::OO::Meta::TypeConstraint->new( |
1953
|
|
|
|
|
|
|
name => $name, |
1954
|
|
|
|
|
|
|
type_constraints => \@types, |
1955
|
|
|
|
|
|
|
); |
1956
|
|
|
|
|
|
|
} |
1957
|
|
|
|
|
|
|
|
1958
|
|
|
|
|
|
|
# The type parser |
1959
|
|
|
|
|
|
|
|
1960
|
|
|
|
|
|
|
# param : '[' type ']' | NOTHING |
1961
|
|
|
|
|
|
|
sub _parse_param { |
1962
|
0
|
|
|
0
|
|
0
|
my($c) = @_; |
1963
|
|
|
|
|
|
|
|
1964
|
0
|
0
|
|
|
|
0
|
if($c->{spec} =~ s/^\[//){ |
1965
|
0
|
|
|
|
|
0
|
my $type = _parse_type($c, 1); |
1966
|
|
|
|
|
|
|
|
1967
|
0
|
0
|
|
|
|
0
|
if($c->{spec} =~ s/^\]//){ |
1968
|
0
|
|
|
|
|
0
|
return $type; |
1969
|
|
|
|
|
|
|
} |
1970
|
0
|
|
|
|
|
0
|
Carp::croak("Syntax error in type: missing right square bracket in '$c->{orig}'"); |
1971
|
|
|
|
|
|
|
} |
1972
|
|
|
|
|
|
|
|
1973
|
0
|
|
|
|
|
0
|
return undef; |
1974
|
|
|
|
|
|
|
} |
1975
|
|
|
|
|
|
|
|
1976
|
|
|
|
|
|
|
# name : [\w.:]+ |
1977
|
|
|
|
|
|
|
sub _parse_name { |
1978
|
0
|
|
|
0
|
|
0
|
my($c, $create) = @_; |
1979
|
|
|
|
|
|
|
|
1980
|
0
|
0
|
|
|
|
0
|
if($c->{spec} =~ s/\A ([\w.:]+) //xms){ |
1981
|
0
|
|
|
|
|
0
|
return _find_or_create_regular_type($1, $create); |
1982
|
|
|
|
|
|
|
} |
1983
|
0
|
|
|
|
|
0
|
Carp::croak("Syntax error in type: expect type name near '$c->{spec}' in '$c->{orig}'"); |
1984
|
|
|
|
|
|
|
} |
1985
|
|
|
|
|
|
|
|
1986
|
|
|
|
|
|
|
# single_type : name param |
1987
|
|
|
|
|
|
|
sub _parse_single_type { |
1988
|
0
|
|
|
0
|
|
0
|
my($c, $create) = @_; |
1989
|
|
|
|
|
|
|
|
1990
|
0
|
|
|
|
|
0
|
my $type = _parse_name($c, $create); |
1991
|
0
|
|
|
|
|
0
|
my $param = _parse_param($c); |
1992
|
|
|
|
|
|
|
|
1993
|
0
|
0
|
|
|
|
0
|
if(defined $type){ |
|
|
0
|
|
|
|
|
|
1994
|
0
|
0
|
|
|
|
0
|
if(defined $param){ |
1995
|
0
|
|
|
|
|
0
|
return _find_or_create_parameterized_type($type, $param); |
1996
|
|
|
|
|
|
|
} |
1997
|
|
|
|
|
|
|
else { |
1998
|
0
|
|
|
|
|
0
|
return $type; |
1999
|
|
|
|
|
|
|
} |
2000
|
|
|
|
|
|
|
} |
2001
|
|
|
|
|
|
|
elsif(defined $param){ |
2002
|
0
|
|
|
|
|
0
|
Carp::croak("Undefined type with parameter [$param] in '$c->{orig}'"); |
2003
|
|
|
|
|
|
|
} |
2004
|
|
|
|
|
|
|
else{ |
2005
|
0
|
|
|
|
|
0
|
return undef; |
2006
|
|
|
|
|
|
|
} |
2007
|
|
|
|
|
|
|
} |
2008
|
|
|
|
|
|
|
|
2009
|
|
|
|
|
|
|
# type : single_type ('|' single_type)* |
2010
|
|
|
|
|
|
|
sub _parse_type { |
2011
|
0
|
|
|
0
|
|
0
|
my($c, $create) = @_; |
2012
|
|
|
|
|
|
|
|
2013
|
0
|
|
|
|
|
0
|
my $type = _parse_single_type($c, $create); |
2014
|
0
|
0
|
|
|
|
0
|
if($c->{spec}){ # can be an union type |
2015
|
0
|
|
|
|
|
0
|
my @types; |
2016
|
0
|
|
|
|
|
0
|
while($c->{spec} =~ s/^\|//){ |
2017
|
0
|
|
|
|
|
0
|
push @types, _parse_single_type($c, $create); |
2018
|
|
|
|
|
|
|
} |
2019
|
0
|
0
|
|
|
|
0
|
if(@types){ |
2020
|
0
|
|
|
|
|
0
|
return _find_or_create_union_type($type, @types); |
2021
|
|
|
|
|
|
|
} |
2022
|
|
|
|
|
|
|
} |
2023
|
0
|
|
|
|
|
0
|
return $type; |
2024
|
|
|
|
|
|
|
} |
2025
|
|
|
|
|
|
|
|
2026
|
|
|
|
|
|
|
|
2027
|
|
|
|
|
|
|
sub find_type_constraint { |
2028
|
2
|
|
|
2
|
0
|
5
|
my($spec) = @_; |
2029
|
2
|
50
|
33
|
|
|
12
|
return $spec if Scalar::Random::PP::OO::Util::is_a_type_constraint($spec) or not defined $spec; |
2030
|
|
|
|
|
|
|
|
2031
|
2
|
|
|
|
|
7
|
$spec =~ s/\s+//g; |
2032
|
2
|
|
|
|
|
16
|
return $TYPE{$spec}; |
2033
|
|
|
|
|
|
|
} |
2034
|
|
|
|
|
|
|
|
2035
|
|
|
|
|
|
|
sub register_type_constraint { |
2036
|
0
|
|
|
0
|
0
|
0
|
my($constraint) = @_; |
2037
|
0
|
0
|
|
|
|
0
|
Carp::croak("No type supplied / type is not a valid type constraint") |
2038
|
|
|
|
|
|
|
unless Scalar::Random::PP::OO::Util::is_a_type_constraint($constraint); |
2039
|
0
|
|
|
|
|
0
|
my $name = $constraint->name; |
2040
|
0
|
0
|
|
|
|
0
|
Carp::croak("can't register an unnamed type constraint") |
2041
|
|
|
|
|
|
|
unless defined $name; |
2042
|
0
|
|
|
|
|
0
|
return $TYPE{$name} = $constraint; |
2043
|
|
|
|
|
|
|
} |
2044
|
|
|
|
|
|
|
|
2045
|
|
|
|
|
|
|
sub find_or_parse_type_constraint { |
2046
|
2
|
|
|
2
|
0
|
4
|
my($spec) = @_; |
2047
|
2
|
50
|
33
|
|
|
5
|
return $spec if Scalar::Random::PP::OO::Util::is_a_type_constraint($spec) or not defined $spec; |
2048
|
|
|
|
|
|
|
|
2049
|
2
|
|
|
|
|
6
|
$spec =~ s/\s+//g; |
2050
|
2
|
|
33
|
|
|
29
|
return $TYPE{$spec} || do{ |
2051
|
|
|
|
|
|
|
my $context = { |
2052
|
|
|
|
|
|
|
spec => $spec, |
2053
|
|
|
|
|
|
|
orig => $spec, |
2054
|
|
|
|
|
|
|
}; |
2055
|
|
|
|
|
|
|
my $type = _parse_type($context); |
2056
|
|
|
|
|
|
|
|
2057
|
|
|
|
|
|
|
if($context->{spec}){ |
2058
|
|
|
|
|
|
|
Carp::croak("Syntax error: extra elements '$context->{spec}' in '$context->{orig}'"); |
2059
|
|
|
|
|
|
|
} |
2060
|
|
|
|
|
|
|
$type; |
2061
|
|
|
|
|
|
|
}; |
2062
|
|
|
|
|
|
|
} |
2063
|
|
|
|
|
|
|
|
2064
|
|
|
|
|
|
|
sub find_or_create_does_type_constraint{ |
2065
|
|
|
|
|
|
|
# XXX: Moose does not register a new role_type, but Scalar::Random::PP::OO does. |
2066
|
0
|
|
0
|
0
|
0
|
0
|
return find_or_parse_type_constraint(@_) || role_type(@_); |
2067
|
|
|
|
|
|
|
} |
2068
|
|
|
|
|
|
|
|
2069
|
|
|
|
|
|
|
sub find_or_create_isa_type_constraint { |
2070
|
|
|
|
|
|
|
# XXX: Moose does not register a new class_type, but Scalar::Random::PP::OO does. |
2071
|
2
|
|
33
|
2
|
0
|
8
|
return find_or_parse_type_constraint(@_) || class_type(@_); |
2072
|
|
|
|
|
|
|
} |
2073
|
|
|
|
|
|
|
|
2074
|
|
|
|
|
|
|
# Contents of Mouse |
2075
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::TOP; |
2076
|
2
|
|
|
2
|
|
68
|
use 5.006_002; |
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
89
|
|
2077
|
|
|
|
|
|
|
|
2078
|
2
|
|
|
2
|
|
9
|
use Scalar::Random::PP::OO::Exporter; # enables strict and warnings |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
10
|
|
2079
|
|
|
|
|
|
|
|
2080
|
|
|
|
|
|
|
our $VERSION = '0.70'; |
2081
|
|
|
|
|
|
|
|
2082
|
2
|
|
|
2
|
|
21
|
use Carp qw(confess); |
|
2
|
|
|
|
|
39
|
|
|
2
|
|
|
|
|
163
|
|
2083
|
2
|
|
|
2
|
|
10
|
use Scalar::Util qw(blessed); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
79
|
|
2084
|
|
|
|
|
|
|
|
2085
|
2
|
|
|
2
|
|
10
|
use Scalar::Random::PP::OO::Util (); |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
44
|
|
2086
|
|
|
|
|
|
|
|
2087
|
2
|
|
|
2
|
|
11
|
use Scalar::Random::PP::OO::Meta::Module; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
60
|
|
2088
|
2
|
|
|
2
|
|
8
|
use Scalar::Random::PP::OO::Meta::Class; |
|
2
|
|
|
|
|
43
|
|
|
2
|
|
|
|
|
49
|
|
2089
|
2
|
|
|
2
|
|
9
|
use Scalar::Random::PP::OO::Meta::Role; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
50
|
|
2090
|
2
|
|
|
2
|
|
9
|
use Scalar::Random::PP::OO::Meta::Attribute; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
53
|
|
2091
|
2
|
|
|
2
|
|
9
|
use Scalar::Random::PP::OO::Object; |
|
2
|
|
|
|
|
10
|
|
|
2
|
|
|
|
|
52
|
|
2092
|
2
|
|
|
2
|
|
9
|
use Scalar::Random::PP::OO::Util::TypeConstraints (); |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
1802
|
|
2093
|
|
|
|
|
|
|
|
2094
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Exporter->setup_import_methods( |
2095
|
|
|
|
|
|
|
as_is => [qw( |
2096
|
|
|
|
|
|
|
extends with |
2097
|
|
|
|
|
|
|
has |
2098
|
|
|
|
|
|
|
before after around |
2099
|
|
|
|
|
|
|
override super |
2100
|
|
|
|
|
|
|
augment inner |
2101
|
|
|
|
|
|
|
), |
2102
|
|
|
|
|
|
|
\&Scalar::Util::blessed, |
2103
|
|
|
|
|
|
|
\&Carp::confess, |
2104
|
|
|
|
|
|
|
], |
2105
|
|
|
|
|
|
|
); |
2106
|
|
|
|
|
|
|
|
2107
|
|
|
|
|
|
|
|
2108
|
|
|
|
|
|
|
sub extends { |
2109
|
0
|
|
|
0
|
|
0
|
Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller)->superclasses(@_); |
2110
|
0
|
|
|
|
|
0
|
return; |
2111
|
|
|
|
|
|
|
} |
2112
|
|
|
|
|
|
|
|
2113
|
|
|
|
|
|
|
sub with { |
2114
|
0
|
|
|
0
|
|
0
|
Scalar::Random::PP::OO::Util::apply_all_roles(scalar(caller), @_); |
2115
|
0
|
|
|
|
|
0
|
return; |
2116
|
|
|
|
|
|
|
} |
2117
|
|
|
|
|
|
|
|
2118
|
|
|
|
|
|
|
sub has { |
2119
|
2
|
|
|
2
|
|
11
|
my $meta = Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller); |
2120
|
2
|
|
|
|
|
5
|
my $name = shift; |
2121
|
|
|
|
|
|
|
|
2122
|
2
|
50
|
|
|
|
10
|
$meta->throw_error(q{Usage: has 'name' => ( key => value, ... )}) |
2123
|
|
|
|
|
|
|
if @_ % 2; # odd number of arguments |
2124
|
|
|
|
|
|
|
|
2125
|
2
|
50
|
|
|
|
8
|
if(ref $name){ # has [qw(foo bar)] => (...) |
2126
|
0
|
|
|
|
|
0
|
for (@{$name}){ |
|
0
|
|
|
|
|
0
|
|
2127
|
0
|
|
|
|
|
0
|
$meta->add_attribute($_ => @_); |
2128
|
|
|
|
|
|
|
} |
2129
|
|
|
|
|
|
|
} |
2130
|
|
|
|
|
|
|
else{ # has foo => (...) |
2131
|
2
|
|
|
|
|
10
|
$meta->add_attribute($name => @_); |
2132
|
|
|
|
|
|
|
} |
2133
|
2
|
|
|
|
|
6
|
return; |
2134
|
|
|
|
|
|
|
} |
2135
|
|
|
|
|
|
|
|
2136
|
|
|
|
|
|
|
sub before { |
2137
|
0
|
|
|
0
|
|
0
|
my $meta = Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller); |
2138
|
0
|
|
|
|
|
0
|
my $code = pop; |
2139
|
0
|
|
|
|
|
0
|
for my $name($meta->_collect_methods(@_)) { |
2140
|
0
|
|
|
|
|
0
|
$meta->add_before_method_modifier($name => $code); |
2141
|
|
|
|
|
|
|
} |
2142
|
0
|
|
|
|
|
0
|
return; |
2143
|
|
|
|
|
|
|
} |
2144
|
|
|
|
|
|
|
|
2145
|
|
|
|
|
|
|
sub after { |
2146
|
0
|
|
|
0
|
|
0
|
my $meta = Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller); |
2147
|
0
|
|
|
|
|
0
|
my $code = pop; |
2148
|
0
|
|
|
|
|
0
|
for my $name($meta->_collect_methods(@_)) { |
2149
|
0
|
|
|
|
|
0
|
$meta->add_after_method_modifier($name => $code); |
2150
|
|
|
|
|
|
|
} |
2151
|
0
|
|
|
|
|
0
|
return; |
2152
|
|
|
|
|
|
|
} |
2153
|
|
|
|
|
|
|
|
2154
|
|
|
|
|
|
|
sub around { |
2155
|
0
|
|
|
0
|
|
0
|
my $meta = Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller); |
2156
|
0
|
|
|
|
|
0
|
my $code = pop; |
2157
|
0
|
|
|
|
|
0
|
for my $name($meta->_collect_methods(@_)) { |
2158
|
0
|
|
|
|
|
0
|
$meta->add_around_method_modifier($name => $code); |
2159
|
|
|
|
|
|
|
} |
2160
|
0
|
|
|
|
|
0
|
return; |
2161
|
|
|
|
|
|
|
} |
2162
|
|
|
|
|
|
|
|
2163
|
|
|
|
|
|
|
our $SUPER_PACKAGE; |
2164
|
|
|
|
|
|
|
our $SUPER_BODY; |
2165
|
|
|
|
|
|
|
our @SUPER_ARGS; |
2166
|
|
|
|
|
|
|
|
2167
|
|
|
|
|
|
|
sub super { |
2168
|
|
|
|
|
|
|
# This check avoids a recursion loop - see |
2169
|
|
|
|
|
|
|
# t/100_bugs/020_super_recursion.t |
2170
|
0
|
0
|
0
|
0
|
|
0
|
return if defined $SUPER_PACKAGE && $SUPER_PACKAGE ne caller(); |
2171
|
0
|
0
|
|
|
|
0
|
return if !defined $SUPER_BODY; |
2172
|
0
|
|
|
|
|
0
|
$SUPER_BODY->(@SUPER_ARGS); |
2173
|
|
|
|
|
|
|
} |
2174
|
|
|
|
|
|
|
|
2175
|
|
|
|
|
|
|
sub override { |
2176
|
|
|
|
|
|
|
# my($name, $method) = @_; |
2177
|
0
|
|
|
0
|
|
0
|
Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller)->add_override_method_modifier(@_); |
2178
|
|
|
|
|
|
|
} |
2179
|
|
|
|
|
|
|
|
2180
|
|
|
|
|
|
|
our %INNER_BODY; |
2181
|
|
|
|
|
|
|
our %INNER_ARGS; |
2182
|
|
|
|
|
|
|
|
2183
|
|
|
|
|
|
|
sub inner { |
2184
|
0
|
|
|
0
|
|
0
|
my $pkg = caller(); |
2185
|
0
|
0
|
|
|
|
0
|
if ( my $body = $INNER_BODY{$pkg} ) { |
2186
|
0
|
|
|
|
|
0
|
my $args = $INNER_ARGS{$pkg}; |
2187
|
0
|
|
|
|
|
0
|
local $INNER_ARGS{$pkg}; |
2188
|
0
|
|
|
|
|
0
|
local $INNER_BODY{$pkg}; |
2189
|
0
|
|
|
|
|
0
|
return $body->(@{$args}); |
|
0
|
|
|
|
|
0
|
|
2190
|
|
|
|
|
|
|
} |
2191
|
|
|
|
|
|
|
else { |
2192
|
0
|
|
|
|
|
0
|
return; |
2193
|
|
|
|
|
|
|
} |
2194
|
|
|
|
|
|
|
} |
2195
|
|
|
|
|
|
|
|
2196
|
|
|
|
|
|
|
sub augment { |
2197
|
|
|
|
|
|
|
#my($name, $method) = @_; |
2198
|
0
|
|
|
0
|
|
0
|
Scalar::Random::PP::OO::Meta::Class->initialize(scalar caller)->add_augment_method_modifier(@_); |
2199
|
0
|
|
|
|
|
0
|
return; |
2200
|
|
|
|
|
|
|
} |
2201
|
|
|
|
|
|
|
|
2202
|
|
|
|
|
|
|
sub init_meta { |
2203
|
2
|
|
|
2
|
|
4
|
shift; |
2204
|
2
|
|
|
|
|
7
|
my %args = @_; |
2205
|
|
|
|
|
|
|
|
2206
|
2
|
50
|
|
|
|
9
|
my $class = $args{for_class} |
2207
|
|
|
|
|
|
|
or confess("Cannot call init_meta without specifying a for_class"); |
2208
|
|
|
|
|
|
|
|
2209
|
2
|
|
50
|
|
|
76
|
my $base_class = $args{base_class} || 'Scalar::Random::PP::OO::Object'; |
2210
|
2
|
|
50
|
|
|
14
|
my $metaclass = $args{metaclass} || 'Scalar::Random::PP::OO::Meta::Class'; |
2211
|
|
|
|
|
|
|
|
2212
|
2
|
|
|
|
|
19
|
my $meta = $metaclass->initialize($class); |
2213
|
|
|
|
|
|
|
|
2214
|
|
|
|
|
|
|
$meta->add_method(meta => sub{ |
2215
|
0
|
|
0
|
0
|
|
0
|
return $metaclass->initialize(ref($_[0]) || $_[0]); |
2216
|
2
|
|
|
|
|
21
|
}); |
2217
|
|
|
|
|
|
|
|
2218
|
2
|
50
|
|
|
|
8
|
$meta->superclasses($base_class) |
2219
|
|
|
|
|
|
|
unless $meta->superclasses; |
2220
|
|
|
|
|
|
|
|
2221
|
|
|
|
|
|
|
# make a class type for each Scalar::Random::PP::OO class |
2222
|
2
|
50
|
|
|
|
7
|
Scalar::Random::PP::OO::Util::TypeConstraints::class_type($class) |
2223
|
|
|
|
|
|
|
unless Scalar::Random::PP::OO::Util::TypeConstraints::find_type_constraint($class); |
2224
|
|
|
|
|
|
|
|
2225
|
2
|
|
|
|
|
10
|
return $meta; |
2226
|
|
|
|
|
|
|
} |
2227
|
|
|
|
|
|
|
|
2228
|
|
|
|
|
|
|
# Contents of Mouse::Meta::Attribute |
2229
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Attribute; |
2230
|
2
|
|
|
2
|
|
13
|
use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
7
|
|
2231
|
|
|
|
|
|
|
|
2232
|
2
|
|
|
2
|
|
10
|
use Carp (); |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
31
|
|
2233
|
|
|
|
|
|
|
|
2234
|
2
|
|
|
2
|
|
10
|
use Scalar::Random::PP::OO::Meta::TypeConstraint; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
4391
|
|
2235
|
|
|
|
|
|
|
|
2236
|
|
|
|
|
|
|
my %valid_options = map { $_ => undef } ( |
2237
|
|
|
|
|
|
|
'accessor', |
2238
|
|
|
|
|
|
|
'auto_deref', |
2239
|
|
|
|
|
|
|
'builder', |
2240
|
|
|
|
|
|
|
'clearer', |
2241
|
|
|
|
|
|
|
'coerce', |
2242
|
|
|
|
|
|
|
'default', |
2243
|
|
|
|
|
|
|
'documentation', |
2244
|
|
|
|
|
|
|
'does', |
2245
|
|
|
|
|
|
|
'handles', |
2246
|
|
|
|
|
|
|
'init_arg', |
2247
|
|
|
|
|
|
|
'insertion_order', |
2248
|
|
|
|
|
|
|
'is', |
2249
|
|
|
|
|
|
|
'isa', |
2250
|
|
|
|
|
|
|
'lazy', |
2251
|
|
|
|
|
|
|
'lazy_build', |
2252
|
|
|
|
|
|
|
'name', |
2253
|
|
|
|
|
|
|
'predicate', |
2254
|
|
|
|
|
|
|
'reader', |
2255
|
|
|
|
|
|
|
'required', |
2256
|
|
|
|
|
|
|
'traits', |
2257
|
|
|
|
|
|
|
'trigger', |
2258
|
|
|
|
|
|
|
'type_constraint', |
2259
|
|
|
|
|
|
|
'weak_ref', |
2260
|
|
|
|
|
|
|
'writer', |
2261
|
|
|
|
|
|
|
|
2262
|
|
|
|
|
|
|
# internally used |
2263
|
|
|
|
|
|
|
'associated_class', |
2264
|
|
|
|
|
|
|
'associated_methods', |
2265
|
|
|
|
|
|
|
|
2266
|
|
|
|
|
|
|
# Moose defines, but Scalar::Random::PP::OO doesn't |
2267
|
|
|
|
|
|
|
#'definition_context', |
2268
|
|
|
|
|
|
|
#'initializer', |
2269
|
|
|
|
|
|
|
|
2270
|
|
|
|
|
|
|
# special case for AttributeHelpers |
2271
|
|
|
|
|
|
|
'provides', |
2272
|
|
|
|
|
|
|
'curries', |
2273
|
|
|
|
|
|
|
); |
2274
|
|
|
|
|
|
|
|
2275
|
|
|
|
|
|
|
our @CARP_NOT = qw(Scalar::Random::PP::OO::Meta::Class); |
2276
|
|
|
|
|
|
|
|
2277
|
|
|
|
|
|
|
sub new { |
2278
|
2
|
|
|
2
|
0
|
4
|
my $class = shift; |
2279
|
2
|
|
|
|
|
4
|
my $name = shift; |
2280
|
|
|
|
|
|
|
|
2281
|
2
|
|
|
|
|
12
|
my $args = $class->Scalar::Random::PP::OO::Object::BUILDARGS(@_); |
2282
|
|
|
|
|
|
|
|
2283
|
2
|
|
|
|
|
10
|
$class->_process_options($name, $args); |
2284
|
|
|
|
|
|
|
|
2285
|
2
|
|
|
|
|
5
|
$args->{name} = $name; |
2286
|
|
|
|
|
|
|
|
2287
|
|
|
|
|
|
|
# check options |
2288
|
|
|
|
|
|
|
# (1) known by core |
2289
|
2
|
|
|
|
|
4
|
my @bad = grep{ !exists $valid_options{$_} } keys %{$args}; |
|
8
|
|
|
|
|
20
|
|
|
2
|
|
|
|
|
7
|
|
2290
|
|
|
|
|
|
|
|
2291
|
|
|
|
|
|
|
# (2) known by subclasses |
2292
|
2
|
50
|
33
|
|
|
10
|
if(@bad && $class ne __PACKAGE__){ |
2293
|
0
|
|
|
|
|
0
|
my %valid_attrs = ( |
2294
|
0
|
|
|
|
|
0
|
map { $_ => undef } |
2295
|
0
|
|
|
|
|
0
|
grep { defined } |
2296
|
0
|
|
|
|
|
0
|
map { $_->init_arg() } |
2297
|
|
|
|
|
|
|
$class->meta->get_all_attributes() |
2298
|
|
|
|
|
|
|
); |
2299
|
0
|
|
|
|
|
0
|
@bad = grep{ !exists $valid_attrs{$_} } @bad; |
|
0
|
|
|
|
|
0
|
|
2300
|
|
|
|
|
|
|
} |
2301
|
|
|
|
|
|
|
|
2302
|
|
|
|
|
|
|
# (3) bad options found |
2303
|
2
|
50
|
|
|
|
7
|
if(@bad){ |
2304
|
0
|
|
|
|
|
0
|
Carp::carp( |
2305
|
|
|
|
|
|
|
"Found unknown argument(s) passed to '$name' attribute constructor in '$class': " |
2306
|
|
|
|
|
|
|
. Scalar::Random::PP::OO::Util::english_list(@bad)); |
2307
|
|
|
|
|
|
|
} |
2308
|
|
|
|
|
|
|
|
2309
|
2
|
|
|
|
|
8
|
my $self = bless $args, $class; |
2310
|
|
|
|
|
|
|
|
2311
|
|
|
|
|
|
|
# extra attributes |
2312
|
2
|
50
|
|
|
|
7
|
if($class ne __PACKAGE__){ |
2313
|
0
|
|
|
|
|
0
|
$class->meta->_initialize_object($self, $args); |
2314
|
|
|
|
|
|
|
} |
2315
|
|
|
|
|
|
|
|
2316
|
2
|
|
|
|
|
7
|
return $self; |
2317
|
|
|
|
|
|
|
} |
2318
|
|
|
|
|
|
|
|
2319
|
0
|
0
|
|
0
|
0
|
0
|
sub has_read_method { $_[0]->has_reader || $_[0]->has_accessor } |
2320
|
0
|
0
|
|
0
|
0
|
0
|
sub has_write_method { $_[0]->has_writer || $_[0]->has_accessor } |
2321
|
|
|
|
|
|
|
|
2322
|
|
|
|
|
|
|
sub interpolate_class{ |
2323
|
2
|
|
|
2
|
0
|
5
|
my($class, $args) = @_; |
2324
|
|
|
|
|
|
|
|
2325
|
2
|
50
|
|
|
|
8
|
if(my $metaclass = delete $args->{metaclass}){ |
2326
|
0
|
|
|
|
|
0
|
$class = Scalar::Random::PP::OO::Util::resolve_metaclass_alias( Attribute => $metaclass ); |
2327
|
|
|
|
|
|
|
} |
2328
|
|
|
|
|
|
|
|
2329
|
2
|
|
|
|
|
4
|
my @traits; |
2330
|
2
|
50
|
|
|
|
9
|
if(my $traits_ref = delete $args->{traits}){ |
2331
|
|
|
|
|
|
|
|
2332
|
0
|
|
|
|
|
0
|
for (my $i = 0; $i < @{$traits_ref}; $i++) { |
|
0
|
|
|
|
|
0
|
|
2333
|
0
|
|
|
|
|
0
|
my $trait = Scalar::Random::PP::OO::Util::resolve_metaclass_alias(Attribute => $traits_ref->[$i], trait => 1); |
2334
|
|
|
|
|
|
|
|
2335
|
0
|
0
|
|
|
|
0
|
next if $class->does($trait); |
2336
|
|
|
|
|
|
|
|
2337
|
0
|
|
|
|
|
0
|
push @traits, $trait; |
2338
|
|
|
|
|
|
|
|
2339
|
|
|
|
|
|
|
# are there options? |
2340
|
0
|
0
|
|
|
|
0
|
push @traits, $traits_ref->[++$i] |
2341
|
|
|
|
|
|
|
if ref($traits_ref->[$i+1]); |
2342
|
|
|
|
|
|
|
} |
2343
|
|
|
|
|
|
|
|
2344
|
0
|
0
|
|
|
|
0
|
if (@traits) { |
2345
|
0
|
|
|
|
|
0
|
$class = Scalar::Random::PP::OO::Meta::Class->create_anon_class( |
2346
|
|
|
|
|
|
|
superclasses => [ $class ], |
2347
|
|
|
|
|
|
|
roles => \@traits, |
2348
|
|
|
|
|
|
|
cache => 1, |
2349
|
|
|
|
|
|
|
)->name; |
2350
|
|
|
|
|
|
|
} |
2351
|
|
|
|
|
|
|
} |
2352
|
|
|
|
|
|
|
|
2353
|
2
|
|
|
|
|
6
|
return( $class, @traits ); |
2354
|
|
|
|
|
|
|
} |
2355
|
|
|
|
|
|
|
|
2356
|
|
|
|
|
|
|
sub _coerce_and_verify { |
2357
|
|
|
|
|
|
|
#my($self, $value, $instance) = @_; |
2358
|
4
|
|
|
4
|
|
10
|
my($self, $value) = @_; |
2359
|
|
|
|
|
|
|
|
2360
|
4
|
|
|
|
|
12
|
my $type_constraint = $self->{type_constraint}; |
2361
|
4
|
50
|
|
|
|
180
|
return $value if !defined $type_constraint; |
2362
|
|
|
|
|
|
|
|
2363
|
0
|
0
|
0
|
|
|
0
|
if ($self->should_coerce && $type_constraint->has_coercion) { |
2364
|
0
|
|
|
|
|
0
|
$value = $type_constraint->coerce($value); |
2365
|
|
|
|
|
|
|
} |
2366
|
|
|
|
|
|
|
|
2367
|
0
|
|
|
|
|
0
|
$self->verify_against_type_constraint($value); |
2368
|
|
|
|
|
|
|
|
2369
|
0
|
|
|
|
|
0
|
return $value; |
2370
|
|
|
|
|
|
|
} |
2371
|
|
|
|
|
|
|
|
2372
|
|
|
|
|
|
|
sub verify_against_type_constraint { |
2373
|
0
|
|
|
0
|
0
|
0
|
my ($self, $value) = @_; |
2374
|
|
|
|
|
|
|
|
2375
|
0
|
|
|
|
|
0
|
my $type_constraint = $self->{type_constraint}; |
2376
|
0
|
0
|
|
|
|
0
|
return 1 if !$type_constraint; |
2377
|
0
|
0
|
|
|
|
0
|
return 1 if $type_constraint->check($value); |
2378
|
|
|
|
|
|
|
|
2379
|
0
|
|
|
|
|
0
|
$self->_throw_type_constraint_error($value, $type_constraint); |
2380
|
|
|
|
|
|
|
} |
2381
|
|
|
|
|
|
|
|
2382
|
|
|
|
|
|
|
sub _throw_type_constraint_error { |
2383
|
0
|
|
|
0
|
|
0
|
my($self, $value, $type) = @_; |
2384
|
|
|
|
|
|
|
|
2385
|
0
|
|
|
|
|
0
|
$self->throw_error( |
2386
|
|
|
|
|
|
|
sprintf q{Attribute (%s) does not pass the type constraint because: %s}, |
2387
|
|
|
|
|
|
|
$self->name, |
2388
|
|
|
|
|
|
|
$type->get_message($value), |
2389
|
|
|
|
|
|
|
); |
2390
|
|
|
|
|
|
|
} |
2391
|
|
|
|
|
|
|
|
2392
|
|
|
|
|
|
|
sub illegal_options_for_inheritance { |
2393
|
0
|
|
|
0
|
0
|
0
|
return qw(reader writer accessor clearer predicate); |
2394
|
|
|
|
|
|
|
} |
2395
|
|
|
|
|
|
|
|
2396
|
|
|
|
|
|
|
sub clone_and_inherit_options{ |
2397
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
2398
|
0
|
|
|
|
|
0
|
my $args = $self->Scalar::Random::PP::OO::Object::BUILDARGS(@_); |
2399
|
|
|
|
|
|
|
|
2400
|
0
|
|
|
|
|
0
|
foreach my $illegal($self->illegal_options_for_inheritance) { |
2401
|
0
|
0
|
0
|
|
|
0
|
if(exists $args->{$illegal} and exists $self->{$illegal}) { |
2402
|
0
|
|
|
|
|
0
|
$self->throw_error("Illegal inherited option: $illegal"); |
2403
|
|
|
|
|
|
|
} |
2404
|
|
|
|
|
|
|
} |
2405
|
|
|
|
|
|
|
|
2406
|
0
|
|
|
|
|
0
|
foreach my $name(keys %{$self}){ |
|
0
|
|
|
|
|
0
|
|
2407
|
0
|
0
|
|
|
|
0
|
if(!exists $args->{$name}){ |
2408
|
0
|
|
|
|
|
0
|
$args->{$name} = $self->{$name}; # inherit from self |
2409
|
|
|
|
|
|
|
} |
2410
|
|
|
|
|
|
|
} |
2411
|
|
|
|
|
|
|
|
2412
|
0
|
|
|
|
|
0
|
my($attribute_class, @traits) = ref($self)->interpolate_class($args); |
2413
|
0
|
0
|
|
|
|
0
|
$args->{traits} = \@traits if @traits; |
2414
|
|
|
|
|
|
|
|
2415
|
|
|
|
|
|
|
# remove temporary caches |
2416
|
0
|
|
|
|
|
0
|
foreach my $attr(keys %{$args}){ |
|
0
|
|
|
|
|
0
|
|
2417
|
0
|
0
|
|
|
|
0
|
if($attr =~ /\A _/xms){ |
2418
|
0
|
|
|
|
|
0
|
delete $args->{$attr}; |
2419
|
|
|
|
|
|
|
} |
2420
|
|
|
|
|
|
|
} |
2421
|
|
|
|
|
|
|
|
2422
|
|
|
|
|
|
|
# remove default if lazy_build => 1 |
2423
|
0
|
0
|
|
|
|
0
|
if($args->{lazy_build}) { |
2424
|
0
|
|
|
|
|
0
|
delete $args->{default}; |
2425
|
|
|
|
|
|
|
} |
2426
|
|
|
|
|
|
|
|
2427
|
0
|
|
|
|
|
0
|
return $attribute_class->new($self->name, $args); |
2428
|
|
|
|
|
|
|
} |
2429
|
|
|
|
|
|
|
|
2430
|
|
|
|
|
|
|
sub get_read_method { |
2431
|
0
|
|
0
|
0
|
0
|
0
|
return $_[0]->reader || $_[0]->accessor |
2432
|
|
|
|
|
|
|
} |
2433
|
|
|
|
|
|
|
sub get_write_method { |
2434
|
0
|
|
0
|
0
|
0
|
0
|
return $_[0]->writer || $_[0]->accessor |
2435
|
|
|
|
|
|
|
} |
2436
|
|
|
|
|
|
|
|
2437
|
|
|
|
|
|
|
sub _get_accessor_method_ref { |
2438
|
0
|
|
|
0
|
|
0
|
my($self, $type, $generator) = @_; |
2439
|
|
|
|
|
|
|
|
2440
|
0
|
|
0
|
|
|
0
|
my $metaclass = $self->associated_class |
2441
|
|
|
|
|
|
|
|| $self->throw_error('No asocciated class for ' . $self->name); |
2442
|
|
|
|
|
|
|
|
2443
|
0
|
|
|
|
|
0
|
my $accessor = $self->$type(); |
2444
|
0
|
0
|
|
|
|
0
|
if($accessor){ |
2445
|
0
|
|
|
|
|
0
|
return $metaclass->get_method_body($accessor); |
2446
|
|
|
|
|
|
|
} |
2447
|
|
|
|
|
|
|
else{ |
2448
|
0
|
|
|
|
|
0
|
return $self->accessor_metaclass->$generator($self, $metaclass); |
2449
|
|
|
|
|
|
|
} |
2450
|
|
|
|
|
|
|
} |
2451
|
|
|
|
|
|
|
|
2452
|
|
|
|
|
|
|
sub get_read_method_ref{ |
2453
|
0
|
|
|
0
|
0
|
0
|
my($self) = @_; |
2454
|
0
|
|
0
|
|
|
0
|
return $self->{_read_method_ref} ||= $self->_get_accessor_method_ref('get_read_method', '_generate_reader'); |
2455
|
|
|
|
|
|
|
} |
2456
|
|
|
|
|
|
|
|
2457
|
|
|
|
|
|
|
sub get_write_method_ref{ |
2458
|
0
|
|
|
0
|
0
|
0
|
my($self) = @_; |
2459
|
0
|
|
0
|
|
|
0
|
return $self->{_write_method_ref} ||= $self->_get_accessor_method_ref('get_write_method', '_generate_writer'); |
2460
|
|
|
|
|
|
|
} |
2461
|
|
|
|
|
|
|
|
2462
|
|
|
|
|
|
|
sub set_value { |
2463
|
0
|
|
|
0
|
0
|
0
|
my($self, $object, $value) = @_; |
2464
|
0
|
|
|
|
|
0
|
return $self->get_write_method_ref()->($object, $value); |
2465
|
|
|
|
|
|
|
} |
2466
|
|
|
|
|
|
|
|
2467
|
|
|
|
|
|
|
sub get_value { |
2468
|
0
|
|
|
0
|
0
|
0
|
my($self, $object) = @_; |
2469
|
0
|
|
|
|
|
0
|
return $self->get_read_method_ref()->($object); |
2470
|
|
|
|
|
|
|
} |
2471
|
|
|
|
|
|
|
|
2472
|
|
|
|
|
|
|
sub has_value { |
2473
|
0
|
|
|
0
|
0
|
0
|
my($self, $object) = @_; |
2474
|
0
|
|
0
|
|
|
0
|
my $accessor_ref = $self->{_predicate_ref} |
2475
|
|
|
|
|
|
|
||= $self->_get_accessor_method_ref('predicate', '_generate_predicate'); |
2476
|
|
|
|
|
|
|
|
2477
|
0
|
|
|
|
|
0
|
return $accessor_ref->($object); |
2478
|
|
|
|
|
|
|
} |
2479
|
|
|
|
|
|
|
|
2480
|
|
|
|
|
|
|
sub clear_value { |
2481
|
0
|
|
|
0
|
0
|
0
|
my($self, $object) = @_; |
2482
|
0
|
|
0
|
|
|
0
|
my $accessor_ref = $self->{_crealer_ref} |
2483
|
|
|
|
|
|
|
||= $self->_get_accessor_method_ref('clearer', '_generate_clearer'); |
2484
|
|
|
|
|
|
|
|
2485
|
0
|
|
|
|
|
0
|
return $accessor_ref->($object); |
2486
|
|
|
|
|
|
|
} |
2487
|
|
|
|
|
|
|
|
2488
|
|
|
|
|
|
|
|
2489
|
|
|
|
|
|
|
sub associate_method{ |
2490
|
|
|
|
|
|
|
#my($attribute, $method_name) = @_; |
2491
|
2
|
|
|
2
|
0
|
4
|
my($attribute) = @_; |
2492
|
2
|
|
|
|
|
5
|
$attribute->{associated_methods}++; |
2493
|
2
|
|
|
|
|
6
|
return; |
2494
|
|
|
|
|
|
|
} |
2495
|
|
|
|
|
|
|
|
2496
|
|
|
|
|
|
|
sub install_accessors{ |
2497
|
2
|
|
|
2
|
0
|
4
|
my($attribute) = @_; |
2498
|
|
|
|
|
|
|
|
2499
|
2
|
|
|
|
|
10
|
my $metaclass = $attribute->associated_class; |
2500
|
2
|
|
|
|
|
10
|
my $accessor_class = $attribute->accessor_metaclass; |
2501
|
|
|
|
|
|
|
|
2502
|
2
|
|
|
|
|
7
|
foreach my $type(qw(accessor reader writer predicate clearer)){ |
2503
|
10
|
100
|
|
|
|
29
|
if(exists $attribute->{$type}){ |
2504
|
2
|
|
|
|
|
6
|
my $generator = '_generate_' . $type; |
2505
|
2
|
|
|
|
|
21
|
my $code = $accessor_class->$generator($attribute, $metaclass); |
2506
|
2
|
|
|
|
|
9
|
$metaclass->add_method($attribute->{$type} => $code); |
2507
|
2
|
|
|
|
|
9
|
$attribute->associate_method($attribute->{$type}); |
2508
|
|
|
|
|
|
|
} |
2509
|
|
|
|
|
|
|
} |
2510
|
|
|
|
|
|
|
|
2511
|
|
|
|
|
|
|
# install delegation |
2512
|
2
|
50
|
|
|
|
9
|
if(exists $attribute->{handles}){ |
2513
|
0
|
|
|
|
|
0
|
my %handles = $attribute->_canonicalize_handles($attribute->{handles}); |
2514
|
|
|
|
|
|
|
|
2515
|
0
|
|
|
|
|
0
|
while(my($handle, $method_to_call) = each %handles){ |
2516
|
0
|
0
|
|
|
|
0
|
if($metaclass->has_method($handle)) { |
2517
|
0
|
|
|
|
|
0
|
$attribute->throw_error("You cannot overwrite a locally defined method ($handle) with a delegation"); |
2518
|
|
|
|
|
|
|
} |
2519
|
|
|
|
|
|
|
|
2520
|
0
|
|
|
|
|
0
|
$metaclass->add_method($handle => |
2521
|
|
|
|
|
|
|
$attribute->_make_delegation_method( |
2522
|
|
|
|
|
|
|
$handle, $method_to_call)); |
2523
|
|
|
|
|
|
|
|
2524
|
0
|
|
|
|
|
0
|
$attribute->associate_method($handle); |
2525
|
|
|
|
|
|
|
} |
2526
|
|
|
|
|
|
|
} |
2527
|
|
|
|
|
|
|
|
2528
|
2
|
|
|
|
|
3
|
return; |
2529
|
|
|
|
|
|
|
} |
2530
|
|
|
|
|
|
|
|
2531
|
|
|
|
|
|
|
sub delegation_metaclass() { ## no critic |
2532
|
|
|
|
|
|
|
'Scalar::Random::PP::OO::Meta::Method::Delegation' |
2533
|
|
|
|
|
|
|
} |
2534
|
|
|
|
|
|
|
|
2535
|
|
|
|
|
|
|
sub _canonicalize_handles { |
2536
|
0
|
|
|
0
|
|
0
|
my($self, $handles) = @_; |
2537
|
|
|
|
|
|
|
|
2538
|
0
|
0
|
|
|
|
0
|
if (ref($handles) eq 'HASH') { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
2539
|
0
|
|
|
|
|
0
|
return %$handles; |
2540
|
|
|
|
|
|
|
} |
2541
|
|
|
|
|
|
|
elsif (ref($handles) eq 'ARRAY') { |
2542
|
0
|
|
|
|
|
0
|
return map { $_ => $_ } @$handles; |
|
0
|
|
|
|
|
0
|
|
2543
|
|
|
|
|
|
|
} |
2544
|
|
|
|
|
|
|
elsif ( ref($handles) eq 'CODE' ) { |
2545
|
0
|
|
0
|
|
|
0
|
my $class_or_role = ( $self->{isa} || $self->{does} ) |
2546
|
|
|
|
|
|
|
|| $self->throw_error( "Cannot find delegate metaclass for attribute " . $self->name ); |
2547
|
0
|
|
|
|
|
0
|
return $handles->( $self, Scalar::Random::PP::OO::Meta::Class->initialize("$class_or_role")); |
2548
|
|
|
|
|
|
|
} |
2549
|
|
|
|
|
|
|
elsif (ref($handles) eq 'Regexp') { |
2550
|
0
|
|
0
|
|
|
0
|
my $class_or_role = ($self->{isa} || $self->{does}) |
2551
|
|
|
|
|
|
|
|| $self->throw_error("Cannot delegate methods based on a Regexp without a type constraint (isa)"); |
2552
|
|
|
|
|
|
|
|
2553
|
0
|
|
|
|
|
0
|
my $meta = Scalar::Random::PP::OO::Meta::Class->initialize("$class_or_role"); # "" for stringify |
2554
|
0
|
0
|
|
|
|
0
|
return map { $_ => $_ } |
|
0
|
|
|
|
|
0
|
|
2555
|
0
|
0
|
|
|
|
0
|
grep { !Scalar::Random::PP::OO::Object->can($_) && $_ =~ $handles } |
2556
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Util::is_a_metarole($meta) |
2557
|
|
|
|
|
|
|
? $meta->get_method_list |
2558
|
|
|
|
|
|
|
: $meta->get_all_method_names; |
2559
|
|
|
|
|
|
|
} |
2560
|
|
|
|
|
|
|
else { |
2561
|
0
|
|
|
|
|
0
|
$self->throw_error("Unable to canonicalize the 'handles' option with $handles"); |
2562
|
|
|
|
|
|
|
} |
2563
|
|
|
|
|
|
|
} |
2564
|
|
|
|
|
|
|
|
2565
|
|
|
|
|
|
|
sub _make_delegation_method { |
2566
|
0
|
|
|
0
|
|
0
|
my($self, $handle, $method_to_call) = @_; |
2567
|
0
|
|
|
|
|
0
|
return Scalar::Random::PP::OO::Util::load_class($self->delegation_metaclass) |
2568
|
|
|
|
|
|
|
->_generate_delegation($self, $handle, $method_to_call); |
2569
|
|
|
|
|
|
|
} |
2570
|
|
|
|
|
|
|
|
2571
|
|
|
|
|
|
|
sub throw_error{ |
2572
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
2573
|
|
|
|
|
|
|
|
2574
|
0
|
|
0
|
|
|
0
|
my $metaclass = (ref $self && $self->associated_class) || 'Scalar::Random::PP::OO::Meta::Class'; |
2575
|
0
|
|
|
|
|
0
|
$metaclass->throw_error(@_, depth => 1); |
2576
|
|
|
|
|
|
|
} |
2577
|
|
|
|
|
|
|
|
2578
|
|
|
|
|
|
|
# Contents of Mouse::Meta::Class |
2579
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Class; |
2580
|
2
|
|
|
2
|
|
12
|
use Scalar::Random::PP::OO::Util qw/:meta get_linear_isa not_supported/; # enables strict and warnings |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
12
|
|
2581
|
2
|
|
|
2
|
|
10
|
no warnings 'once'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
91
|
|
2582
|
|
|
|
|
|
|
|
2583
|
2
|
|
|
2
|
|
20
|
use Scalar::Util qw/blessed weaken/; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
117
|
|
2584
|
|
|
|
|
|
|
|
2585
|
2
|
|
|
2
|
|
10
|
use Scalar::Random::PP::OO::Meta::Module; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
282
|
|
2586
|
|
|
|
|
|
|
our @ISA = qw(Scalar::Random::PP::OO::Meta::Module); |
2587
|
|
|
|
|
|
|
|
2588
|
|
|
|
|
|
|
our @CARP_NOT = qw(Scalar::Random::PP::OO); # trust Mousse |
2589
|
|
|
|
|
|
|
|
2590
|
|
|
|
|
|
|
sub attribute_metaclass; |
2591
|
|
|
|
|
|
|
sub method_metaclass; |
2592
|
|
|
|
|
|
|
|
2593
|
|
|
|
|
|
|
sub constructor_class; |
2594
|
|
|
|
|
|
|
sub destructor_class; |
2595
|
|
|
|
|
|
|
|
2596
|
|
|
|
|
|
|
|
2597
|
|
|
|
|
|
|
sub _construct_meta { |
2598
|
4
|
|
|
4
|
|
14
|
my($class, %args) = @_; |
2599
|
|
|
|
|
|
|
|
2600
|
4
|
|
|
|
|
13
|
$args{attributes} = {}; |
2601
|
4
|
|
|
|
|
12
|
$args{methods} = {}; |
2602
|
4
|
|
|
|
|
10
|
$args{roles} = []; |
2603
|
|
|
|
|
|
|
|
2604
|
4
|
|
|
|
|
6
|
$args{superclasses} = do { |
2605
|
2
|
|
|
2
|
|
11
|
no strict 'refs'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
5738
|
|
2606
|
4
|
|
|
|
|
8
|
\@{ $args{package} . '::ISA' }; |
|
4
|
|
|
|
|
98
|
|
2607
|
|
|
|
|
|
|
}; |
2608
|
|
|
|
|
|
|
|
2609
|
4
|
|
66
|
|
|
29
|
my $self = bless \%args, ref($class) || $class; |
2610
|
4
|
50
|
|
|
|
18
|
if(ref($self) ne __PACKAGE__){ |
2611
|
0
|
|
|
|
|
0
|
$self->meta->_initialize_object($self, \%args); |
2612
|
|
|
|
|
|
|
} |
2613
|
4
|
|
|
|
|
37
|
return $self; |
2614
|
|
|
|
|
|
|
} |
2615
|
|
|
|
|
|
|
|
2616
|
|
|
|
|
|
|
sub create_anon_class{ |
2617
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
2618
|
0
|
|
|
|
|
0
|
return $self->create(undef, @_); |
2619
|
|
|
|
|
|
|
} |
2620
|
|
|
|
|
|
|
|
2621
|
|
|
|
|
|
|
sub is_anon_class; |
2622
|
|
|
|
|
|
|
|
2623
|
|
|
|
|
|
|
sub roles; |
2624
|
|
|
|
|
|
|
|
2625
|
|
|
|
|
|
|
sub calculate_all_roles { |
2626
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
2627
|
0
|
|
|
|
|
0
|
my %seen; |
2628
|
0
|
|
|
|
|
0
|
return grep { !$seen{ $_->name }++ } |
|
0
|
|
|
|
|
0
|
|
2629
|
0
|
|
|
|
|
0
|
map { $_->calculate_all_roles } @{ $self->roles }; |
|
0
|
|
|
|
|
0
|
|
2630
|
|
|
|
|
|
|
} |
2631
|
|
|
|
|
|
|
|
2632
|
|
|
|
|
|
|
sub superclasses { |
2633
|
4
|
|
|
4
|
0
|
6
|
my $self = shift; |
2634
|
|
|
|
|
|
|
|
2635
|
4
|
100
|
|
|
|
11
|
if (@_) { |
2636
|
2
|
|
|
|
|
5
|
foreach my $super(@_){ |
2637
|
2
|
|
|
|
|
7
|
Scalar::Random::PP::OO::Util::load_class($super); |
2638
|
2
|
|
|
|
|
7
|
my $meta = Scalar::Random::PP::OO::Util::get_metaclass_by_name($super); |
2639
|
|
|
|
|
|
|
|
2640
|
2
|
50
|
|
|
|
9
|
next if not defined $meta; |
2641
|
|
|
|
|
|
|
|
2642
|
0
|
0
|
|
|
|
0
|
if(Scalar::Random::PP::OO::Util::is_a_metarole($meta)){ |
2643
|
0
|
|
|
|
|
0
|
$self->throw_error("You cannot inherit from a Scalar::Random::PP::OO Role ($super)"); |
2644
|
|
|
|
|
|
|
} |
2645
|
|
|
|
|
|
|
|
2646
|
0
|
0
|
|
|
|
0
|
next if $self->isa(ref $meta); # _superclass_meta_is_compatible |
2647
|
|
|
|
|
|
|
|
2648
|
0
|
|
|
|
|
0
|
$self->_reconcile_with_superclass_meta($meta); |
2649
|
|
|
|
|
|
|
} |
2650
|
2
|
|
|
|
|
4
|
@{ $self->{superclasses} } = @_; |
|
2
|
|
|
|
|
34
|
|
2651
|
|
|
|
|
|
|
} |
2652
|
|
|
|
|
|
|
|
2653
|
4
|
|
|
|
|
7
|
return @{ $self->{superclasses} }; |
|
4
|
|
|
|
|
16
|
|
2654
|
|
|
|
|
|
|
} |
2655
|
|
|
|
|
|
|
my @MetaClassTypes = ( |
2656
|
|
|
|
|
|
|
'attribute', # Scalar::Random::PP::OO::Meta::Attribute |
2657
|
|
|
|
|
|
|
'method', # Scalar::Random::PP::OO::Meta::Method |
2658
|
|
|
|
|
|
|
'constructor', # Scalar::Random::PP::OO::Meta::Method::Constructor |
2659
|
|
|
|
|
|
|
'destructor', # Scalar::Random::PP::OO::Meta::Method::Destructor |
2660
|
|
|
|
|
|
|
); |
2661
|
|
|
|
|
|
|
|
2662
|
|
|
|
|
|
|
sub _reconcile_with_superclass_meta { |
2663
|
0
|
|
|
0
|
|
0
|
my($self, $other) = @_; |
2664
|
|
|
|
|
|
|
|
2665
|
|
|
|
|
|
|
# find incompatible traits |
2666
|
0
|
|
|
|
|
0
|
my %metaroles; |
2667
|
0
|
|
|
|
|
0
|
foreach my $metaclass_type(@MetaClassTypes){ |
2668
|
0
|
|
0
|
|
|
0
|
my $accessor = $self->can($metaclass_type . '_metaclass') |
2669
|
|
|
|
|
|
|
|| $self->can($metaclass_type . '_class'); |
2670
|
|
|
|
|
|
|
|
2671
|
0
|
|
|
|
|
0
|
my $other_c = $other->$accessor(); |
2672
|
0
|
|
|
|
|
0
|
my $self_c = $self->$accessor(); |
2673
|
|
|
|
|
|
|
|
2674
|
0
|
0
|
|
|
|
0
|
if(!$self_c->isa($other_c)){ |
2675
|
0
|
|
|
|
|
0
|
$metaroles{$metaclass_type} |
2676
|
|
|
|
|
|
|
= [ $self_c->meta->_collect_roles($other_c->meta) ]; |
2677
|
|
|
|
|
|
|
} |
2678
|
|
|
|
|
|
|
} |
2679
|
|
|
|
|
|
|
|
2680
|
0
|
|
|
|
|
0
|
$metaroles{class} = [$self->meta->_collect_roles($other->meta)]; |
2681
|
|
|
|
|
|
|
|
2682
|
|
|
|
|
|
|
#use Data::Dumper; print Data::Dumper->new([\%metaroles], ['*metaroles'])->Indent(1)->Dump; |
2683
|
|
|
|
|
|
|
|
2684
|
0
|
|
|
|
|
0
|
require Scalar::Random::PP::OO::Util::MetaRole; |
2685
|
0
|
|
|
|
|
0
|
$_[0] = Scalar::Random::PP::OO::Util::MetaRole::apply_metaroles( |
2686
|
|
|
|
|
|
|
for => $self, |
2687
|
|
|
|
|
|
|
class_metaroles => \%metaroles, |
2688
|
|
|
|
|
|
|
); |
2689
|
0
|
|
|
|
|
0
|
return; |
2690
|
|
|
|
|
|
|
} |
2691
|
|
|
|
|
|
|
|
2692
|
|
|
|
|
|
|
sub _collect_roles { |
2693
|
0
|
|
|
0
|
|
0
|
my ($self, $other) = @_; |
2694
|
|
|
|
|
|
|
|
2695
|
|
|
|
|
|
|
# find common ancestor |
2696
|
0
|
|
|
|
|
0
|
my @self_lin_isa = $self->linearized_isa; |
2697
|
0
|
|
|
|
|
0
|
my @other_lin_isa = $other->linearized_isa; |
2698
|
|
|
|
|
|
|
|
2699
|
0
|
|
|
|
|
0
|
my(@self_anon_supers, @other_anon_supers); |
2700
|
0
|
|
|
|
|
0
|
push @self_anon_supers, shift @self_lin_isa while $self_lin_isa[0]->meta->is_anon_class; |
2701
|
0
|
|
|
|
|
0
|
push @other_anon_supers, shift @other_lin_isa while $other_lin_isa[0]->meta->is_anon_class; |
2702
|
|
|
|
|
|
|
|
2703
|
0
|
|
0
|
|
|
0
|
my $common_ancestor = $self_lin_isa[0] eq $other_lin_isa[0] && $self_lin_isa[0]; |
2704
|
|
|
|
|
|
|
|
2705
|
0
|
0
|
|
|
|
0
|
if(!$common_ancestor){ |
2706
|
0
|
|
|
|
|
0
|
$self->throw_error(sprintf '%s cannot have %s as a super class because of their metaclass incompatibility', |
2707
|
|
|
|
|
|
|
$self->name, $other->name); |
2708
|
|
|
|
|
|
|
} |
2709
|
|
|
|
|
|
|
|
2710
|
0
|
|
|
|
|
0
|
my %seen; |
2711
|
0
|
|
|
|
|
0
|
return sort grep { !$seen{$_}++ } ## no critic |
|
0
|
|
|
|
|
0
|
|
2712
|
0
|
|
|
|
|
0
|
(map{ $_->name } map{ $_->meta->calculate_all_roles } @self_anon_supers), |
|
0
|
|
|
|
|
0
|
|
2713
|
0
|
|
|
|
|
0
|
(map{ $_->name } map{ $_->meta->calculate_all_roles } @other_anon_supers), |
|
0
|
|
|
|
|
0
|
|
2714
|
|
|
|
|
|
|
; |
2715
|
|
|
|
|
|
|
} |
2716
|
|
|
|
|
|
|
|
2717
|
|
|
|
|
|
|
|
2718
|
|
|
|
|
|
|
sub find_method_by_name{ |
2719
|
0
|
|
|
0
|
0
|
0
|
my($self, $method_name) = @_; |
2720
|
0
|
0
|
|
|
|
0
|
defined($method_name) |
2721
|
|
|
|
|
|
|
or $self->throw_error('You must define a method name to find'); |
2722
|
|
|
|
|
|
|
|
2723
|
0
|
|
|
|
|
0
|
foreach my $class( $self->linearized_isa ){ |
2724
|
0
|
|
|
|
|
0
|
my $method = $self->initialize($class)->get_method($method_name); |
2725
|
0
|
0
|
|
|
|
0
|
return $method if defined $method; |
2726
|
|
|
|
|
|
|
} |
2727
|
0
|
|
|
|
|
0
|
return undef; |
2728
|
|
|
|
|
|
|
} |
2729
|
|
|
|
|
|
|
|
2730
|
|
|
|
|
|
|
sub get_all_methods { |
2731
|
0
|
|
|
0
|
0
|
0
|
my($self) = @_; |
2732
|
0
|
|
|
|
|
0
|
return map{ $self->find_method_by_name($_) } $self->get_all_method_names; |
|
0
|
|
|
|
|
0
|
|
2733
|
|
|
|
|
|
|
} |
2734
|
|
|
|
|
|
|
|
2735
|
|
|
|
|
|
|
sub get_all_method_names { |
2736
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
2737
|
0
|
|
|
|
|
0
|
my %uniq; |
2738
|
0
|
|
|
|
|
0
|
return grep { $uniq{$_}++ == 0 } |
|
0
|
|
|
|
|
0
|
|
2739
|
0
|
|
|
|
|
0
|
map { Scalar::Random::PP::OO::Meta::Class->initialize($_)->get_method_list() } |
2740
|
|
|
|
|
|
|
$self->linearized_isa; |
2741
|
|
|
|
|
|
|
} |
2742
|
|
|
|
|
|
|
|
2743
|
|
|
|
|
|
|
sub find_attribute_by_name{ |
2744
|
0
|
|
|
0
|
0
|
0
|
my($self, $name) = @_; |
2745
|
0
|
|
|
|
|
0
|
my $attr; |
2746
|
0
|
|
|
|
|
0
|
foreach my $class($self->linearized_isa){ |
2747
|
0
|
0
|
|
|
|
0
|
my $meta = Scalar::Random::PP::OO::Util::get_metaclass_by_name($class) or next; |
2748
|
0
|
0
|
|
|
|
0
|
$attr = $meta->get_attribute($name) and last; |
2749
|
|
|
|
|
|
|
} |
2750
|
0
|
|
|
|
|
0
|
return $attr; |
2751
|
|
|
|
|
|
|
} |
2752
|
|
|
|
|
|
|
|
2753
|
|
|
|
|
|
|
sub add_attribute { |
2754
|
2
|
|
|
2
|
0
|
5
|
my $self = shift; |
2755
|
|
|
|
|
|
|
|
2756
|
2
|
|
|
|
|
4
|
my($attr, $name); |
2757
|
|
|
|
|
|
|
|
2758
|
2
|
50
|
|
|
|
10
|
if(blessed $_[0]){ |
2759
|
0
|
|
|
|
|
0
|
$attr = $_[0]; |
2760
|
|
|
|
|
|
|
|
2761
|
0
|
0
|
|
|
|
0
|
$attr->isa('Scalar::Random::PP::OO::Meta::Attribute') |
2762
|
|
|
|
|
|
|
|| $self->throw_error("Your attribute must be an instance of Scalar::Random::PP::OO::Meta::Attribute (or a subclass)"); |
2763
|
|
|
|
|
|
|
|
2764
|
0
|
|
|
|
|
0
|
$name = $attr->name; |
2765
|
|
|
|
|
|
|
} |
2766
|
|
|
|
|
|
|
else{ |
2767
|
|
|
|
|
|
|
# _process_attribute |
2768
|
2
|
|
|
|
|
5
|
$name = shift; |
2769
|
|
|
|
|
|
|
|
2770
|
2
|
50
|
|
|
|
11
|
my %args = (@_ == 1) ? %{$_[0]} : @_; |
|
0
|
|
|
|
|
0
|
|
2771
|
|
|
|
|
|
|
|
2772
|
2
|
50
|
|
|
|
7
|
defined($name) |
2773
|
|
|
|
|
|
|
or $self->throw_error('You must provide a name for the attribute'); |
2774
|
|
|
|
|
|
|
|
2775
|
2
|
50
|
|
|
|
9
|
if ($name =~ s/^\+//) { # inherited attributes |
2776
|
0
|
0
|
|
|
|
0
|
my $inherited_attr = $self->find_attribute_by_name($name) |
2777
|
|
|
|
|
|
|
or $self->throw_error("Could not find an attribute by the name of '$name' to inherit from in ".$self->name); |
2778
|
|
|
|
|
|
|
|
2779
|
0
|
|
|
|
|
0
|
$attr = $inherited_attr->clone_and_inherit_options(%args); |
2780
|
|
|
|
|
|
|
} |
2781
|
|
|
|
|
|
|
else{ |
2782
|
2
|
|
|
|
|
9
|
my($attribute_class, @traits) = $self->attribute_metaclass->interpolate_class(\%args); |
2783
|
2
|
50
|
|
|
|
8
|
$args{traits} = \@traits if @traits; |
2784
|
|
|
|
|
|
|
|
2785
|
2
|
|
|
|
|
11
|
$attr = $attribute_class->new($name, %args); |
2786
|
|
|
|
|
|
|
} |
2787
|
|
|
|
|
|
|
} |
2788
|
|
|
|
|
|
|
|
2789
|
2
|
|
|
|
|
18
|
weaken( $attr->{associated_class} = $self ); |
2790
|
|
|
|
|
|
|
|
2791
|
|
|
|
|
|
|
# install accessors first |
2792
|
2
|
|
|
|
|
11
|
$attr->install_accessors(); |
2793
|
|
|
|
|
|
|
|
2794
|
|
|
|
|
|
|
# then register the attribute to the metaclass |
2795
|
2
|
|
|
|
|
3
|
$attr->{insertion_order} = keys %{ $self->{attributes} }; |
|
2
|
|
|
|
|
8
|
|
2796
|
2
|
|
|
|
|
7
|
$self->{attributes}{$attr->name} = $attr; |
2797
|
|
|
|
|
|
|
|
2798
|
2
|
50
|
0
|
|
|
11
|
if(!$attr->{associated_methods} && ($attr->{is} || '') ne 'bare'){ |
|
|
|
33
|
|
|
|
|
2799
|
0
|
|
|
|
|
0
|
Carp::carp(qq{Attribute ($name) of class }.$self->name |
2800
|
|
|
|
|
|
|
.qq{ has no associated methods (did you mean to provide an "is" argument?)}); |
2801
|
|
|
|
|
|
|
} |
2802
|
2
|
|
|
|
|
4
|
return $attr; |
2803
|
|
|
|
|
|
|
} |
2804
|
|
|
|
|
|
|
|
2805
|
|
|
|
|
|
|
sub linearized_isa; |
2806
|
|
|
|
|
|
|
|
2807
|
|
|
|
|
|
|
sub new_object; |
2808
|
|
|
|
|
|
|
sub clone_object; |
2809
|
|
|
|
|
|
|
|
2810
|
|
|
|
|
|
|
sub immutable_options { |
2811
|
0
|
|
|
0
|
0
|
0
|
my ( $self, @args ) = @_; |
2812
|
|
|
|
|
|
|
|
2813
|
|
|
|
|
|
|
return ( |
2814
|
0
|
|
|
|
|
0
|
inline_constructor => 1, |
2815
|
|
|
|
|
|
|
inline_destructor => 1, |
2816
|
|
|
|
|
|
|
constructor_name => 'new', |
2817
|
|
|
|
|
|
|
@args, |
2818
|
|
|
|
|
|
|
); |
2819
|
|
|
|
|
|
|
} |
2820
|
|
|
|
|
|
|
|
2821
|
|
|
|
|
|
|
sub make_immutable { |
2822
|
0
|
|
|
0
|
0
|
0
|
my $self = shift; |
2823
|
0
|
|
|
|
|
0
|
my %args = $self->immutable_options(@_); |
2824
|
|
|
|
|
|
|
|
2825
|
0
|
|
|
|
|
0
|
$self->{is_immutable}++; |
2826
|
|
|
|
|
|
|
|
2827
|
0
|
0
|
|
|
|
0
|
if ($args{inline_constructor}) { |
2828
|
0
|
|
|
|
|
0
|
$self->add_method($args{constructor_name} => |
2829
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Util::load_class($self->constructor_class) |
2830
|
|
|
|
|
|
|
->_generate_constructor($self, \%args)); |
2831
|
|
|
|
|
|
|
} |
2832
|
|
|
|
|
|
|
|
2833
|
0
|
0
|
|
|
|
0
|
if ($args{inline_destructor}) { |
2834
|
0
|
|
|
|
|
0
|
$self->add_method(DESTROY => |
2835
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Util::load_class($self->destructor_class) |
2836
|
|
|
|
|
|
|
->_generate_destructor($self, \%args)); |
2837
|
|
|
|
|
|
|
} |
2838
|
|
|
|
|
|
|
|
2839
|
|
|
|
|
|
|
# Moose's make_immutable returns true allowing calling code to skip setting an explicit true value |
2840
|
|
|
|
|
|
|
# at the end of a source file. |
2841
|
0
|
|
|
|
|
0
|
return 1; |
2842
|
|
|
|
|
|
|
} |
2843
|
|
|
|
|
|
|
|
2844
|
|
|
|
|
|
|
sub make_mutable { |
2845
|
0
|
|
|
0
|
0
|
0
|
my($self) = @_; |
2846
|
0
|
|
|
|
|
0
|
$self->{is_immutable} = 0; |
2847
|
0
|
|
|
|
|
0
|
return; |
2848
|
|
|
|
|
|
|
} |
2849
|
|
|
|
|
|
|
|
2850
|
|
|
|
|
|
|
sub is_immutable; |
2851
|
0
|
|
|
0
|
0
|
0
|
sub is_mutable { !$_[0]->is_immutable } |
2852
|
|
|
|
|
|
|
|
2853
|
|
|
|
|
|
|
sub _install_modifier { |
2854
|
0
|
|
|
0
|
|
0
|
my( $self, $type, $name, $code ) = @_; |
2855
|
0
|
|
|
|
|
0
|
my $into = $self->name; |
2856
|
|
|
|
|
|
|
|
2857
|
0
|
0
|
|
|
|
0
|
my $original = $into->can($name) |
2858
|
|
|
|
|
|
|
or $self->throw_error("The method '$name' was not found in the inheritance hierarchy for $into"); |
2859
|
|
|
|
|
|
|
|
2860
|
0
|
|
|
|
|
0
|
my $modifier_table = $self->{modifiers}{$name}; |
2861
|
|
|
|
|
|
|
|
2862
|
0
|
0
|
|
|
|
0
|
if(!$modifier_table){ |
2863
|
0
|
|
|
|
|
0
|
my(@before, @after, @around); |
2864
|
0
|
|
|
|
|
0
|
my $cache = $original; |
2865
|
|
|
|
|
|
|
my $modified = sub { |
2866
|
0
|
0
|
|
0
|
|
0
|
if(@before) { |
2867
|
0
|
|
|
|
|
0
|
for my $c (@before) { $c->(@_) } |
|
0
|
|
|
|
|
0
|
|
2868
|
|
|
|
|
|
|
} |
2869
|
0
|
0
|
|
|
|
0
|
unless(@after) { |
2870
|
0
|
|
|
|
|
0
|
return $cache->(@_); |
2871
|
|
|
|
|
|
|
} |
2872
|
|
|
|
|
|
|
|
2873
|
0
|
0
|
|
|
|
0
|
if(wantarray){ # list context |
|
|
0
|
|
|
|
|
|
2874
|
0
|
|
|
|
|
0
|
my @rval = $cache->(@_); |
2875
|
|
|
|
|
|
|
|
2876
|
0
|
|
|
|
|
0
|
for my $c(@after){ $c->(@_) } |
|
0
|
|
|
|
|
0
|
|
2877
|
0
|
|
|
|
|
0
|
return @rval; |
2878
|
|
|
|
|
|
|
} |
2879
|
|
|
|
|
|
|
elsif(defined wantarray){ # scalar context |
2880
|
0
|
|
|
|
|
0
|
my $rval = $cache->(@_); |
2881
|
|
|
|
|
|
|
|
2882
|
0
|
|
|
|
|
0
|
for my $c(@after){ $c->(@_) } |
|
0
|
|
|
|
|
0
|
|
2883
|
0
|
|
|
|
|
0
|
return $rval; |
2884
|
|
|
|
|
|
|
} |
2885
|
|
|
|
|
|
|
else{ # void context |
2886
|
0
|
|
|
|
|
0
|
$cache->(@_); |
2887
|
|
|
|
|
|
|
|
2888
|
0
|
|
|
|
|
0
|
for my $c(@after){ $c->(@_) } |
|
0
|
|
|
|
|
0
|
|
2889
|
0
|
|
|
|
|
0
|
return; |
2890
|
|
|
|
|
|
|
} |
2891
|
0
|
|
|
|
|
0
|
}; |
2892
|
|
|
|
|
|
|
|
2893
|
0
|
|
|
|
|
0
|
$self->{modifiers}{$name} = $modifier_table = { |
2894
|
|
|
|
|
|
|
original => $original, |
2895
|
|
|
|
|
|
|
|
2896
|
|
|
|
|
|
|
before => \@before, |
2897
|
|
|
|
|
|
|
after => \@after, |
2898
|
|
|
|
|
|
|
around => \@around, |
2899
|
|
|
|
|
|
|
|
2900
|
|
|
|
|
|
|
cache => \$cache, # cache for around modifiers |
2901
|
|
|
|
|
|
|
}; |
2902
|
|
|
|
|
|
|
|
2903
|
0
|
|
|
|
|
0
|
$self->add_method($name => $modified); |
2904
|
|
|
|
|
|
|
} |
2905
|
|
|
|
|
|
|
|
2906
|
0
|
0
|
|
|
|
0
|
if($type eq 'before'){ |
|
|
0
|
|
|
|
|
|
2907
|
0
|
|
|
|
|
0
|
unshift @{$modifier_table->{before}}, $code; |
|
0
|
|
|
|
|
0
|
|
2908
|
|
|
|
|
|
|
} |
2909
|
|
|
|
|
|
|
elsif($type eq 'after'){ |
2910
|
0
|
|
|
|
|
0
|
push @{$modifier_table->{after}}, $code; |
|
0
|
|
|
|
|
0
|
|
2911
|
|
|
|
|
|
|
} |
2912
|
|
|
|
|
|
|
else{ # around |
2913
|
0
|
|
|
|
|
0
|
push @{$modifier_table->{around}}, $code; |
|
0
|
|
|
|
|
0
|
|
2914
|
|
|
|
|
|
|
|
2915
|
0
|
|
|
|
|
0
|
my $next = ${ $modifier_table->{cache} }; |
|
0
|
|
|
|
|
0
|
|
2916
|
0
|
|
|
0
|
|
0
|
${ $modifier_table->{cache} } = sub{ $code->($next, @_) }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
2917
|
|
|
|
|
|
|
} |
2918
|
|
|
|
|
|
|
|
2919
|
0
|
|
|
|
|
0
|
return; |
2920
|
|
|
|
|
|
|
} |
2921
|
|
|
|
|
|
|
|
2922
|
|
|
|
|
|
|
sub add_before_method_modifier { |
2923
|
0
|
|
|
0
|
0
|
0
|
my ( $self, $name, $code ) = @_; |
2924
|
0
|
|
|
|
|
0
|
$self->_install_modifier( 'before', $name, $code ); |
2925
|
|
|
|
|
|
|
} |
2926
|
|
|
|
|
|
|
|
2927
|
|
|
|
|
|
|
sub add_around_method_modifier { |
2928
|
0
|
|
|
0
|
0
|
0
|
my ( $self, $name, $code ) = @_; |
2929
|
0
|
|
|
|
|
0
|
$self->_install_modifier( 'around', $name, $code ); |
2930
|
|
|
|
|
|
|
} |
2931
|
|
|
|
|
|
|
|
2932
|
|
|
|
|
|
|
sub add_after_method_modifier { |
2933
|
0
|
|
|
0
|
0
|
0
|
my ( $self, $name, $code ) = @_; |
2934
|
0
|
|
|
|
|
0
|
$self->_install_modifier( 'after', $name, $code ); |
2935
|
|
|
|
|
|
|
} |
2936
|
|
|
|
|
|
|
|
2937
|
|
|
|
|
|
|
sub add_override_method_modifier { |
2938
|
0
|
|
|
0
|
0
|
0
|
my ($self, $name, $code) = @_; |
2939
|
|
|
|
|
|
|
|
2940
|
0
|
0
|
|
|
|
0
|
if($self->has_method($name)){ |
2941
|
0
|
|
|
|
|
0
|
$self->throw_error("Cannot add an override method if a local method is already present"); |
2942
|
|
|
|
|
|
|
} |
2943
|
|
|
|
|
|
|
|
2944
|
0
|
|
|
|
|
0
|
my $package = $self->name; |
2945
|
|
|
|
|
|
|
|
2946
|
0
|
0
|
|
|
|
0
|
my $super_body = $package->can($name) |
2947
|
|
|
|
|
|
|
or $self->throw_error("You cannot override '$name' because it has no super method"); |
2948
|
|
|
|
|
|
|
|
2949
|
|
|
|
|
|
|
$self->add_method($name => sub { |
2950
|
0
|
|
|
0
|
|
0
|
local $Scalar::Random::PP::OO::SUPER_PACKAGE = $package; |
2951
|
0
|
|
|
|
|
0
|
local $Scalar::Random::PP::OO::SUPER_BODY = $super_body; |
2952
|
0
|
|
|
|
|
0
|
local @Scalar::Random::PP::OO::SUPER_ARGS = @_; |
2953
|
|
|
|
|
|
|
|
2954
|
0
|
|
|
|
|
0
|
$code->(@_); |
2955
|
0
|
|
|
|
|
0
|
}); |
2956
|
0
|
|
|
|
|
0
|
return; |
2957
|
|
|
|
|
|
|
} |
2958
|
|
|
|
|
|
|
|
2959
|
|
|
|
|
|
|
sub add_augment_method_modifier { |
2960
|
0
|
|
|
0
|
0
|
0
|
my ($self, $name, $code) = @_; |
2961
|
0
|
0
|
|
|
|
0
|
if($self->has_method($name)){ |
2962
|
0
|
|
|
|
|
0
|
$self->throw_error("Cannot add an augment method if a local method is already present"); |
2963
|
|
|
|
|
|
|
} |
2964
|
|
|
|
|
|
|
|
2965
|
0
|
0
|
|
|
|
0
|
my $super = $self->find_method_by_name($name) |
2966
|
|
|
|
|
|
|
or $self->throw_error("You cannot augment '$name' because it has no super method"); |
2967
|
|
|
|
|
|
|
|
2968
|
0
|
|
|
|
|
0
|
my $super_package = $super->package_name; |
2969
|
0
|
|
|
|
|
0
|
my $super_body = $super->body; |
2970
|
|
|
|
|
|
|
|
2971
|
|
|
|
|
|
|
$self->add_method($name => sub{ |
2972
|
0
|
|
|
0
|
|
0
|
local $Scalar::Random::PP::OO::INNER_BODY{$super_package} = $code; |
2973
|
0
|
|
|
|
|
0
|
local $Scalar::Random::PP::OO::INNER_ARGS{$super_package} = [@_]; |
2974
|
0
|
|
|
|
|
0
|
$super_body->(@_); |
2975
|
0
|
|
|
|
|
0
|
}); |
2976
|
0
|
|
|
|
|
0
|
return; |
2977
|
|
|
|
|
|
|
} |
2978
|
|
|
|
|
|
|
|
2979
|
|
|
|
|
|
|
sub does_role { |
2980
|
0
|
|
|
0
|
0
|
0
|
my ($self, $role_name) = @_; |
2981
|
|
|
|
|
|
|
|
2982
|
0
|
0
|
|
|
|
0
|
(defined $role_name) |
2983
|
|
|
|
|
|
|
|| $self->throw_error("You must supply a role name to look for"); |
2984
|
|
|
|
|
|
|
|
2985
|
0
|
0
|
|
|
|
0
|
$role_name = $role_name->name if ref $role_name; |
2986
|
|
|
|
|
|
|
|
2987
|
0
|
|
|
|
|
0
|
for my $class ($self->linearized_isa) { |
2988
|
0
|
0
|
|
|
|
0
|
my $meta = Scalar::Random::PP::OO::Util::get_metaclass_by_name($class) |
2989
|
|
|
|
|
|
|
or next; |
2990
|
|
|
|
|
|
|
|
2991
|
0
|
|
|
|
|
0
|
for my $role (@{ $meta->roles }) { |
|
0
|
|
|
|
|
0
|
|
2992
|
|
|
|
|
|
|
|
2993
|
0
|
0
|
|
|
|
0
|
return 1 if $role->does_role($role_name); |
2994
|
|
|
|
|
|
|
} |
2995
|
|
|
|
|
|
|
} |
2996
|
|
|
|
|
|
|
|
2997
|
0
|
|
|
|
|
0
|
return 0; |
2998
|
|
|
|
|
|
|
} |
2999
|
|
|
|
|
|
|
|
3000
|
|
|
|
|
|
|
# Contents of Mouse::Meta::Method |
3001
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Method; |
3002
|
2
|
|
|
2
|
|
12
|
use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
10
|
|
3003
|
2
|
|
|
2
|
|
18
|
use Scalar::Util (); |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
124
|
|
3004
|
|
|
|
|
|
|
|
3005
|
|
|
|
|
|
|
use overload |
3006
|
|
|
|
|
|
|
'==' => '_equal', |
3007
|
|
|
|
|
|
|
'eq' => '_equal', |
3008
|
0
|
|
|
0
|
|
0
|
'&{}' => sub{ $_[0]->body }, |
3009
|
2
|
|
|
|
|
23
|
fallback => 1, |
3010
|
2
|
|
|
2
|
|
15
|
; |
|
2
|
|
|
|
|
3
|
|
3011
|
|
|
|
|
|
|
|
3012
|
|
|
|
|
|
|
sub wrap{ |
3013
|
0
|
|
|
0
|
0
|
0
|
my $class = shift; |
3014
|
|
|
|
|
|
|
|
3015
|
0
|
|
|
|
|
0
|
return $class->_new(@_); |
3016
|
|
|
|
|
|
|
} |
3017
|
|
|
|
|
|
|
|
3018
|
|
|
|
|
|
|
sub _new{ |
3019
|
0
|
|
|
0
|
|
0
|
my($class, %args) = @_; |
3020
|
0
|
|
|
|
|
0
|
my $self = bless \%args, $class; |
3021
|
|
|
|
|
|
|
|
3022
|
0
|
0
|
|
|
|
0
|
if($class ne __PACKAGE__){ |
3023
|
0
|
|
|
|
|
0
|
$self->meta->_initialize_object($self, \%args); |
3024
|
|
|
|
|
|
|
} |
3025
|
0
|
|
|
|
|
0
|
return $self; |
3026
|
|
|
|
|
|
|
} |
3027
|
|
|
|
|
|
|
|
3028
|
0
|
|
|
0
|
0
|
0
|
sub body { $_[0]->{body} } |
3029
|
0
|
|
|
0
|
0
|
0
|
sub name { $_[0]->{name} } |
3030
|
0
|
|
|
0
|
0
|
0
|
sub package_name { $_[0]->{package} } |
3031
|
0
|
|
|
0
|
0
|
0
|
sub associated_metaclass { $_[0]->{associated_metaclass} } |
3032
|
|
|
|
|
|
|
|
3033
|
|
|
|
|
|
|
sub fully_qualified_name { |
3034
|
0
|
|
|
0
|
0
|
0
|
my($self) = @_; |
3035
|
0
|
|
|
|
|
0
|
return $self->package_name . '::' . $self->name; |
3036
|
|
|
|
|
|
|
} |
3037
|
|
|
|
|
|
|
|
3038
|
|
|
|
|
|
|
# for Moose compat |
3039
|
|
|
|
|
|
|
sub _equal { |
3040
|
0
|
|
|
0
|
|
0
|
my($l, $r) = @_; |
3041
|
|
|
|
|
|
|
|
3042
|
0
|
|
0
|
|
|
0
|
return Scalar::Util::blessed($r) |
3043
|
|
|
|
|
|
|
&& $l->body == $r->body |
3044
|
|
|
|
|
|
|
&& $l->name eq $r->name |
3045
|
|
|
|
|
|
|
&& $l->package_name eq $r->package_name; |
3046
|
|
|
|
|
|
|
} |
3047
|
|
|
|
|
|
|
|
3048
|
|
|
|
|
|
|
# Contents of Mouse::Meta::Method::Accessor |
3049
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Method::Accessor; |
3050
|
2
|
|
|
2
|
|
908
|
use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
6
|
|
3051
|
|
|
|
|
|
|
|
3052
|
|
|
|
|
|
|
sub _inline_slot{ |
3053
|
2
|
|
|
2
|
|
5
|
my(undef, $self_var, $attr_name) = @_; |
3054
|
2
|
|
|
|
|
15
|
return sprintf '%s->{q{%s}}', $self_var, $attr_name; |
3055
|
|
|
|
|
|
|
} |
3056
|
|
|
|
|
|
|
|
3057
|
|
|
|
|
|
|
sub _generate_accessor_any{ |
3058
|
2
|
|
|
2
|
|
4
|
my($method_class, $type, $attribute, $class) = @_; |
3059
|
|
|
|
|
|
|
|
3060
|
2
|
|
|
|
|
8
|
my $name = $attribute->name; |
3061
|
2
|
|
|
|
|
8
|
my $default = $attribute->default; |
3062
|
2
|
|
|
|
|
9
|
my $constraint = $attribute->type_constraint; |
3063
|
2
|
|
|
|
|
8
|
my $builder = $attribute->builder; |
3064
|
2
|
|
|
|
|
7
|
my $trigger = $attribute->trigger; |
3065
|
2
|
|
|
|
|
7
|
my $is_weak = $attribute->is_weak_ref; |
3066
|
2
|
|
|
|
|
7
|
my $should_deref = $attribute->should_auto_deref; |
3067
|
2
|
|
33
|
|
|
9
|
my $should_coerce = (defined($constraint) && $constraint->has_coercion && $attribute->should_coerce); |
3068
|
|
|
|
|
|
|
|
3069
|
2
|
50
|
|
|
|
8
|
my $compiled_type_constraint = defined($constraint) ? $constraint->_compiled_type_constraint : undef; |
3070
|
|
|
|
|
|
|
|
3071
|
2
|
|
|
|
|
2
|
my $self = '$_[0]'; |
3072
|
2
|
|
|
|
|
9
|
my $slot = $method_class->_inline_slot($self, $name);; |
3073
|
|
|
|
|
|
|
|
3074
|
2
|
|
|
|
|
7
|
my $accessor = sprintf(qq{package %s;\n#line 1 "%s-accessor for %s (%s)"\n}, $class->name, $type, $name, __FILE__) |
3075
|
|
|
|
|
|
|
. "sub {\n"; |
3076
|
|
|
|
|
|
|
|
3077
|
2
|
50
|
33
|
|
|
20
|
if ($type eq 'rw' || $type eq 'wo') { |
|
|
50
|
|
|
|
|
|
3078
|
0
|
0
|
|
|
|
0
|
if($type eq 'rw'){ |
3079
|
0
|
|
|
|
|
0
|
$accessor .= |
3080
|
|
|
|
|
|
|
'if (scalar(@_) >= 2) {' . "\n"; |
3081
|
|
|
|
|
|
|
} |
3082
|
|
|
|
|
|
|
else{ # writer |
3083
|
0
|
|
|
|
|
0
|
$accessor .= |
3084
|
|
|
|
|
|
|
'if(@_ < 2){ Carp::confess("Not enough arguments for the writer of '.$name.'") }'. |
3085
|
|
|
|
|
|
|
'{' . "\n"; |
3086
|
|
|
|
|
|
|
} |
3087
|
|
|
|
|
|
|
|
3088
|
0
|
|
|
|
|
0
|
my $value = '$_[1]'; |
3089
|
|
|
|
|
|
|
|
3090
|
0
|
0
|
|
|
|
0
|
if (defined $constraint) { |
3091
|
0
|
0
|
|
|
|
0
|
if ($should_coerce) { |
3092
|
0
|
|
|
|
|
0
|
$accessor .= |
3093
|
|
|
|
|
|
|
"\n". |
3094
|
|
|
|
|
|
|
'my $val = $constraint->coerce('.$value.');'; |
3095
|
0
|
|
|
|
|
0
|
$value = '$val'; |
3096
|
|
|
|
|
|
|
} |
3097
|
|
|
|
|
|
|
$accessor .= |
3098
|
0
|
|
|
|
|
0
|
"\n". |
3099
|
|
|
|
|
|
|
'$compiled_type_constraint->('.$value.') or |
3100
|
|
|
|
|
|
|
$attribute->_throw_type_constraint_error('.$value.', $constraint);' . "\n"; |
3101
|
|
|
|
|
|
|
} |
3102
|
|
|
|
|
|
|
|
3103
|
|
|
|
|
|
|
# if there's nothing left to do for the attribute we can return during |
3104
|
|
|
|
|
|
|
# this setter |
3105
|
0
|
0
|
0
|
|
|
0
|
$accessor .= 'return ' if !$is_weak && !$trigger && !$should_deref; |
|
|
|
0
|
|
|
|
|
3106
|
|
|
|
|
|
|
|
3107
|
0
|
|
|
|
|
0
|
$accessor .= "$slot = $value;\n"; |
3108
|
|
|
|
|
|
|
|
3109
|
0
|
0
|
|
|
|
0
|
if ($is_weak) { |
3110
|
0
|
|
|
|
|
0
|
$accessor .= "Scalar::Util::weaken($slot) if ref $slot;\n"; |
3111
|
|
|
|
|
|
|
} |
3112
|
|
|
|
|
|
|
|
3113
|
0
|
0
|
|
|
|
0
|
if ($trigger) { |
3114
|
0
|
|
|
|
|
0
|
$accessor .= '$trigger->('.$self.', '.$value.');' . "\n"; |
3115
|
|
|
|
|
|
|
} |
3116
|
|
|
|
|
|
|
|
3117
|
0
|
|
|
|
|
0
|
$accessor .= "}\n"; |
3118
|
|
|
|
|
|
|
} |
3119
|
|
|
|
|
|
|
elsif($type eq 'ro') { |
3120
|
2
|
|
|
|
|
6
|
$accessor .= 'Carp::confess("Cannot assign a value to a read-only accessor") if scalar(@_) >= 2;' . "\n"; |
3121
|
|
|
|
|
|
|
} |
3122
|
|
|
|
|
|
|
else{ |
3123
|
0
|
|
|
|
|
0
|
$class->throw_error("Unknown accessor type '$type'"); |
3124
|
|
|
|
|
|
|
} |
3125
|
|
|
|
|
|
|
|
3126
|
2
|
50
|
33
|
|
|
9
|
if ($attribute->is_lazy and $type ne 'wo') { |
3127
|
0
|
|
|
|
|
0
|
my $value; |
3128
|
|
|
|
|
|
|
|
3129
|
0
|
0
|
|
|
|
0
|
if (defined $builder){ |
|
|
0
|
|
|
|
|
|
3130
|
0
|
|
|
|
|
0
|
$value = "$self->\$builder()"; |
3131
|
|
|
|
|
|
|
} |
3132
|
|
|
|
|
|
|
elsif (ref($default) eq 'CODE'){ |
3133
|
0
|
|
|
|
|
0
|
$value = "$self->\$default()"; |
3134
|
|
|
|
|
|
|
} |
3135
|
|
|
|
|
|
|
else{ |
3136
|
0
|
|
|
|
|
0
|
$value = '$default'; |
3137
|
|
|
|
|
|
|
} |
3138
|
|
|
|
|
|
|
|
3139
|
0
|
0
|
|
|
|
0
|
$accessor .= "els" if $type eq 'rw'; |
3140
|
0
|
|
|
|
|
0
|
$accessor .= "if(!exists $slot){\n"; |
3141
|
0
|
0
|
|
|
|
0
|
if($should_coerce){ |
|
|
0
|
|
|
|
|
|
3142
|
0
|
|
|
|
|
0
|
$accessor .= "$slot = \$constraint->coerce($value)"; |
3143
|
|
|
|
|
|
|
} |
3144
|
|
|
|
|
|
|
elsif(defined $constraint){ |
3145
|
0
|
|
|
|
|
0
|
$accessor .= "my \$tmp = $value;\n"; |
3146
|
|
|
|
|
|
|
|
3147
|
0
|
|
|
|
|
0
|
$accessor .= "\$compiled_type_constraint->(\$tmp)"; |
3148
|
0
|
|
|
|
|
0
|
$accessor .= " || \$attribute->_throw_type_constraint_error(\$tmp, \$constraint);\n"; |
3149
|
0
|
|
|
|
|
0
|
$accessor .= "$slot = \$tmp;\n"; |
3150
|
|
|
|
|
|
|
} |
3151
|
|
|
|
|
|
|
else{ |
3152
|
0
|
|
|
|
|
0
|
$accessor .= "$slot = $value;\n"; |
3153
|
|
|
|
|
|
|
} |
3154
|
0
|
0
|
|
|
|
0
|
if ($is_weak) { |
3155
|
0
|
|
|
|
|
0
|
$accessor .= "Scalar::Util::weaken($slot) if ref $slot;\n"; |
3156
|
|
|
|
|
|
|
} |
3157
|
0
|
|
|
|
|
0
|
$accessor .= "}\n"; |
3158
|
|
|
|
|
|
|
} |
3159
|
|
|
|
|
|
|
|
3160
|
2
|
50
|
|
|
|
7
|
if ($should_deref) { |
3161
|
0
|
0
|
|
|
|
0
|
if ($constraint->is_a_type_of('ArrayRef')) { |
|
|
0
|
|
|
|
|
|
3162
|
0
|
|
|
|
|
0
|
$accessor .= "return \@{ $slot || [] } if wantarray;\n"; |
3163
|
|
|
|
|
|
|
} |
3164
|
|
|
|
|
|
|
elsif($constraint->is_a_type_of('HashRef')){ |
3165
|
0
|
|
|
|
|
0
|
$accessor .= "return \%{ $slot || {} } if wantarray;\n"; |
3166
|
|
|
|
|
|
|
} |
3167
|
|
|
|
|
|
|
else{ |
3168
|
0
|
|
|
|
|
0
|
$class->throw_error("Can not auto de-reference the type constraint " . $constraint->name); |
3169
|
|
|
|
|
|
|
} |
3170
|
|
|
|
|
|
|
} |
3171
|
|
|
|
|
|
|
|
3172
|
2
|
|
|
|
|
7
|
$accessor .= "return $slot;\n}\n"; |
3173
|
|
|
|
|
|
|
|
3174
|
|
|
|
|
|
|
#print $accessor, "\n"; |
3175
|
2
|
|
|
|
|
4
|
my $code; |
3176
|
2
|
|
|
|
|
3
|
my $e = do{ |
3177
|
2
|
|
|
|
|
4
|
local $@; |
3178
|
2
|
|
|
|
|
626
|
$code = eval $accessor; |
3179
|
2
|
|
|
|
|
27
|
$@; |
3180
|
|
|
|
|
|
|
}; |
3181
|
2
|
50
|
|
|
|
15
|
die $e if $e; |
3182
|
|
|
|
|
|
|
|
3183
|
2
|
|
|
|
|
8
|
return $code; |
3184
|
|
|
|
|
|
|
} |
3185
|
|
|
|
|
|
|
|
3186
|
|
|
|
|
|
|
sub _generate_accessor{ |
3187
|
|
|
|
|
|
|
#my($self, $attribute, $metaclass) = @_; |
3188
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
3189
|
0
|
|
|
|
|
0
|
return $self->_generate_accessor_any(rw => @_); |
3190
|
|
|
|
|
|
|
} |
3191
|
|
|
|
|
|
|
|
3192
|
|
|
|
|
|
|
sub _generate_reader { |
3193
|
|
|
|
|
|
|
#my($self, $attribute, $metaclass) = @_; |
3194
|
2
|
|
|
2
|
|
4
|
my $self = shift; |
3195
|
2
|
|
|
|
|
11
|
return $self->_generate_accessor_any(ro => @_); |
3196
|
|
|
|
|
|
|
} |
3197
|
|
|
|
|
|
|
|
3198
|
|
|
|
|
|
|
sub _generate_writer { |
3199
|
|
|
|
|
|
|
#my($self, $attribute, $metaclass) = @_; |
3200
|
0
|
|
|
0
|
|
0
|
my $self = shift; |
3201
|
0
|
|
|
|
|
0
|
return $self->_generate_accessor_any(wo => @_); |
3202
|
|
|
|
|
|
|
} |
3203
|
|
|
|
|
|
|
|
3204
|
|
|
|
|
|
|
sub _generate_predicate { |
3205
|
|
|
|
|
|
|
#my($self, $attribute, $metaclass) = @_; |
3206
|
0
|
|
|
0
|
|
0
|
my(undef, $attribute) = @_; |
3207
|
|
|
|
|
|
|
|
3208
|
0
|
|
|
|
|
0
|
my $slot = $attribute->name; |
3209
|
|
|
|
|
|
|
return sub{ |
3210
|
0
|
|
|
0
|
|
0
|
return exists $_[0]->{$slot}; |
3211
|
0
|
|
|
|
|
0
|
}; |
3212
|
|
|
|
|
|
|
} |
3213
|
|
|
|
|
|
|
|
3214
|
|
|
|
|
|
|
sub _generate_clearer { |
3215
|
|
|
|
|
|
|
#my($self, $attribute, $metaclass) = @_; |
3216
|
0
|
|
|
0
|
|
0
|
my(undef, $attribute) = @_; |
3217
|
|
|
|
|
|
|
|
3218
|
0
|
|
|
|
|
0
|
my $slot = $attribute->name; |
3219
|
|
|
|
|
|
|
return sub{ |
3220
|
0
|
|
|
0
|
|
0
|
delete $_[0]->{$slot}; |
3221
|
0
|
|
|
|
|
0
|
}; |
3222
|
|
|
|
|
|
|
} |
3223
|
|
|
|
|
|
|
|
3224
|
|
|
|
|
|
|
# Contents of Mouse::Meta::Method::Constructor |
3225
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Method::Constructor; |
3226
|
2
|
|
|
2
|
|
11
|
use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
7
|
|
3227
|
|
|
|
|
|
|
|
3228
|
|
|
|
|
|
|
sub _inline_slot{ |
3229
|
0
|
|
|
0
|
|
0
|
my(undef, $self_var, $attr_name) = @_; |
3230
|
0
|
|
|
|
|
0
|
return sprintf '%s->{q{%s}}', $self_var, $attr_name; |
3231
|
|
|
|
|
|
|
} |
3232
|
|
|
|
|
|
|
|
3233
|
|
|
|
|
|
|
sub _generate_constructor { |
3234
|
0
|
|
|
0
|
|
0
|
my ($class, $metaclass, $args) = @_; |
3235
|
|
|
|
|
|
|
|
3236
|
0
|
|
|
|
|
0
|
my $associated_metaclass_name = $metaclass->name; |
3237
|
|
|
|
|
|
|
|
3238
|
0
|
|
|
|
|
0
|
my @attrs = $metaclass->get_all_attributes; |
3239
|
|
|
|
|
|
|
|
3240
|
0
|
|
|
|
|
0
|
my $buildall = $class->_generate_BUILDALL($metaclass); |
3241
|
0
|
|
|
|
|
0
|
my $buildargs = $class->_generate_BUILDARGS($metaclass); |
3242
|
0
|
|
|
|
|
0
|
my $processattrs = $class->_generate_processattrs($metaclass, \@attrs); |
3243
|
|
|
|
|
|
|
|
3244
|
0
|
0
|
|
|
|
0
|
my @checks = map { $_ && $_->_compiled_type_constraint } |
|
0
|
|
|
|
|
0
|
|
3245
|
0
|
|
|
|
|
0
|
map { $_->type_constraint } @attrs; |
3246
|
|
|
|
|
|
|
|
3247
|
0
|
|
|
|
|
0
|
my $source = sprintf("#line %d %s\n", __LINE__, __FILE__).<<"..."; |
3248
|
|
|
|
|
|
|
sub \{ |
3249
|
|
|
|
|
|
|
my \$class = shift; |
3250
|
|
|
|
|
|
|
return \$class->Scalar::Random::PP::OO::Object::new(\@_) |
3251
|
|
|
|
|
|
|
if \$class ne q{$associated_metaclass_name}; |
3252
|
|
|
|
|
|
|
# BUILDARGS |
3253
|
|
|
|
|
|
|
$buildargs; |
3254
|
|
|
|
|
|
|
my \$instance = bless {}, \$class; |
3255
|
|
|
|
|
|
|
# process attributes |
3256
|
|
|
|
|
|
|
$processattrs; |
3257
|
|
|
|
|
|
|
# BUILDALL |
3258
|
|
|
|
|
|
|
$buildall; |
3259
|
|
|
|
|
|
|
return \$instance; |
3260
|
|
|
|
|
|
|
} |
3261
|
|
|
|
|
|
|
... |
3262
|
|
|
|
|
|
|
#warn $source; |
3263
|
0
|
|
|
|
|
0
|
my $code; |
3264
|
0
|
|
|
|
|
0
|
my $e = do{ |
3265
|
0
|
|
|
|
|
0
|
local $@; |
3266
|
0
|
|
|
|
|
0
|
$code = eval $source; |
3267
|
0
|
|
|
|
|
0
|
$@; |
3268
|
|
|
|
|
|
|
}; |
3269
|
0
|
0
|
|
|
|
0
|
die $e if $e; |
3270
|
0
|
|
|
|
|
0
|
return $code; |
3271
|
|
|
|
|
|
|
} |
3272
|
|
|
|
|
|
|
|
3273
|
|
|
|
|
|
|
sub _generate_processattrs { |
3274
|
0
|
|
|
0
|
|
0
|
my ($method_class, $metaclass, $attrs) = @_; |
3275
|
0
|
|
|
|
|
0
|
my @res; |
3276
|
|
|
|
|
|
|
|
3277
|
|
|
|
|
|
|
my $has_triggers; |
3278
|
0
|
|
|
|
|
0
|
my $strict = $metaclass->strict_constructor; |
3279
|
|
|
|
|
|
|
|
3280
|
0
|
0
|
|
|
|
0
|
if($strict){ |
3281
|
0
|
|
|
|
|
0
|
push @res, 'my $used = 0;'; |
3282
|
|
|
|
|
|
|
} |
3283
|
|
|
|
|
|
|
|
3284
|
0
|
|
|
|
|
0
|
for my $index (0 .. @$attrs - 1) { |
3285
|
0
|
|
|
|
|
0
|
my $code = ''; |
3286
|
|
|
|
|
|
|
|
3287
|
0
|
|
|
|
|
0
|
my $attr = $attrs->[$index]; |
3288
|
0
|
|
|
|
|
0
|
my $key = $attr->name; |
3289
|
|
|
|
|
|
|
|
3290
|
0
|
|
|
|
|
0
|
my $init_arg = $attr->init_arg; |
3291
|
0
|
|
|
|
|
0
|
my $type_constraint = $attr->type_constraint; |
3292
|
0
|
|
|
|
|
0
|
my $is_weak_ref = $attr->is_weak_ref; |
3293
|
0
|
|
|
|
|
0
|
my $need_coercion; |
3294
|
|
|
|
|
|
|
|
3295
|
0
|
|
|
|
|
0
|
my $instance_slot = $method_class->_inline_slot('$instance', $key); |
3296
|
0
|
|
|
|
|
0
|
my $attr_var = "\$attrs[$index]"; |
3297
|
0
|
|
|
|
|
0
|
my $constraint_var; |
3298
|
|
|
|
|
|
|
|
3299
|
0
|
0
|
|
|
|
0
|
if(defined $type_constraint){ |
3300
|
0
|
|
|
|
|
0
|
$constraint_var = "$attr_var\->{type_constraint}"; |
3301
|
0
|
|
0
|
|
|
0
|
$need_coercion = ($attr->should_coerce && $type_constraint->has_coercion); |
3302
|
|
|
|
|
|
|
} |
3303
|
|
|
|
|
|
|
|
3304
|
0
|
|
|
|
|
0
|
$code .= "# initialize $key\n"; |
3305
|
|
|
|
|
|
|
|
3306
|
0
|
|
|
|
|
0
|
my $post_process = ''; |
3307
|
0
|
0
|
|
|
|
0
|
if(defined $type_constraint){ |
3308
|
0
|
|
|
|
|
0
|
$post_process .= "\$checks[$index]->($instance_slot)"; |
3309
|
0
|
|
|
|
|
0
|
$post_process .= " or $attr_var->_throw_type_constraint_error($instance_slot, $constraint_var);\n"; |
3310
|
|
|
|
|
|
|
} |
3311
|
0
|
0
|
|
|
|
0
|
if($is_weak_ref){ |
3312
|
0
|
|
|
|
|
0
|
$post_process .= "Scalar::Util::weaken($instance_slot) if ref $instance_slot;\n"; |
3313
|
|
|
|
|
|
|
} |
3314
|
|
|
|
|
|
|
|
3315
|
0
|
0
|
|
|
|
0
|
if (defined $init_arg) { |
3316
|
0
|
|
|
|
|
0
|
my $value = "\$args->{q{$init_arg}}"; |
3317
|
|
|
|
|
|
|
|
3318
|
0
|
|
|
|
|
0
|
$code .= "if (exists $value) {\n"; |
3319
|
|
|
|
|
|
|
|
3320
|
0
|
0
|
|
|
|
0
|
if($need_coercion){ |
3321
|
0
|
|
|
|
|
0
|
$value = "$constraint_var->coerce($value)"; |
3322
|
|
|
|
|
|
|
} |
3323
|
|
|
|
|
|
|
|
3324
|
0
|
|
|
|
|
0
|
$code .= "$instance_slot = $value;\n"; |
3325
|
0
|
|
|
|
|
0
|
$code .= $post_process; |
3326
|
|
|
|
|
|
|
|
3327
|
0
|
0
|
|
|
|
0
|
if ($attr->has_trigger) { |
3328
|
0
|
|
|
|
|
0
|
$has_triggers++; |
3329
|
0
|
|
|
|
|
0
|
$code .= "push \@triggers, [$attr_var\->{trigger}, $instance_slot];\n"; |
3330
|
|
|
|
|
|
|
} |
3331
|
|
|
|
|
|
|
|
3332
|
0
|
0
|
|
|
|
0
|
if ($strict){ |
3333
|
0
|
|
|
|
|
0
|
$code .= '++$used;' . "\n"; |
3334
|
|
|
|
|
|
|
} |
3335
|
|
|
|
|
|
|
|
3336
|
0
|
|
|
|
|
0
|
$code .= "\n} else {\n"; # $value exists |
3337
|
|
|
|
|
|
|
} |
3338
|
|
|
|
|
|
|
|
3339
|
0
|
0
|
0
|
|
|
0
|
if ($attr->has_default || $attr->has_builder) { |
|
|
0
|
|
|
|
|
|
3340
|
0
|
0
|
|
|
|
0
|
unless ($attr->is_lazy) { |
3341
|
0
|
|
|
|
|
0
|
my $default = $attr->default; |
3342
|
0
|
|
|
|
|
0
|
my $builder = $attr->builder; |
3343
|
|
|
|
|
|
|
|
3344
|
0
|
|
|
|
|
0
|
my $value; |
3345
|
0
|
0
|
|
|
|
0
|
if (defined($builder)) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
3346
|
0
|
|
|
|
|
0
|
$value = "\$instance->$builder()"; |
3347
|
|
|
|
|
|
|
} |
3348
|
|
|
|
|
|
|
elsif (ref($default) eq 'CODE') { |
3349
|
0
|
|
|
|
|
0
|
$value = "$attr_var\->{default}->(\$instance)"; |
3350
|
|
|
|
|
|
|
} |
3351
|
|
|
|
|
|
|
elsif (defined($default)) { |
3352
|
0
|
|
|
|
|
0
|
$value = "$attr_var\->{default}"; |
3353
|
|
|
|
|
|
|
} |
3354
|
|
|
|
|
|
|
else { |
3355
|
0
|
|
|
|
|
0
|
$value = 'undef'; |
3356
|
|
|
|
|
|
|
} |
3357
|
|
|
|
|
|
|
|
3358
|
0
|
0
|
|
|
|
0
|
if($need_coercion){ |
3359
|
0
|
|
|
|
|
0
|
$value = "$constraint_var->coerce($value)"; |
3360
|
|
|
|
|
|
|
} |
3361
|
|
|
|
|
|
|
|
3362
|
0
|
|
|
|
|
0
|
$code .= "$instance_slot = $value;\n"; |
3363
|
0
|
0
|
|
|
|
0
|
if($is_weak_ref){ |
3364
|
0
|
|
|
|
|
0
|
$code .= "Scalar::Util::weaken($instance_slot);\n"; |
3365
|
|
|
|
|
|
|
} |
3366
|
|
|
|
|
|
|
} |
3367
|
|
|
|
|
|
|
} |
3368
|
|
|
|
|
|
|
elsif ($attr->is_required) { |
3369
|
0
|
|
|
|
|
0
|
$code .= "Carp::confess('Attribute ($key) is required');"; |
3370
|
|
|
|
|
|
|
} |
3371
|
|
|
|
|
|
|
|
3372
|
0
|
0
|
|
|
|
0
|
$code .= "}\n" if defined $init_arg; |
3373
|
|
|
|
|
|
|
|
3374
|
0
|
|
|
|
|
0
|
push @res, $code; |
3375
|
|
|
|
|
|
|
} |
3376
|
|
|
|
|
|
|
|
3377
|
0
|
0
|
|
|
|
0
|
if($strict){ |
3378
|
0
|
|
|
|
|
0
|
push @res, q{if($used < keys %{$args})} |
3379
|
|
|
|
|
|
|
. q{{ $metaclass->_report_unknown_args(\@attrs, $args) }}; |
3380
|
|
|
|
|
|
|
} |
3381
|
|
|
|
|
|
|
|
3382
|
0
|
0
|
|
|
|
0
|
if($metaclass->is_anon_class){ |
3383
|
0
|
|
|
|
|
0
|
push @res, q{$instance->{__METACLASS__} = $metaclass;}; |
3384
|
|
|
|
|
|
|
} |
3385
|
|
|
|
|
|
|
|
3386
|
0
|
0
|
|
|
|
0
|
if($has_triggers){ |
3387
|
0
|
|
|
|
|
0
|
unshift @res, q{my @triggers;}; |
3388
|
0
|
|
|
|
|
0
|
push @res, q{$_->[0]->($instance, $_->[1]) for @triggers;}; |
3389
|
|
|
|
|
|
|
} |
3390
|
|
|
|
|
|
|
|
3391
|
0
|
|
|
|
|
0
|
return join "\n", @res; |
3392
|
|
|
|
|
|
|
} |
3393
|
|
|
|
|
|
|
|
3394
|
|
|
|
|
|
|
sub _generate_BUILDARGS { |
3395
|
0
|
|
|
0
|
|
0
|
my(undef, $metaclass) = @_; |
3396
|
|
|
|
|
|
|
|
3397
|
0
|
|
|
|
|
0
|
my $class = $metaclass->name; |
3398
|
0
|
0
|
0
|
|
|
0
|
if ( $class->can('BUILDARGS') && $class->can('BUILDARGS') != \&Scalar::Random::PP::OO::Object::BUILDARGS ) { |
3399
|
0
|
|
|
|
|
0
|
return 'my $args = $class->BUILDARGS(@_)'; |
3400
|
|
|
|
|
|
|
} |
3401
|
|
|
|
|
|
|
|
3402
|
0
|
|
|
|
|
0
|
return <<'...'; |
3403
|
|
|
|
|
|
|
my $args; |
3404
|
|
|
|
|
|
|
if ( scalar @_ == 1 ) { |
3405
|
|
|
|
|
|
|
( ref( $_[0] ) eq 'HASH' ) |
3406
|
|
|
|
|
|
|
|| Carp::confess "Single parameters to new() must be a HASH ref"; |
3407
|
|
|
|
|
|
|
$args = +{ %{ $_[0] } }; |
3408
|
|
|
|
|
|
|
} |
3409
|
|
|
|
|
|
|
else { |
3410
|
|
|
|
|
|
|
$args = +{@_}; |
3411
|
|
|
|
|
|
|
} |
3412
|
|
|
|
|
|
|
... |
3413
|
|
|
|
|
|
|
} |
3414
|
|
|
|
|
|
|
|
3415
|
|
|
|
|
|
|
sub _generate_BUILDALL { |
3416
|
0
|
|
|
0
|
|
0
|
my (undef, $metaclass) = @_; |
3417
|
|
|
|
|
|
|
|
3418
|
0
|
0
|
|
|
|
0
|
return '' unless $metaclass->name->can('BUILD'); |
3419
|
|
|
|
|
|
|
|
3420
|
0
|
|
|
|
|
0
|
my @code; |
3421
|
0
|
|
|
|
|
0
|
for my $class ($metaclass->linearized_isa) { |
3422
|
0
|
0
|
|
|
|
0
|
if (Scalar::Random::PP::OO::Util::get_code_ref($class, 'BUILD')) { |
3423
|
0
|
|
|
|
|
0
|
unshift @code, qq{${class}::BUILD(\$instance, \$args);}; |
3424
|
|
|
|
|
|
|
} |
3425
|
|
|
|
|
|
|
} |
3426
|
0
|
|
|
|
|
0
|
return join "\n", @code; |
3427
|
|
|
|
|
|
|
} |
3428
|
|
|
|
|
|
|
|
3429
|
|
|
|
|
|
|
# Contents of Mouse::Meta::Method::Delegation |
3430
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Method::Delegation; |
3431
|
2
|
|
|
2
|
|
35
|
use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
15
|
|
3432
|
2
|
|
|
2
|
|
12
|
use Scalar::Util; |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
860
|
|
3433
|
|
|
|
|
|
|
|
3434
|
|
|
|
|
|
|
sub _generate_delegation{ |
3435
|
0
|
|
|
0
|
|
0
|
my (undef, $attr, $handle_name, $method_to_call) = @_; |
3436
|
|
|
|
|
|
|
|
3437
|
0
|
|
|
|
|
0
|
my @curried_args; |
3438
|
0
|
0
|
|
|
|
0
|
if(ref($method_to_call) eq 'ARRAY'){ |
3439
|
0
|
|
|
|
|
0
|
($method_to_call, @curried_args) = @{$method_to_call}; |
|
0
|
|
|
|
|
0
|
|
3440
|
|
|
|
|
|
|
} |
3441
|
|
|
|
|
|
|
|
3442
|
|
|
|
|
|
|
# If it has a reader, we must use it to make method modifiers work |
3443
|
0
|
|
0
|
|
|
0
|
my $reader = $attr->get_read_method() || $attr->get_read_method_ref(); |
3444
|
|
|
|
|
|
|
|
3445
|
0
|
|
|
|
|
0
|
my $can_be_optimized = $attr->{_method_delegation_can_be_optimized}; |
3446
|
|
|
|
|
|
|
|
3447
|
0
|
0
|
|
|
|
0
|
if(!defined $can_be_optimized){ |
3448
|
0
|
|
|
|
|
0
|
my $tc = $attr->type_constraint; |
3449
|
|
|
|
|
|
|
|
3450
|
0
|
|
0
|
|
|
0
|
$attr->{_method_delegation_can_be_optimized} = |
3451
|
|
|
|
|
|
|
(defined($tc) && $tc->is_a_type_of('Object')) |
3452
|
|
|
|
|
|
|
&& ($attr->is_required || $attr->has_default || $attr->has_builder) |
3453
|
|
|
|
|
|
|
&& ($attr->is_lazy || !$attr->has_clearer); |
3454
|
|
|
|
|
|
|
} |
3455
|
|
|
|
|
|
|
|
3456
|
0
|
0
|
|
|
|
0
|
if($can_be_optimized){ |
3457
|
|
|
|
|
|
|
# need not check the attribute value |
3458
|
|
|
|
|
|
|
return sub { |
3459
|
0
|
|
|
0
|
|
0
|
return shift()->$reader()->$method_to_call(@curried_args, @_); |
3460
|
0
|
|
|
|
|
0
|
}; |
3461
|
|
|
|
|
|
|
} |
3462
|
|
|
|
|
|
|
else { |
3463
|
|
|
|
|
|
|
# need to check the attribute value |
3464
|
|
|
|
|
|
|
return sub { |
3465
|
0
|
|
|
0
|
|
0
|
my $instance = shift; |
3466
|
0
|
|
|
|
|
0
|
my $proxy = $instance->$reader(); |
3467
|
|
|
|
|
|
|
|
3468
|
0
|
0
|
0
|
|
|
0
|
my $error = !defined($proxy) ? ' is not defined' |
|
|
0
|
|
|
|
|
|
3469
|
|
|
|
|
|
|
: ref($proxy) && !Scalar::Util::blessed($proxy) ? qq{ is not an object (got '$proxy')} |
3470
|
|
|
|
|
|
|
: undef; |
3471
|
0
|
0
|
|
|
|
0
|
if ($error) { |
3472
|
0
|
|
|
|
|
0
|
$instance->meta->throw_error( |
3473
|
|
|
|
|
|
|
"Cannot delegate $handle_name to $method_to_call because " |
3474
|
|
|
|
|
|
|
. "the value of " |
3475
|
|
|
|
|
|
|
. $attr->name |
3476
|
|
|
|
|
|
|
. $error |
3477
|
|
|
|
|
|
|
); |
3478
|
|
|
|
|
|
|
} |
3479
|
0
|
|
|
|
|
0
|
$proxy->$method_to_call(@curried_args, @_); |
3480
|
0
|
|
|
|
|
0
|
}; |
3481
|
|
|
|
|
|
|
} |
3482
|
|
|
|
|
|
|
} |
3483
|
|
|
|
|
|
|
|
3484
|
|
|
|
|
|
|
|
3485
|
|
|
|
|
|
|
# Contents of Mouse::Meta::Method::Destructor |
3486
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Method::Destructor; |
3487
|
2
|
|
|
2
|
|
13
|
use Scalar::Random::PP::OO::Util qw(:meta); # enables strict and warnings |
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
23
|
|
3488
|
|
|
|
|
|
|
|
3489
|
0
|
|
|
0
|
|
0
|
sub _empty_DESTROY{ } |
3490
|
|
|
|
|
|
|
|
3491
|
|
|
|
|
|
|
sub _generate_destructor{ |
3492
|
0
|
|
|
0
|
|
0
|
my (undef, $metaclass) = @_; |
3493
|
|
|
|
|
|
|
|
3494
|
0
|
0
|
|
|
|
0
|
if(!$metaclass->name->can('DEMOLISH')){ |
3495
|
0
|
|
|
|
|
0
|
return \&_empty_DESTROY; |
3496
|
|
|
|
|
|
|
} |
3497
|
|
|
|
|
|
|
|
3498
|
0
|
|
|
|
|
0
|
my $demolishall = ''; |
3499
|
0
|
|
|
|
|
0
|
for my $class ($metaclass->linearized_isa) { |
3500
|
0
|
0
|
|
|
|
0
|
if (Scalar::Random::PP::OO::Util::get_code_ref($class, 'DEMOLISH')) { |
3501
|
0
|
|
|
|
|
0
|
$demolishall .= sprintf "%s::DEMOLISH(\$self, \$Scalar::Random::PP::OO::Util::in_global_destruction);\n", |
3502
|
|
|
|
|
|
|
$class, |
3503
|
|
|
|
|
|
|
} |
3504
|
|
|
|
|
|
|
} |
3505
|
|
|
|
|
|
|
|
3506
|
0
|
|
|
|
|
0
|
my $source = sprintf(<<'END_DESTROY', __LINE__, __FILE__, $demolishall); |
3507
|
|
|
|
|
|
|
#line %d %s |
3508
|
|
|
|
|
|
|
sub { |
3509
|
|
|
|
|
|
|
my $self = shift; |
3510
|
|
|
|
|
|
|
my $e = do{ |
3511
|
|
|
|
|
|
|
local $?; |
3512
|
|
|
|
|
|
|
local $@; |
3513
|
|
|
|
|
|
|
eval{ |
3514
|
|
|
|
|
|
|
# demolishall |
3515
|
|
|
|
|
|
|
%s; |
3516
|
|
|
|
|
|
|
}; |
3517
|
|
|
|
|
|
|
$@; |
3518
|
|
|
|
|
|
|
}; |
3519
|
|
|
|
|
|
|
no warnings 'misc'; |
3520
|
|
|
|
|
|
|
die $e if $e; # rethrow |
3521
|
|
|
|
|
|
|
} |
3522
|
|
|
|
|
|
|
END_DESTROY |
3523
|
|
|
|
|
|
|
|
3524
|
0
|
|
|
|
|
0
|
my $code; |
3525
|
0
|
|
|
|
|
0
|
my $e = do{ |
3526
|
0
|
|
|
|
|
0
|
local $@; |
3527
|
0
|
|
|
|
|
0
|
$code = eval $source; |
3528
|
0
|
|
|
|
|
0
|
$@; |
3529
|
|
|
|
|
|
|
}; |
3530
|
0
|
0
|
|
|
|
0
|
die $e if $e; |
3531
|
0
|
|
|
|
|
0
|
return $code; |
3532
|
|
|
|
|
|
|
} |
3533
|
|
|
|
|
|
|
|
3534
|
|
|
|
|
|
|
# Contents of Mouse::Meta::Module |
3535
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Module; |
3536
|
2
|
|
|
2
|
|
1260
|
use Scalar::Random::PP::OO::Util qw/:meta get_code_package get_code_ref not_supported/; # enables strict and warnings |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
9
|
|
3537
|
2
|
|
|
2
|
|
9
|
no warnings 'once'; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
64
|
|
3538
|
|
|
|
|
|
|
|
3539
|
2
|
|
|
2
|
|
9
|
use Carp (); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
33
|
|
3540
|
2
|
|
|
2
|
|
9
|
use Scalar::Util (); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
2808
|
|
3541
|
|
|
|
|
|
|
|
3542
|
|
|
|
|
|
|
my %METAS; |
3543
|
|
|
|
|
|
|
|
3544
|
|
|
|
|
|
|
if(Scalar::Random::PP::OO::Util::MOUSE_XS){ |
3545
|
|
|
|
|
|
|
# register meta storage for performance |
3546
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Util::__register_metaclass_storage(\%METAS, 0); |
3547
|
|
|
|
|
|
|
|
3548
|
|
|
|
|
|
|
# ensure thread safety |
3549
|
|
|
|
|
|
|
*CLONE = sub { Scalar::Random::PP::OO::Util::__register_metaclass_storage(\%METAS, 1) }; |
3550
|
|
|
|
|
|
|
} |
3551
|
|
|
|
|
|
|
|
3552
|
|
|
|
|
|
|
sub _metaclass_cache { # DEPRECATED |
3553
|
0
|
|
|
0
|
|
0
|
my($self, $name) = @_; |
3554
|
0
|
|
|
|
|
0
|
Carp::cluck('_metaclass_cache() has been deprecated. Use Scalar::Random::PP::OO::Util::get_metaclass_by_name() instead'); |
3555
|
0
|
|
|
|
|
0
|
return $METAS{$name}; |
3556
|
|
|
|
|
|
|
} |
3557
|
|
|
|
|
|
|
|
3558
|
|
|
|
|
|
|
sub initialize { |
3559
|
16
|
|
|
16
|
0
|
70
|
my($class, $package_name, @args) = @_; |
3560
|
|
|
|
|
|
|
|
3561
|
16
|
50
|
33
|
|
|
90
|
($package_name && !ref($package_name)) |
3562
|
|
|
|
|
|
|
|| $class->throw_error("You must pass a package name and it cannot be blessed"); |
3563
|
|
|
|
|
|
|
|
3564
|
16
|
|
66
|
|
|
120
|
return $METAS{$package_name} |
3565
|
|
|
|
|
|
|
||= $class->_construct_meta(package => $package_name, @args); |
3566
|
|
|
|
|
|
|
} |
3567
|
|
|
|
|
|
|
|
3568
|
|
|
|
|
|
|
sub reinitialize { |
3569
|
0
|
|
|
0
|
0
|
0
|
my($class, $package_name, @args) = @_; |
3570
|
|
|
|
|
|
|
|
3571
|
0
|
0
|
|
|
|
0
|
$package_name = $package_name->name if ref $package_name; |
3572
|
|
|
|
|
|
|
|
3573
|
0
|
0
|
0
|
|
|
0
|
($package_name && !ref($package_name)) |
3574
|
|
|
|
|
|
|
|| $class->throw_error("You must pass a package name and it cannot be blessed"); |
3575
|
|
|
|
|
|
|
|
3576
|
0
|
|
|
|
|
0
|
delete $METAS{$package_name}; |
3577
|
0
|
|
|
|
|
0
|
return $class->initialize($package_name, @args); |
3578
|
|
|
|
|
|
|
} |
3579
|
|
|
|
|
|
|
|
3580
|
|
|
|
|
|
|
sub _class_of{ |
3581
|
0
|
|
|
0
|
|
0
|
my($class_or_instance) = @_; |
3582
|
0
|
0
|
|
|
|
0
|
return undef unless defined $class_or_instance; |
3583
|
0
|
|
0
|
|
|
0
|
return $METAS{ ref($class_or_instance) || $class_or_instance }; |
3584
|
|
|
|
|
|
|
} |
3585
|
|
|
|
|
|
|
|
3586
|
|
|
|
|
|
|
# Means of accessing all the metaclasses that have |
3587
|
|
|
|
|
|
|
# been initialized thus far |
3588
|
|
|
|
|
|
|
#sub _get_all_metaclasses { %METAS } |
3589
|
0
|
|
|
0
|
|
0
|
sub _get_all_metaclass_instances { values %METAS } |
3590
|
0
|
|
|
0
|
|
0
|
sub _get_all_metaclass_names { keys %METAS } |
3591
|
2
|
|
|
2
|
|
4
|
sub _get_metaclass_by_name { $METAS{$_[0]} } |
3592
|
|
|
|
|
|
|
#sub _store_metaclass_by_name { $METAS{$_[0]} = $_[1] } |
3593
|
|
|
|
|
|
|
#sub _weaken_metaclass { weaken($METAS{$_[0]}) } |
3594
|
|
|
|
|
|
|
#sub _does_metaclass_exist { defined $METAS{$_[0]} } |
3595
|
|
|
|
|
|
|
#sub _remove_metaclass_by_name { delete $METAS{$_[0]} } |
3596
|
|
|
|
|
|
|
|
3597
|
|
|
|
|
|
|
sub name; |
3598
|
|
|
|
|
|
|
|
3599
|
|
|
|
|
|
|
sub namespace; |
3600
|
|
|
|
|
|
|
|
3601
|
|
|
|
|
|
|
# add_attribute is an abstract method |
3602
|
|
|
|
|
|
|
|
3603
|
|
|
|
|
|
|
sub get_attribute_map { # DEPRECATED |
3604
|
0
|
|
|
0
|
0
|
|
Carp::cluck('get_attribute_map() has been deprecated. Use get_attribute_list() and get_attribute() instead'); |
3605
|
0
|
|
|
|
|
|
return $_[0]->{attributes}; |
3606
|
|
|
|
|
|
|
} |
3607
|
|
|
|
|
|
|
|
3608
|
0
|
|
|
0
|
0
|
|
sub has_attribute { exists $_[0]->{attributes}->{$_[1]} } |
3609
|
0
|
|
|
0
|
0
|
|
sub get_attribute { $_[0]->{attributes}->{$_[1]} } |
3610
|
0
|
|
|
0
|
0
|
|
sub remove_attribute { delete $_[0]->{attributes}->{$_[1]} } |
3611
|
|
|
|
|
|
|
|
3612
|
0
|
|
|
0
|
0
|
|
sub get_attribute_list{ keys %{$_[0]->{attributes}} } |
|
0
|
|
|
|
|
|
|
3613
|
|
|
|
|
|
|
|
3614
|
|
|
|
|
|
|
# XXX: for backward compatibility |
3615
|
|
|
|
|
|
|
my %foreign = map{ $_ => undef } qw( |
3616
|
|
|
|
|
|
|
Scalar::Random::PP::OO Scalar::Random::PP::OO::Role Scalar::Random::PP::OO::Util Scalar::Random::PP::OO::Util::TypeConstraints |
3617
|
|
|
|
|
|
|
Carp Scalar::Util List::Util |
3618
|
|
|
|
|
|
|
); |
3619
|
|
|
|
|
|
|
sub _code_is_mine{ |
3620
|
|
|
|
|
|
|
# my($self, $code) = @_; |
3621
|
|
|
|
|
|
|
|
3622
|
0
|
|
|
0
|
|
|
return !exists $foreign{ get_code_package($_[1]) }; |
3623
|
|
|
|
|
|
|
} |
3624
|
|
|
|
|
|
|
|
3625
|
|
|
|
|
|
|
sub add_method; |
3626
|
|
|
|
|
|
|
|
3627
|
|
|
|
|
|
|
sub has_method { |
3628
|
0
|
|
|
0
|
0
|
|
my($self, $method_name) = @_; |
3629
|
|
|
|
|
|
|
|
3630
|
0
|
0
|
|
|
|
|
defined($method_name) |
3631
|
|
|
|
|
|
|
or $self->throw_error('You must define a method name'); |
3632
|
|
|
|
|
|
|
|
3633
|
0
|
|
0
|
|
|
|
return defined($self->{methods}{$method_name}) || do{ |
3634
|
|
|
|
|
|
|
my $code = get_code_ref($self->{package}, $method_name); |
3635
|
|
|
|
|
|
|
$code && $self->_code_is_mine($code); |
3636
|
|
|
|
|
|
|
}; |
3637
|
|
|
|
|
|
|
} |
3638
|
|
|
|
|
|
|
|
3639
|
|
|
|
|
|
|
sub get_method_body { |
3640
|
0
|
|
|
0
|
0
|
|
my($self, $method_name) = @_; |
3641
|
|
|
|
|
|
|
|
3642
|
0
|
0
|
|
|
|
|
defined($method_name) |
3643
|
|
|
|
|
|
|
or $self->throw_error('You must define a method name'); |
3644
|
|
|
|
|
|
|
|
3645
|
0
|
|
0
|
|
|
|
return $self->{methods}{$method_name} ||= do{ |
3646
|
0
|
|
|
|
|
|
my $code = get_code_ref($self->{package}, $method_name); |
3647
|
0
|
0
|
0
|
|
|
|
$code && $self->_code_is_mine($code) ? $code : undef; |
3648
|
|
|
|
|
|
|
}; |
3649
|
|
|
|
|
|
|
} |
3650
|
|
|
|
|
|
|
|
3651
|
|
|
|
|
|
|
sub get_method{ |
3652
|
0
|
|
|
0
|
0
|
|
my($self, $method_name) = @_; |
3653
|
|
|
|
|
|
|
|
3654
|
0
|
0
|
|
|
|
|
if(my $code = $self->get_method_body($method_name)){ |
3655
|
0
|
|
|
|
|
|
return Scalar::Random::PP::OO::Util::load_class($self->method_metaclass)->wrap( |
3656
|
|
|
|
|
|
|
body => $code, |
3657
|
|
|
|
|
|
|
name => $method_name, |
3658
|
|
|
|
|
|
|
package => $self->name, |
3659
|
|
|
|
|
|
|
associated_metaclass => $self, |
3660
|
|
|
|
|
|
|
); |
3661
|
|
|
|
|
|
|
} |
3662
|
|
|
|
|
|
|
|
3663
|
0
|
|
|
|
|
|
return undef; |
3664
|
|
|
|
|
|
|
} |
3665
|
|
|
|
|
|
|
|
3666
|
|
|
|
|
|
|
sub get_method_list { |
3667
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
3668
|
|
|
|
|
|
|
|
3669
|
0
|
|
|
|
|
|
return grep { $self->has_method($_) } keys %{ $self->namespace }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
3670
|
|
|
|
|
|
|
} |
3671
|
|
|
|
|
|
|
|
3672
|
|
|
|
|
|
|
sub _collect_methods { # Scalar::Random::PP::OO specific |
3673
|
0
|
|
|
0
|
|
|
my($meta, @args) = @_; |
3674
|
|
|
|
|
|
|
|
3675
|
0
|
|
|
|
|
|
my @methods; |
3676
|
0
|
|
|
|
|
|
foreach my $arg(@args){ |
3677
|
0
|
0
|
|
|
|
|
if(my $type = ref $arg){ |
3678
|
0
|
0
|
|
|
|
|
if($type eq 'Regexp'){ |
|
|
0
|
|
|
|
|
|
3679
|
0
|
|
|
|
|
|
push @methods, grep { $_ =~ $arg } $meta->get_all_method_names; |
|
0
|
|
|
|
|
|
|
3680
|
|
|
|
|
|
|
} |
3681
|
|
|
|
|
|
|
elsif($type eq 'ARRAY'){ |
3682
|
0
|
|
|
|
|
|
push @methods, @{$arg}; |
|
0
|
|
|
|
|
|
|
3683
|
|
|
|
|
|
|
} |
3684
|
|
|
|
|
|
|
else{ |
3685
|
0
|
|
|
|
|
|
my $subname = ( caller(1) )[3]; |
3686
|
0
|
|
|
|
|
|
$meta->throw_error( |
3687
|
|
|
|
|
|
|
sprintf( |
3688
|
|
|
|
|
|
|
'Methods passed to %s must be provided as a list, ArrayRef or regular expression, not %s', |
3689
|
|
|
|
|
|
|
$subname, |
3690
|
|
|
|
|
|
|
$type, |
3691
|
|
|
|
|
|
|
) |
3692
|
|
|
|
|
|
|
); |
3693
|
|
|
|
|
|
|
} |
3694
|
|
|
|
|
|
|
} |
3695
|
|
|
|
|
|
|
else{ |
3696
|
0
|
|
|
|
|
|
push @methods, $arg; |
3697
|
|
|
|
|
|
|
} |
3698
|
|
|
|
|
|
|
} |
3699
|
0
|
|
|
|
|
|
return @methods; |
3700
|
|
|
|
|
|
|
} |
3701
|
|
|
|
|
|
|
|
3702
|
|
|
|
|
|
|
my $ANON_SERIAL = 0; # anonymous class/role id |
3703
|
|
|
|
|
|
|
my %IMMORTALS; # immortal anonymous classes |
3704
|
|
|
|
|
|
|
|
3705
|
|
|
|
|
|
|
sub create { |
3706
|
0
|
|
|
0
|
0
|
|
my($self, $package_name, %options) = @_; |
3707
|
|
|
|
|
|
|
|
3708
|
0
|
|
0
|
|
|
|
my $class = ref($self) || $self; |
3709
|
0
|
0
|
|
|
|
|
$self->throw_error('You must pass a package name') if @_ < 2; |
3710
|
|
|
|
|
|
|
|
3711
|
0
|
|
|
|
|
|
my $superclasses; |
3712
|
0
|
0
|
|
|
|
|
if(exists $options{superclasses}){ |
3713
|
0
|
0
|
|
|
|
|
if(Scalar::Random::PP::OO::Util::is_a_metarole($self)){ |
3714
|
0
|
|
|
|
|
|
delete $options{superclasses}; |
3715
|
|
|
|
|
|
|
} |
3716
|
|
|
|
|
|
|
else{ |
3717
|
0
|
|
|
|
|
|
$superclasses = delete $options{superclasses}; |
3718
|
0
|
0
|
|
|
|
|
(ref $superclasses eq 'ARRAY') |
3719
|
|
|
|
|
|
|
|| $self->throw_error("You must pass an ARRAY ref of superclasses"); |
3720
|
|
|
|
|
|
|
} |
3721
|
|
|
|
|
|
|
} |
3722
|
|
|
|
|
|
|
|
3723
|
0
|
|
|
|
|
|
my $attributes = delete $options{attributes}; |
3724
|
0
|
0
|
|
|
|
|
if(defined $attributes){ |
3725
|
0
|
0
|
0
|
|
|
|
(ref $attributes eq 'ARRAY' || ref $attributes eq 'HASH') |
3726
|
|
|
|
|
|
|
|| $self->throw_error("You must pass an ARRAY ref of attributes"); |
3727
|
|
|
|
|
|
|
} |
3728
|
0
|
|
|
|
|
|
my $methods = delete $options{methods}; |
3729
|
0
|
0
|
|
|
|
|
if(defined $methods){ |
3730
|
0
|
0
|
|
|
|
|
(ref $methods eq 'HASH') |
3731
|
|
|
|
|
|
|
|| $self->throw_error("You must pass a HASH ref of methods"); |
3732
|
|
|
|
|
|
|
} |
3733
|
0
|
|
|
|
|
|
my $roles = delete $options{roles}; |
3734
|
0
|
0
|
|
|
|
|
if(defined $roles){ |
3735
|
0
|
0
|
|
|
|
|
(ref $roles eq 'ARRAY') |
3736
|
|
|
|
|
|
|
|| $self->throw_error("You must pass an ARRAY ref of roles"); |
3737
|
|
|
|
|
|
|
} |
3738
|
0
|
|
|
|
|
|
my $mortal; |
3739
|
|
|
|
|
|
|
my $cache_key; |
3740
|
|
|
|
|
|
|
|
3741
|
0
|
0
|
|
|
|
|
if(!defined $package_name){ # anonymous |
3742
|
0
|
|
|
|
|
|
$mortal = !$options{cache}; |
3743
|
|
|
|
|
|
|
|
3744
|
|
|
|
|
|
|
# anonymous but immortal |
3745
|
0
|
0
|
|
|
|
|
if(!$mortal){ |
3746
|
|
|
|
|
|
|
# something like Super::Class|Super::Class::2=Role|Role::1 |
3747
|
0
|
0
|
|
|
|
|
$cache_key = join '=' => ( |
3748
|
0
|
0
|
|
|
|
|
join('|', @{$superclasses || []}), |
3749
|
0
|
|
|
|
|
|
join('|', sort @{$roles || []}), |
3750
|
|
|
|
|
|
|
); |
3751
|
0
|
0
|
|
|
|
|
return $IMMORTALS{$cache_key} if exists $IMMORTALS{$cache_key}; |
3752
|
|
|
|
|
|
|
} |
3753
|
0
|
|
|
|
|
|
$options{anon_serial_id} = ++$ANON_SERIAL; |
3754
|
0
|
|
|
|
|
|
$package_name = $class . '::__ANON__::' . $ANON_SERIAL; |
3755
|
|
|
|
|
|
|
} |
3756
|
|
|
|
|
|
|
|
3757
|
|
|
|
|
|
|
# instantiate a module |
3758
|
|
|
|
|
|
|
{ |
3759
|
2
|
|
|
2
|
|
10
|
no strict 'refs'; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
1080
|
|
|
0
|
|
|
|
|
|
|
3760
|
0
|
0
|
|
|
|
|
${ $package_name . '::VERSION' } = delete $options{version} if exists $options{version}; |
|
0
|
|
|
|
|
|
|
3761
|
0
|
0
|
|
|
|
|
${ $package_name . '::AUTHORITY' } = delete $options{authority} if exists $options{authority}; |
|
0
|
|
|
|
|
|
|
3762
|
|
|
|
|
|
|
} |
3763
|
|
|
|
|
|
|
|
3764
|
0
|
|
|
|
|
|
my $meta = $self->initialize( $package_name, %options); |
3765
|
|
|
|
|
|
|
|
3766
|
0
|
0
|
|
|
|
|
Scalar::Util::weaken $METAS{$package_name} |
3767
|
|
|
|
|
|
|
if $mortal; |
3768
|
|
|
|
|
|
|
|
3769
|
|
|
|
|
|
|
$meta->add_method(meta => sub { |
3770
|
0
|
|
0
|
0
|
|
|
$self->initialize(ref($_[0]) || $_[0]); |
3771
|
0
|
|
|
|
|
|
}); |
3772
|
|
|
|
|
|
|
|
3773
|
0
|
0
|
|
|
|
|
$meta->superclasses(@{$superclasses}) |
|
0
|
|
|
|
|
|
|
3774
|
|
|
|
|
|
|
if defined $superclasses; |
3775
|
|
|
|
|
|
|
|
3776
|
|
|
|
|
|
|
# NOTE: |
3777
|
|
|
|
|
|
|
# process attributes first, so that they can |
3778
|
|
|
|
|
|
|
# install accessors, but locally defined methods |
3779
|
|
|
|
|
|
|
# can then overwrite them. It is maybe a little odd, but |
3780
|
|
|
|
|
|
|
# I think this should be the order of things. |
3781
|
0
|
0
|
|
|
|
|
if (defined $attributes) { |
3782
|
0
|
0
|
|
|
|
|
if(ref($attributes) eq 'ARRAY'){ |
3783
|
|
|
|
|
|
|
# array of Scalar::Random::PP::OO::Meta::Attribute |
3784
|
0
|
|
|
|
|
|
foreach my $attr (@{$attributes}) { |
|
0
|
|
|
|
|
|
|
3785
|
0
|
|
|
|
|
|
$meta->add_attribute($attr); |
3786
|
|
|
|
|
|
|
} |
3787
|
|
|
|
|
|
|
} |
3788
|
|
|
|
|
|
|
else{ |
3789
|
|
|
|
|
|
|
# hash map of name and attribute spec pairs |
3790
|
0
|
|
|
|
|
|
while(my($name, $attr) = each %{$attributes}){ |
|
0
|
|
|
|
|
|
|
3791
|
0
|
|
|
|
|
|
$meta->add_attribute($name => $attr); |
3792
|
|
|
|
|
|
|
} |
3793
|
|
|
|
|
|
|
} |
3794
|
|
|
|
|
|
|
} |
3795
|
0
|
0
|
|
|
|
|
if (defined $methods) { |
3796
|
0
|
|
|
|
|
|
while(my($method_name, $method_body) = each %{$methods}){ |
|
0
|
|
|
|
|
|
|
3797
|
0
|
|
|
|
|
|
$meta->add_method($method_name, $method_body); |
3798
|
|
|
|
|
|
|
} |
3799
|
|
|
|
|
|
|
} |
3800
|
0
|
0
|
|
|
|
|
if (defined $roles){ |
3801
|
0
|
|
|
|
|
|
Scalar::Random::PP::OO::Util::apply_all_roles($package_name, @{$roles}); |
|
0
|
|
|
|
|
|
|
3802
|
|
|
|
|
|
|
} |
3803
|
|
|
|
|
|
|
|
3804
|
0
|
0
|
|
|
|
|
if($cache_key){ |
3805
|
0
|
|
|
|
|
|
$IMMORTALS{$cache_key} = $meta; |
3806
|
|
|
|
|
|
|
} |
3807
|
|
|
|
|
|
|
|
3808
|
0
|
|
|
|
|
|
return $meta; |
3809
|
|
|
|
|
|
|
} |
3810
|
|
|
|
|
|
|
|
3811
|
|
|
|
|
|
|
sub DESTROY{ |
3812
|
0
|
|
|
0
|
|
|
my($self) = @_; |
3813
|
|
|
|
|
|
|
|
3814
|
0
|
0
|
|
|
|
|
return if $Scalar::Random::PP::OO::Util::in_global_destruction; |
3815
|
|
|
|
|
|
|
|
3816
|
0
|
|
|
|
|
|
my $serial_id = $self->{anon_serial_id}; |
3817
|
|
|
|
|
|
|
|
3818
|
0
|
0
|
|
|
|
|
return if !$serial_id; |
3819
|
|
|
|
|
|
|
# mortal anonymous class |
3820
|
|
|
|
|
|
|
|
3821
|
|
|
|
|
|
|
# XXX: cleaning stash with threads causes panic/SEGV. |
3822
|
0
|
0
|
|
|
|
|
if(exists $INC{'threads.pm'}) { |
3823
|
|
|
|
|
|
|
# (caller)[2] indicates the caller's line number, |
3824
|
|
|
|
|
|
|
# which is zero when the current thread is joining. |
3825
|
0
|
0
|
|
|
|
|
return if( (caller)[2] == 0); |
3826
|
|
|
|
|
|
|
} |
3827
|
|
|
|
|
|
|
|
3828
|
|
|
|
|
|
|
# @ISA is a magical variable, so we clear it manually. |
3829
|
0
|
0
|
|
|
|
|
@{$self->{superclasses}} = () if exists $self->{superclasses}; |
|
0
|
|
|
|
|
|
|
3830
|
|
|
|
|
|
|
|
3831
|
|
|
|
|
|
|
# Then, clear the symbol table hash |
3832
|
0
|
|
|
|
|
|
%{$self->namespace} = (); |
|
0
|
|
|
|
|
|
|
3833
|
|
|
|
|
|
|
|
3834
|
0
|
|
|
|
|
|
my $name = $self->name; |
3835
|
0
|
|
|
|
|
|
delete $METAS{$name}; |
3836
|
|
|
|
|
|
|
|
3837
|
0
|
|
|
|
|
|
$name =~ s/ $serial_id \z//xms; |
3838
|
2
|
|
|
2
|
|
11
|
no strict 'refs'; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
337
|
|
3839
|
0
|
|
|
|
|
|
delete ${$name}{ $serial_id . '::' }; |
|
0
|
|
|
|
|
|
|
3840
|
|
|
|
|
|
|
|
3841
|
0
|
|
|
|
|
|
return; |
3842
|
|
|
|
|
|
|
} |
3843
|
|
|
|
|
|
|
|
3844
|
|
|
|
|
|
|
sub throw_error{ |
3845
|
0
|
|
|
0
|
0
|
|
my($self, $message, %args) = @_; |
3846
|
|
|
|
|
|
|
|
3847
|
0
|
|
0
|
|
|
|
local $Carp::CarpLevel = $Carp::CarpLevel + 1 + ($args{depth} || 0); |
3848
|
0
|
|
|
|
|
|
local $Carp::MaxArgNums = 20; # default is 8, usually we use named args which gets messier though |
3849
|
|
|
|
|
|
|
|
3850
|
0
|
0
|
0
|
|
|
|
if(exists $args{longmess} && !$args{longmess}){ # intentionaly longmess => 0 |
3851
|
0
|
|
|
|
|
|
Carp::croak($message); |
3852
|
|
|
|
|
|
|
} |
3853
|
|
|
|
|
|
|
else{ |
3854
|
0
|
|
|
|
|
|
Carp::confess($message); |
3855
|
|
|
|
|
|
|
} |
3856
|
|
|
|
|
|
|
} |
3857
|
|
|
|
|
|
|
|
3858
|
|
|
|
|
|
|
# Contents of Mouse::Meta::Role |
3859
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Role; |
3860
|
2
|
|
|
2
|
|
8
|
use Scalar::Random::PP::OO::Util qw(:meta not_supported); # enables strict and warnings |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
7
|
|
3861
|
|
|
|
|
|
|
|
3862
|
2
|
|
|
2
|
|
9
|
use Scalar::Random::PP::OO::Meta::Module; |
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
4282
|
|
3863
|
|
|
|
|
|
|
our @ISA = qw(Scalar::Random::PP::OO::Meta::Module); |
3864
|
|
|
|
|
|
|
|
3865
|
|
|
|
|
|
|
sub method_metaclass; |
3866
|
|
|
|
|
|
|
|
3867
|
|
|
|
|
|
|
sub _construct_meta { |
3868
|
0
|
|
|
0
|
|
|
my $class = shift; |
3869
|
|
|
|
|
|
|
|
3870
|
0
|
|
|
|
|
|
my %args = @_; |
3871
|
|
|
|
|
|
|
|
3872
|
0
|
|
|
|
|
|
$args{methods} = {}; |
3873
|
0
|
|
|
|
|
|
$args{attributes} = {}; |
3874
|
0
|
|
|
|
|
|
$args{required_methods} = []; |
3875
|
0
|
|
|
|
|
|
$args{roles} = []; |
3876
|
|
|
|
|
|
|
|
3877
|
0
|
|
0
|
|
|
|
my $self = bless \%args, ref($class) || $class; |
3878
|
0
|
0
|
|
|
|
|
if($class ne __PACKAGE__){ |
3879
|
0
|
|
|
|
|
|
$self->meta->_initialize_object($self, \%args); |
3880
|
|
|
|
|
|
|
} |
3881
|
|
|
|
|
|
|
|
3882
|
0
|
|
|
|
|
|
return $self; |
3883
|
|
|
|
|
|
|
} |
3884
|
|
|
|
|
|
|
|
3885
|
|
|
|
|
|
|
sub create_anon_role{ |
3886
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
3887
|
0
|
|
|
|
|
|
return $self->create(undef, @_); |
3888
|
|
|
|
|
|
|
} |
3889
|
|
|
|
|
|
|
|
3890
|
|
|
|
|
|
|
sub is_anon_role; |
3891
|
|
|
|
|
|
|
|
3892
|
|
|
|
|
|
|
sub get_roles; |
3893
|
|
|
|
|
|
|
|
3894
|
|
|
|
|
|
|
sub calculate_all_roles { |
3895
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
3896
|
0
|
|
|
|
|
|
my %seen; |
3897
|
0
|
|
|
|
|
|
return grep { !$seen{ $_->name }++ } |
|
0
|
|
|
|
|
|
|
3898
|
0
|
|
|
|
|
|
($self, map { $_->calculate_all_roles } @{ $self->get_roles }); |
|
0
|
|
|
|
|
|
|
3899
|
|
|
|
|
|
|
} |
3900
|
|
|
|
|
|
|
|
3901
|
|
|
|
|
|
|
sub get_required_method_list{ |
3902
|
0
|
|
|
0
|
0
|
|
return @{ $_[0]->{required_methods} }; |
|
0
|
|
|
|
|
|
|
3903
|
|
|
|
|
|
|
} |
3904
|
|
|
|
|
|
|
|
3905
|
|
|
|
|
|
|
sub add_required_methods { |
3906
|
0
|
|
|
0
|
0
|
|
my($self, @methods) = @_; |
3907
|
0
|
|
|
|
|
|
my %required = map{ $_ => 1 } @{$self->{required_methods}}; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
3908
|
0
|
|
0
|
|
|
|
push @{$self->{required_methods}}, grep{ !$required{$_}++ && !$self->has_method($_) } @methods; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
3909
|
0
|
|
|
|
|
|
return; |
3910
|
|
|
|
|
|
|
} |
3911
|
|
|
|
|
|
|
|
3912
|
|
|
|
|
|
|
sub requires_method { |
3913
|
0
|
|
|
0
|
0
|
|
my($self, $name) = @_; |
3914
|
0
|
|
|
|
|
|
return scalar( grep{ $_ eq $name } @{ $self->{required_methods} } ) != 0; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
3915
|
|
|
|
|
|
|
} |
3916
|
|
|
|
|
|
|
|
3917
|
|
|
|
|
|
|
sub add_attribute { |
3918
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
3919
|
0
|
|
|
|
|
|
my $name = shift; |
3920
|
|
|
|
|
|
|
|
3921
|
0
|
0
|
|
|
|
|
$self->{attributes}->{$name} = (@_ == 1) ? $_[0] : { @_ }; |
3922
|
0
|
|
|
|
|
|
return; |
3923
|
|
|
|
|
|
|
} |
3924
|
|
|
|
|
|
|
|
3925
|
|
|
|
|
|
|
sub _check_required_methods{ |
3926
|
0
|
|
|
0
|
|
|
my($role, $consumer, $args) = @_; |
3927
|
|
|
|
|
|
|
|
3928
|
0
|
0
|
|
|
|
|
if($args->{_to} eq 'role'){ |
3929
|
0
|
|
|
|
|
|
$consumer->add_required_methods($role->get_required_method_list); |
3930
|
|
|
|
|
|
|
} |
3931
|
|
|
|
|
|
|
else{ # to class or instance |
3932
|
0
|
|
|
|
|
|
my $consumer_class_name = $consumer->name; |
3933
|
|
|
|
|
|
|
|
3934
|
0
|
|
|
|
|
|
my @missing; |
3935
|
0
|
|
|
|
|
|
foreach my $method_name(@{$role->{required_methods}}){ |
|
0
|
|
|
|
|
|
|
3936
|
0
|
0
|
|
|
|
|
next if exists $args->{aliased_methods}{$method_name}; |
3937
|
0
|
0
|
|
|
|
|
next if exists $role->{methods}{$method_name}; |
3938
|
0
|
0
|
|
|
|
|
next if $consumer_class_name->can($method_name); |
3939
|
|
|
|
|
|
|
|
3940
|
0
|
|
|
|
|
|
push @missing, $method_name; |
3941
|
|
|
|
|
|
|
} |
3942
|
0
|
0
|
|
|
|
|
if(@missing){ |
3943
|
0
|
0
|
|
|
|
|
$role->throw_error(sprintf "'%s' requires the method%s %s to be implemented by '%s'", |
3944
|
|
|
|
|
|
|
$role->name, |
3945
|
|
|
|
|
|
|
(@missing == 1 ? '' : 's'), # method or methods |
3946
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Util::quoted_english_list(@missing), |
3947
|
|
|
|
|
|
|
$consumer_class_name); |
3948
|
|
|
|
|
|
|
} |
3949
|
|
|
|
|
|
|
} |
3950
|
|
|
|
|
|
|
|
3951
|
0
|
|
|
|
|
|
return; |
3952
|
|
|
|
|
|
|
} |
3953
|
|
|
|
|
|
|
|
3954
|
|
|
|
|
|
|
sub _apply_methods{ |
3955
|
0
|
|
|
0
|
|
|
my($role, $consumer, $args) = @_; |
3956
|
|
|
|
|
|
|
|
3957
|
0
|
|
|
|
|
|
my $alias = $args->{-alias}; |
3958
|
0
|
|
|
|
|
|
my $excludes = $args->{-excludes}; |
3959
|
|
|
|
|
|
|
|
3960
|
0
|
|
|
|
|
|
foreach my $method_name($role->get_method_list){ |
3961
|
0
|
0
|
|
|
|
|
next if $method_name eq 'meta'; |
3962
|
|
|
|
|
|
|
|
3963
|
0
|
|
|
|
|
|
my $code = $role->get_method_body($method_name); |
3964
|
|
|
|
|
|
|
|
3965
|
0
|
0
|
|
|
|
|
if(!exists $excludes->{$method_name}){ |
3966
|
0
|
0
|
|
|
|
|
if(!$consumer->has_method($method_name)){ |
3967
|
|
|
|
|
|
|
# The third argument $role is used in Role::Composite |
3968
|
0
|
|
|
|
|
|
$consumer->add_method($method_name => $code, $role); |
3969
|
|
|
|
|
|
|
} |
3970
|
|
|
|
|
|
|
} |
3971
|
|
|
|
|
|
|
|
3972
|
0
|
0
|
|
|
|
|
if(exists $alias->{$method_name}){ |
3973
|
0
|
|
|
|
|
|
my $dstname = $alias->{$method_name}; |
3974
|
|
|
|
|
|
|
|
3975
|
0
|
|
|
|
|
|
my $dstcode = $consumer->get_method_body($dstname); |
3976
|
|
|
|
|
|
|
|
3977
|
0
|
0
|
0
|
|
|
|
if(defined($dstcode) && $dstcode != $code){ |
3978
|
0
|
|
|
|
|
|
$role->throw_error("Cannot create a method alias if a local method of the same name exists"); |
3979
|
|
|
|
|
|
|
} |
3980
|
|
|
|
|
|
|
else{ |
3981
|
0
|
|
|
|
|
|
$consumer->add_method($dstname => $code, $role); |
3982
|
|
|
|
|
|
|
} |
3983
|
|
|
|
|
|
|
} |
3984
|
|
|
|
|
|
|
} |
3985
|
|
|
|
|
|
|
|
3986
|
0
|
|
|
|
|
|
return; |
3987
|
|
|
|
|
|
|
} |
3988
|
|
|
|
|
|
|
|
3989
|
|
|
|
|
|
|
sub _apply_attributes{ |
3990
|
|
|
|
|
|
|
#my($role, $consumer, $args) = @_; |
3991
|
0
|
|
|
0
|
|
|
my($role, $consumer) = @_; |
3992
|
|
|
|
|
|
|
|
3993
|
0
|
|
|
|
|
|
for my $attr_name ($role->get_attribute_list) { |
3994
|
0
|
0
|
|
|
|
|
next if $consumer->has_attribute($attr_name); |
3995
|
|
|
|
|
|
|
|
3996
|
0
|
|
|
|
|
|
$consumer->add_attribute($attr_name => $role->get_attribute($attr_name)); |
3997
|
|
|
|
|
|
|
} |
3998
|
0
|
|
|
|
|
|
return; |
3999
|
|
|
|
|
|
|
} |
4000
|
|
|
|
|
|
|
|
4001
|
|
|
|
|
|
|
sub _apply_modifiers{ |
4002
|
|
|
|
|
|
|
#my($role, $consumer, $args) = @_; |
4003
|
0
|
|
|
0
|
|
|
my($role, $consumer) = @_; |
4004
|
|
|
|
|
|
|
|
4005
|
|
|
|
|
|
|
|
4006
|
0
|
0
|
|
|
|
|
if(my $modifiers = $role->{override_method_modifiers}){ |
4007
|
0
|
|
|
|
|
|
foreach my $method_name (keys %{$modifiers}){ |
|
0
|
|
|
|
|
|
|
4008
|
0
|
|
|
|
|
|
$consumer->add_override_method_modifier($method_name => $modifiers->{$method_name}); |
4009
|
|
|
|
|
|
|
} |
4010
|
|
|
|
|
|
|
} |
4011
|
|
|
|
|
|
|
|
4012
|
0
|
|
|
|
|
|
for my $modifier_type (qw/before around after/) { |
4013
|
0
|
0
|
|
|
|
|
my $table = $role->{"${modifier_type}_method_modifiers"} |
4014
|
|
|
|
|
|
|
or next; |
4015
|
|
|
|
|
|
|
|
4016
|
0
|
|
|
|
|
|
my $add_modifier = "add_${modifier_type}_method_modifier"; |
4017
|
|
|
|
|
|
|
|
4018
|
0
|
|
|
|
|
|
while(my($method_name, $modifiers) = each %{$table}){ |
|
0
|
|
|
|
|
|
|
4019
|
0
|
|
|
|
|
|
foreach my $code(@{ $modifiers }){ |
|
0
|
|
|
|
|
|
|
4020
|
0
|
0
|
|
|
|
|
next if $consumer->{"_applied_$modifier_type"}{$method_name, $code}++; # skip applied modifiers |
4021
|
0
|
|
|
|
|
|
$consumer->$add_modifier($method_name => $code); |
4022
|
|
|
|
|
|
|
} |
4023
|
|
|
|
|
|
|
} |
4024
|
|
|
|
|
|
|
} |
4025
|
0
|
|
|
|
|
|
return; |
4026
|
|
|
|
|
|
|
} |
4027
|
|
|
|
|
|
|
|
4028
|
|
|
|
|
|
|
sub _append_roles{ |
4029
|
|
|
|
|
|
|
#my($role, $consumer, $args) = @_; |
4030
|
0
|
|
|
0
|
|
|
my($role, $consumer) = @_; |
4031
|
|
|
|
|
|
|
|
4032
|
0
|
|
|
|
|
|
my $roles = $consumer->{roles}; |
4033
|
|
|
|
|
|
|
|
4034
|
0
|
|
|
|
|
|
foreach my $r($role, @{$role->get_roles}){ |
|
0
|
|
|
|
|
|
|
4035
|
0
|
0
|
|
|
|
|
if(!$consumer->does_role($r)){ |
4036
|
0
|
|
|
|
|
|
push @{$roles}, $r; |
|
0
|
|
|
|
|
|
|
4037
|
|
|
|
|
|
|
} |
4038
|
|
|
|
|
|
|
} |
4039
|
0
|
|
|
|
|
|
return; |
4040
|
|
|
|
|
|
|
} |
4041
|
|
|
|
|
|
|
|
4042
|
|
|
|
|
|
|
# Moose uses Application::ToInstance, Application::ToClass, Application::ToRole |
4043
|
|
|
|
|
|
|
sub apply { |
4044
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
4045
|
0
|
|
|
|
|
|
my $consumer = shift; |
4046
|
|
|
|
|
|
|
|
4047
|
0
|
0
|
|
|
|
|
my %args = (@_ == 1) ? %{ $_[0] } : @_; |
|
0
|
|
|
|
|
|
|
4048
|
|
|
|
|
|
|
|
4049
|
0
|
|
|
|
|
|
my $instance; |
4050
|
|
|
|
|
|
|
|
4051
|
0
|
0
|
|
|
|
|
if(Scalar::Random::PP::OO::Util::is_a_metaclass($consumer)){ # Application::ToClass |
|
|
0
|
|
|
|
|
|
4052
|
0
|
|
|
|
|
|
$args{_to} = 'class'; |
4053
|
|
|
|
|
|
|
} |
4054
|
|
|
|
|
|
|
elsif(Scalar::Random::PP::OO::Util::is_a_metarole($consumer)){ # Application::ToRole |
4055
|
0
|
|
|
|
|
|
$args{_to} = 'role'; |
4056
|
|
|
|
|
|
|
} |
4057
|
|
|
|
|
|
|
else{ # Appplication::ToInstance |
4058
|
0
|
|
|
|
|
|
$args{_to} = 'instance'; |
4059
|
0
|
|
|
|
|
|
$instance = $consumer; |
4060
|
|
|
|
|
|
|
|
4061
|
0
|
|
0
|
|
|
|
$consumer = (Scalar::Random::PP::OO::Util::class_of($instance) || 'Scalar::Random::PP::OO::Meta::Class')->create_anon_class( |
4062
|
|
|
|
|
|
|
superclasses => [ref $instance], |
4063
|
|
|
|
|
|
|
cache => 1, |
4064
|
|
|
|
|
|
|
); |
4065
|
|
|
|
|
|
|
} |
4066
|
|
|
|
|
|
|
|
4067
|
0
|
0
|
0
|
|
|
|
if($args{alias} && !exists $args{-alias}){ |
4068
|
0
|
|
|
|
|
|
$args{-alias} = $args{alias}; |
4069
|
|
|
|
|
|
|
} |
4070
|
0
|
0
|
0
|
|
|
|
if($args{excludes} && !exists $args{-excludes}){ |
4071
|
0
|
|
|
|
|
|
$args{-excludes} = $args{excludes}; |
4072
|
|
|
|
|
|
|
} |
4073
|
|
|
|
|
|
|
|
4074
|
0
|
|
|
|
|
|
$args{aliased_methods} = {}; |
4075
|
0
|
0
|
|
|
|
|
if(my $alias = $args{-alias}){ |
4076
|
0
|
|
|
|
|
|
@{$args{aliased_methods}}{ values %{$alias} } = (); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4077
|
|
|
|
|
|
|
} |
4078
|
|
|
|
|
|
|
|
4079
|
0
|
0
|
|
|
|
|
if(my $excludes = $args{-excludes}){ |
4080
|
0
|
|
|
|
|
|
$args{-excludes} = {}; # replace with a hash ref |
4081
|
0
|
0
|
|
|
|
|
if(ref $excludes){ |
4082
|
0
|
|
|
|
|
|
%{$args{-excludes}} = (map{ $_ => undef } @{$excludes}); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4083
|
|
|
|
|
|
|
} |
4084
|
|
|
|
|
|
|
else{ |
4085
|
0
|
|
|
|
|
|
$args{-excludes}{$excludes} = undef; |
4086
|
|
|
|
|
|
|
} |
4087
|
|
|
|
|
|
|
} |
4088
|
|
|
|
|
|
|
|
4089
|
0
|
|
|
|
|
|
$self->_check_required_methods($consumer, \%args); |
4090
|
0
|
|
|
|
|
|
$self->_apply_attributes($consumer, \%args); |
4091
|
0
|
|
|
|
|
|
$self->_apply_methods($consumer, \%args); |
4092
|
0
|
|
|
|
|
|
$self->_apply_modifiers($consumer, \%args); |
4093
|
0
|
|
|
|
|
|
$self->_append_roles($consumer, \%args); |
4094
|
|
|
|
|
|
|
|
4095
|
|
|
|
|
|
|
|
4096
|
0
|
0
|
|
|
|
|
if(defined $instance){ # Application::ToInstance |
4097
|
|
|
|
|
|
|
# rebless instance |
4098
|
0
|
|
|
|
|
|
bless $instance, $consumer->name; |
4099
|
0
|
|
|
|
|
|
$consumer->_initialize_object($instance, $instance, 1); |
4100
|
|
|
|
|
|
|
} |
4101
|
|
|
|
|
|
|
|
4102
|
0
|
|
|
|
|
|
return; |
4103
|
|
|
|
|
|
|
} |
4104
|
|
|
|
|
|
|
|
4105
|
|
|
|
|
|
|
|
4106
|
|
|
|
|
|
|
sub combine { |
4107
|
0
|
|
|
0
|
0
|
|
my($self, @role_specs) = @_; |
4108
|
|
|
|
|
|
|
|
4109
|
0
|
|
|
|
|
|
require 'Scalar/Random/PP/OO/Meta/Role/Composite.pm'; # we don't want to create its namespace |
4110
|
|
|
|
|
|
|
|
4111
|
0
|
|
|
|
|
|
my $composite = Scalar::Random::PP::OO::Meta::Role::Composite->create_anon_role(); |
4112
|
|
|
|
|
|
|
|
4113
|
0
|
|
|
|
|
|
foreach my $role_spec (@role_specs) { |
4114
|
0
|
|
|
|
|
|
my($role_name, $args) = @{$role_spec}; |
|
0
|
|
|
|
|
|
|
4115
|
0
|
|
|
|
|
|
$role_name->meta->apply($composite, %{$args}); |
|
0
|
|
|
|
|
|
|
4116
|
|
|
|
|
|
|
} |
4117
|
0
|
|
|
|
|
|
return $composite; |
4118
|
|
|
|
|
|
|
} |
4119
|
|
|
|
|
|
|
|
4120
|
|
|
|
|
|
|
sub add_before_method_modifier; |
4121
|
|
|
|
|
|
|
sub add_around_method_modifier; |
4122
|
|
|
|
|
|
|
sub add_after_method_modifier; |
4123
|
|
|
|
|
|
|
|
4124
|
|
|
|
|
|
|
sub get_before_method_modifiers; |
4125
|
|
|
|
|
|
|
sub get_around_method_modifiers; |
4126
|
|
|
|
|
|
|
sub get_after_method_modifiers; |
4127
|
|
|
|
|
|
|
|
4128
|
|
|
|
|
|
|
sub add_override_method_modifier{ |
4129
|
0
|
|
|
0
|
0
|
|
my($self, $method_name, $method) = @_; |
4130
|
|
|
|
|
|
|
|
4131
|
0
|
0
|
|
|
|
|
if($self->has_method($method_name)){ |
4132
|
|
|
|
|
|
|
# This error happens in the override keyword or during role composition, |
4133
|
|
|
|
|
|
|
# so I added a message, "A local method of ...", only for compatibility (gfx) |
4134
|
0
|
|
|
|
|
|
$self->throw_error("Cannot add an override of method '$method_name' " |
4135
|
|
|
|
|
|
|
. "because there is a local version of '$method_name'" |
4136
|
|
|
|
|
|
|
. "(A local method of the same name as been found)"); |
4137
|
|
|
|
|
|
|
} |
4138
|
|
|
|
|
|
|
|
4139
|
0
|
|
|
|
|
|
$self->{override_method_modifiers}->{$method_name} = $method; |
4140
|
|
|
|
|
|
|
} |
4141
|
|
|
|
|
|
|
|
4142
|
|
|
|
|
|
|
sub get_override_method_modifier { |
4143
|
0
|
|
|
0
|
0
|
|
my ($self, $method_name) = @_; |
4144
|
0
|
|
|
|
|
|
return $self->{override_method_modifiers}->{$method_name}; |
4145
|
|
|
|
|
|
|
} |
4146
|
|
|
|
|
|
|
|
4147
|
|
|
|
|
|
|
sub does_role { |
4148
|
0
|
|
|
0
|
0
|
|
my ($self, $role_name) = @_; |
4149
|
|
|
|
|
|
|
|
4150
|
0
|
0
|
|
|
|
|
(defined $role_name) |
4151
|
|
|
|
|
|
|
|| $self->throw_error("You must supply a role name to look for"); |
4152
|
|
|
|
|
|
|
|
4153
|
0
|
0
|
|
|
|
|
$role_name = $role_name->name if ref $role_name; |
4154
|
|
|
|
|
|
|
|
4155
|
|
|
|
|
|
|
# if we are it,.. then return true |
4156
|
0
|
0
|
|
|
|
|
return 1 if $role_name eq $self->name; |
4157
|
|
|
|
|
|
|
# otherwise.. check our children |
4158
|
0
|
|
|
|
|
|
for my $role (@{ $self->get_roles }) { |
|
0
|
|
|
|
|
|
|
4159
|
0
|
0
|
|
|
|
|
return 1 if $role->does_role($role_name); |
4160
|
|
|
|
|
|
|
} |
4161
|
0
|
|
|
|
|
|
return 0; |
4162
|
|
|
|
|
|
|
} |
4163
|
|
|
|
|
|
|
|
4164
|
|
|
|
|
|
|
# Contents of Mouse::Meta::Role::Composite |
4165
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Role::Composite; |
4166
|
2
|
|
|
2
|
|
17
|
use Scalar::Random::PP::OO::Util; # enables strict and warnings |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
8
|
|
4167
|
2
|
|
|
2
|
|
9
|
use Scalar::Random::PP::OO::Meta::Role; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
1635
|
|
4168
|
|
|
|
|
|
|
our @ISA = qw(Scalar::Random::PP::OO::Meta::Role); |
4169
|
|
|
|
|
|
|
|
4170
|
|
|
|
|
|
|
sub get_method_list{ |
4171
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
4172
|
0
|
|
|
|
|
|
return keys %{ $self->{methods} }; |
|
0
|
|
|
|
|
|
|
4173
|
|
|
|
|
|
|
} |
4174
|
|
|
|
|
|
|
|
4175
|
|
|
|
|
|
|
sub add_method { |
4176
|
0
|
|
|
0
|
0
|
|
my($self, $method_name, $code, $role) = @_; |
4177
|
|
|
|
|
|
|
|
4178
|
0
|
0
|
0
|
|
|
|
if( ($self->{methods}{$method_name} || 0) == $code){ |
4179
|
|
|
|
|
|
|
# This role already has the same method. |
4180
|
0
|
|
|
|
|
|
return; |
4181
|
|
|
|
|
|
|
} |
4182
|
|
|
|
|
|
|
|
4183
|
0
|
0
|
|
|
|
|
if($method_name eq 'meta'){ |
4184
|
0
|
|
|
|
|
|
$self->SUPER::add_method($method_name => $code); |
4185
|
|
|
|
|
|
|
} |
4186
|
|
|
|
|
|
|
else{ |
4187
|
|
|
|
|
|
|
# no need to add a subroutine to the stash |
4188
|
0
|
|
0
|
|
|
|
my $roles = $self->{composed_roles_by_method}{$method_name} ||= []; |
4189
|
0
|
|
|
|
|
|
push @{$roles}, $role; |
|
0
|
|
|
|
|
|
|
4190
|
0
|
0
|
|
|
|
|
if(@{$roles} > 1){ |
|
0
|
|
|
|
|
|
|
4191
|
0
|
|
|
|
|
|
$self->{conflicting_methods}{$method_name}++; |
4192
|
|
|
|
|
|
|
} |
4193
|
0
|
|
|
|
|
|
$self->{methods}{$method_name} = $code; |
4194
|
|
|
|
|
|
|
} |
4195
|
0
|
|
|
|
|
|
return; |
4196
|
|
|
|
|
|
|
} |
4197
|
|
|
|
|
|
|
|
4198
|
|
|
|
|
|
|
sub get_method_body { |
4199
|
0
|
|
|
0
|
0
|
|
my($self, $method_name) = @_; |
4200
|
0
|
|
|
|
|
|
return $self->{methods}{$method_name}; |
4201
|
|
|
|
|
|
|
} |
4202
|
|
|
|
|
|
|
|
4203
|
|
|
|
|
|
|
sub has_method { |
4204
|
|
|
|
|
|
|
# my($self, $method_name) = @_; |
4205
|
0
|
|
|
0
|
0
|
|
return 0; # to fool _apply_methods() in combine() |
4206
|
|
|
|
|
|
|
} |
4207
|
|
|
|
|
|
|
|
4208
|
|
|
|
|
|
|
sub has_attribute{ |
4209
|
|
|
|
|
|
|
# my($self, $method_name) = @_; |
4210
|
0
|
|
|
0
|
0
|
|
return 0; # to fool _appply_attributes() in combine() |
4211
|
|
|
|
|
|
|
} |
4212
|
|
|
|
|
|
|
|
4213
|
|
|
|
|
|
|
sub has_override_method_modifier{ |
4214
|
|
|
|
|
|
|
# my($self, $method_name) = @_; |
4215
|
0
|
|
|
0
|
0
|
|
return 0; # to fool _apply_modifiers() in combine() |
4216
|
|
|
|
|
|
|
} |
4217
|
|
|
|
|
|
|
|
4218
|
|
|
|
|
|
|
sub add_attribute{ |
4219
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
4220
|
0
|
|
|
|
|
|
my $attr_name = shift; |
4221
|
0
|
0
|
|
|
|
|
my $spec = (@_ == 1 ? $_[0] : {@_}); |
4222
|
|
|
|
|
|
|
|
4223
|
0
|
|
|
|
|
|
my $existing = $self->{attributes}{$attr_name}; |
4224
|
0
|
0
|
0
|
|
|
|
if($existing && $existing != $spec){ |
4225
|
0
|
|
|
|
|
|
$self->throw_error("We have encountered an attribute conflict with '$attr_name' " |
4226
|
|
|
|
|
|
|
. "during composition. This is fatal error and cannot be disambiguated."); |
4227
|
|
|
|
|
|
|
} |
4228
|
0
|
|
|
|
|
|
$self->SUPER::add_attribute($attr_name, $spec); |
4229
|
0
|
|
|
|
|
|
return; |
4230
|
|
|
|
|
|
|
} |
4231
|
|
|
|
|
|
|
|
4232
|
|
|
|
|
|
|
sub add_override_method_modifier{ |
4233
|
0
|
|
|
0
|
0
|
|
my($self, $method_name, $code) = @_; |
4234
|
|
|
|
|
|
|
|
4235
|
0
|
|
|
|
|
|
my $existing = $self->{override_method_modifiers}{$method_name}; |
4236
|
0
|
0
|
0
|
|
|
|
if($existing && $existing != $code){ |
4237
|
0
|
|
|
|
|
|
$self->throw_error( "We have encountered an 'override' method conflict with '$method_name' during " |
4238
|
|
|
|
|
|
|
. "composition (Two 'override' methods of the same name encountered). " |
4239
|
|
|
|
|
|
|
. "This is fatal error.") |
4240
|
|
|
|
|
|
|
} |
4241
|
0
|
|
|
|
|
|
$self->SUPER::add_override_method_modifier($method_name, $code); |
4242
|
0
|
|
|
|
|
|
return; |
4243
|
|
|
|
|
|
|
} |
4244
|
|
|
|
|
|
|
|
4245
|
|
|
|
|
|
|
# components of apply() |
4246
|
|
|
|
|
|
|
|
4247
|
|
|
|
|
|
|
sub _apply_methods{ |
4248
|
0
|
|
|
0
|
|
|
my($self, $consumer, $args) = @_; |
4249
|
|
|
|
|
|
|
|
4250
|
0
|
0
|
|
|
|
|
if(exists $self->{conflicting_methods}){ |
4251
|
0
|
|
|
|
|
|
my $consumer_class_name = $consumer->name; |
4252
|
|
|
|
|
|
|
|
4253
|
0
|
|
|
|
|
|
my @conflicting = grep{ !$consumer_class_name->can($_) } keys %{ $self->{conflicting_methods} }; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4254
|
|
|
|
|
|
|
|
4255
|
0
|
0
|
|
|
|
|
if(@conflicting == 1){ |
|
|
0
|
|
|
|
|
|
4256
|
0
|
|
|
|
|
|
my $method_name = $conflicting[0]; |
4257
|
0
|
|
|
|
|
|
my $roles = Scalar::Random::PP::OO::Util::quoted_english_list(map{ $_->name } @{ $self->{composed_roles_by_method}{$method_name} }); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4258
|
0
|
|
|
|
|
|
$self->throw_error( |
4259
|
|
|
|
|
|
|
sprintf q{Due to a method name conflict in roles %s, the method '%s' must be implemented or excluded by '%s'}, |
4260
|
|
|
|
|
|
|
$roles, $method_name, $consumer_class_name |
4261
|
|
|
|
|
|
|
); |
4262
|
|
|
|
|
|
|
} |
4263
|
|
|
|
|
|
|
elsif(@conflicting > 1){ |
4264
|
0
|
|
|
|
|
|
my %seen; |
4265
|
0
|
|
|
|
|
|
my $roles = Scalar::Random::PP::OO::Util::quoted_english_list( |
4266
|
0
|
|
|
|
|
|
grep{ !$seen{$_}++ } # uniq |
4267
|
0
|
|
|
|
|
|
map { $_->name } |
4268
|
0
|
|
|
|
|
|
map { @{$_} } @{ $self->{composed_roles_by_method} }{@conflicting} |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4269
|
|
|
|
|
|
|
); |
4270
|
|
|
|
|
|
|
|
4271
|
0
|
|
|
|
|
|
$self->throw_error( |
4272
|
|
|
|
|
|
|
sprintf q{Due to method name conflicts in roles %s, the methods %s must be implemented or excluded by '%s'}, |
4273
|
|
|
|
|
|
|
$roles, |
4274
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Util::quoted_english_list(@conflicting), |
4275
|
|
|
|
|
|
|
$consumer_class_name |
4276
|
|
|
|
|
|
|
); |
4277
|
|
|
|
|
|
|
} |
4278
|
|
|
|
|
|
|
} |
4279
|
|
|
|
|
|
|
|
4280
|
0
|
|
|
|
|
|
$self->SUPER::_apply_methods($consumer, $args); |
4281
|
0
|
|
|
|
|
|
return; |
4282
|
|
|
|
|
|
|
} |
4283
|
|
|
|
|
|
|
# Contents of Mouse::Meta::Role::Method |
4284
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Meta::Role::Method; |
4285
|
2
|
|
|
2
|
|
12
|
use Scalar::Random::PP::OO::Util; # enables strict and warnings |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
7
|
|
4286
|
|
|
|
|
|
|
|
4287
|
2
|
|
|
2
|
|
14
|
use Scalar::Random::PP::OO::Meta::Method; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
283
|
|
4288
|
|
|
|
|
|
|
our @ISA = qw(Scalar::Random::PP::OO::Meta::Method); |
4289
|
|
|
|
|
|
|
|
4290
|
|
|
|
|
|
|
sub _new{ |
4291
|
0
|
|
|
0
|
|
|
my($class, %args) = @_; |
4292
|
0
|
|
|
|
|
|
my $self = bless \%args, $class; |
4293
|
|
|
|
|
|
|
|
4294
|
0
|
0
|
|
|
|
|
if($class ne __PACKAGE__){ |
4295
|
0
|
|
|
|
|
|
$self->meta->_initialize_object($self, \%args); |
4296
|
|
|
|
|
|
|
} |
4297
|
0
|
|
|
|
|
|
return $self; |
4298
|
|
|
|
|
|
|
} |
4299
|
|
|
|
|
|
|
|
4300
|
|
|
|
|
|
|
# Contents of Mouse::Object |
4301
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Object; |
4302
|
2
|
|
|
2
|
|
9
|
use Scalar::Random::PP::OO::Util qw(does dump meta); # enables strict and warnings |
|
2
|
|
|
|
|
1210
|
|
|
2
|
|
|
|
|
7
|
|
4303
|
|
|
|
|
|
|
|
4304
|
|
|
|
|
|
|
sub new; |
4305
|
|
|
|
|
|
|
sub BUILDARGS; |
4306
|
|
|
|
|
|
|
sub BUILDALL; |
4307
|
|
|
|
|
|
|
|
4308
|
|
|
|
|
|
|
sub DESTROY; |
4309
|
|
|
|
|
|
|
sub DEMOLISHALL; |
4310
|
|
|
|
|
|
|
|
4311
|
|
|
|
|
|
|
# Contents of Mouse::Role |
4312
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Role; |
4313
|
2
|
|
|
2
|
|
12
|
use Scalar::Random::PP::OO::Exporter; # enables strict and warnings |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
9
|
|
4314
|
|
|
|
|
|
|
|
4315
|
|
|
|
|
|
|
our $VERSION = '0.70'; |
4316
|
|
|
|
|
|
|
|
4317
|
2
|
|
|
2
|
|
9
|
use Carp qw(confess); |
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
135
|
|
4318
|
2
|
|
|
2
|
|
10
|
use Scalar::Util qw(blessed); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
94
|
|
4319
|
|
|
|
|
|
|
|
4320
|
2
|
|
|
2
|
|
8
|
use Scalar::Random::PP::OO::Util qw(not_supported); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
7
|
|
4321
|
2
|
|
|
2
|
|
8
|
use Scalar::Random::PP::OO::Meta::Role; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
30
|
|
4322
|
2
|
|
|
2
|
|
10
|
use Scalar::Random::PP::OO (); |
|
2
|
|
|
|
|
10
|
|
|
2
|
|
|
|
|
1578
|
|
4323
|
|
|
|
|
|
|
|
4324
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Exporter->setup_import_methods( |
4325
|
|
|
|
|
|
|
as_is => [qw( |
4326
|
|
|
|
|
|
|
extends with |
4327
|
|
|
|
|
|
|
has |
4328
|
|
|
|
|
|
|
before after around |
4329
|
|
|
|
|
|
|
override super |
4330
|
|
|
|
|
|
|
augment inner |
4331
|
|
|
|
|
|
|
|
4332
|
|
|
|
|
|
|
requires excludes |
4333
|
|
|
|
|
|
|
), |
4334
|
|
|
|
|
|
|
\&Scalar::Util::blessed, |
4335
|
|
|
|
|
|
|
\&Carp::confess, |
4336
|
|
|
|
|
|
|
], |
4337
|
|
|
|
|
|
|
); |
4338
|
|
|
|
|
|
|
|
4339
|
|
|
|
|
|
|
|
4340
|
|
|
|
|
|
|
sub extends { |
4341
|
0
|
|
|
0
|
0
|
|
Carp::croak "Roles do not support 'extends'"; |
4342
|
|
|
|
|
|
|
} |
4343
|
|
|
|
|
|
|
|
4344
|
|
|
|
|
|
|
sub with { |
4345
|
0
|
|
|
0
|
0
|
|
my $meta = Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller); |
4346
|
0
|
|
|
|
|
|
Scalar::Random::PP::OO::Util::apply_all_roles($meta->name, @_); |
4347
|
0
|
|
|
|
|
|
return; |
4348
|
|
|
|
|
|
|
} |
4349
|
|
|
|
|
|
|
|
4350
|
|
|
|
|
|
|
sub has { |
4351
|
0
|
|
|
0
|
0
|
|
my $meta = Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller); |
4352
|
0
|
|
|
|
|
|
my $name = shift; |
4353
|
|
|
|
|
|
|
|
4354
|
0
|
0
|
|
|
|
|
$meta->throw_error(q{Usage: has 'name' => ( key => value, ... )}) |
4355
|
|
|
|
|
|
|
if @_ % 2; # odd number of arguments |
4356
|
|
|
|
|
|
|
|
4357
|
0
|
0
|
|
|
|
|
if(ref $name){ # has [qw(foo bar)] => (...) |
4358
|
0
|
|
|
|
|
|
for (@{$name}){ |
|
0
|
|
|
|
|
|
|
4359
|
0
|
|
|
|
|
|
$meta->add_attribute($_ => @_); |
4360
|
|
|
|
|
|
|
} |
4361
|
|
|
|
|
|
|
} |
4362
|
|
|
|
|
|
|
else{ # has foo => (...) |
4363
|
0
|
|
|
|
|
|
$meta->add_attribute($name => @_); |
4364
|
|
|
|
|
|
|
} |
4365
|
0
|
|
|
|
|
|
return; |
4366
|
|
|
|
|
|
|
} |
4367
|
|
|
|
|
|
|
|
4368
|
|
|
|
|
|
|
sub before { |
4369
|
0
|
|
|
0
|
0
|
|
my $meta = Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller); |
4370
|
0
|
|
|
|
|
|
my $code = pop; |
4371
|
0
|
|
|
|
|
|
for my $name($meta->_collect_methods(@_)) { |
4372
|
0
|
|
|
|
|
|
$meta->add_before_method_modifier($name => $code); |
4373
|
|
|
|
|
|
|
} |
4374
|
0
|
|
|
|
|
|
return; |
4375
|
|
|
|
|
|
|
} |
4376
|
|
|
|
|
|
|
|
4377
|
|
|
|
|
|
|
sub after { |
4378
|
0
|
|
|
0
|
0
|
|
my $meta = Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller); |
4379
|
0
|
|
|
|
|
|
my $code = pop; |
4380
|
0
|
|
|
|
|
|
for my $name($meta->_collect_methods(@_)) { |
4381
|
0
|
|
|
|
|
|
$meta->add_after_method_modifier($name => $code); |
4382
|
|
|
|
|
|
|
} |
4383
|
0
|
|
|
|
|
|
return; |
4384
|
|
|
|
|
|
|
} |
4385
|
|
|
|
|
|
|
|
4386
|
|
|
|
|
|
|
sub around { |
4387
|
0
|
|
|
0
|
0
|
|
my $meta = Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller); |
4388
|
0
|
|
|
|
|
|
my $code = pop; |
4389
|
0
|
|
|
|
|
|
for my $name($meta->_collect_methods(@_)) { |
4390
|
0
|
|
|
|
|
|
$meta->add_around_method_modifier($name => $code); |
4391
|
|
|
|
|
|
|
} |
4392
|
0
|
|
|
|
|
|
return; |
4393
|
|
|
|
|
|
|
} |
4394
|
|
|
|
|
|
|
|
4395
|
|
|
|
|
|
|
|
4396
|
|
|
|
|
|
|
sub super { |
4397
|
0
|
0
|
|
0
|
0
|
|
return if !defined $Scalar::Random::PP::OO::SUPER_BODY; |
4398
|
0
|
|
|
|
|
|
$Scalar::Random::PP::OO::SUPER_BODY->(@Scalar::Random::PP::OO::SUPER_ARGS); |
4399
|
|
|
|
|
|
|
} |
4400
|
|
|
|
|
|
|
|
4401
|
|
|
|
|
|
|
sub override { |
4402
|
|
|
|
|
|
|
# my($name, $code) = @_; |
4403
|
0
|
|
|
0
|
0
|
|
Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller)->add_override_method_modifier(@_); |
4404
|
0
|
|
|
|
|
|
return; |
4405
|
|
|
|
|
|
|
} |
4406
|
|
|
|
|
|
|
|
4407
|
|
|
|
|
|
|
# We keep the same errors messages as Moose::Role emits, here. |
4408
|
|
|
|
|
|
|
sub inner { |
4409
|
0
|
|
|
0
|
0
|
|
Carp::croak "Roles cannot support 'inner'"; |
4410
|
|
|
|
|
|
|
} |
4411
|
|
|
|
|
|
|
|
4412
|
|
|
|
|
|
|
sub augment { |
4413
|
0
|
|
|
0
|
0
|
|
Carp::croak "Roles cannot support 'augment'"; |
4414
|
|
|
|
|
|
|
} |
4415
|
|
|
|
|
|
|
|
4416
|
|
|
|
|
|
|
sub requires { |
4417
|
0
|
|
|
0
|
0
|
|
my $meta = Scalar::Random::PP::OO::Meta::Role->initialize(scalar caller); |
4418
|
0
|
0
|
|
|
|
|
$meta->throw_error("Must specify at least one method") unless @_; |
4419
|
0
|
|
|
|
|
|
$meta->add_required_methods(@_); |
4420
|
0
|
|
|
|
|
|
return; |
4421
|
|
|
|
|
|
|
} |
4422
|
|
|
|
|
|
|
|
4423
|
|
|
|
|
|
|
sub excludes { |
4424
|
0
|
|
|
0
|
0
|
|
not_supported; |
4425
|
|
|
|
|
|
|
} |
4426
|
|
|
|
|
|
|
|
4427
|
|
|
|
|
|
|
sub init_meta{ |
4428
|
0
|
|
|
0
|
0
|
|
shift; |
4429
|
0
|
|
|
|
|
|
my %args = @_; |
4430
|
|
|
|
|
|
|
|
4431
|
0
|
0
|
|
|
|
|
my $class = $args{for_class} |
4432
|
|
|
|
|
|
|
or Carp::confess("Cannot call init_meta without specifying a for_class"); |
4433
|
|
|
|
|
|
|
|
4434
|
0
|
|
0
|
|
|
|
my $metaclass = $args{metaclass} || 'Scalar::Random::PP::OO::Meta::Role'; |
4435
|
|
|
|
|
|
|
|
4436
|
0
|
|
|
|
|
|
my $meta = $metaclass->initialize($class); |
4437
|
|
|
|
|
|
|
|
4438
|
|
|
|
|
|
|
$meta->add_method(meta => sub{ |
4439
|
0
|
|
0
|
0
|
|
|
$metaclass->initialize(ref($_[0]) || $_[0]); |
4440
|
0
|
|
|
|
|
|
}); |
4441
|
|
|
|
|
|
|
|
4442
|
|
|
|
|
|
|
# make a role type for each Scalar::Random::PP::OO role |
4443
|
0
|
0
|
|
|
|
|
Scalar::Random::PP::OO::Util::TypeConstraints::role_type($class) |
4444
|
|
|
|
|
|
|
unless Scalar::Random::PP::OO::Util::TypeConstraints::find_type_constraint($class); |
4445
|
|
|
|
|
|
|
|
4446
|
0
|
|
|
|
|
|
return $meta; |
4447
|
|
|
|
|
|
|
} |
4448
|
|
|
|
|
|
|
|
4449
|
|
|
|
|
|
|
# Contents of Mouse::Util::MetaRole |
4450
|
|
|
|
|
|
|
package Scalar::Random::PP::OO::Util::MetaRole; |
4451
|
2
|
|
|
2
|
|
11
|
use Scalar::Random::PP::OO::Util; # enables strict and warnings |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
6
|
|
4452
|
2
|
|
|
2
|
|
11
|
use Scalar::Util (); |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
2074
|
|
4453
|
|
|
|
|
|
|
|
4454
|
|
|
|
|
|
|
sub apply_metaclass_roles { |
4455
|
0
|
|
|
0
|
0
|
|
my %args = @_; |
4456
|
0
|
|
|
|
|
|
_fixup_old_style_args(\%args); |
4457
|
|
|
|
|
|
|
|
4458
|
0
|
|
|
|
|
|
return apply_metaroles(%args); |
4459
|
|
|
|
|
|
|
} |
4460
|
|
|
|
|
|
|
|
4461
|
|
|
|
|
|
|
sub apply_metaroles { |
4462
|
0
|
|
|
0
|
0
|
|
my %args = @_; |
4463
|
|
|
|
|
|
|
|
4464
|
0
|
0
|
|
|
|
|
my $for = Scalar::Util::blessed($args{for}) |
4465
|
|
|
|
|
|
|
? $args{for} |
4466
|
|
|
|
|
|
|
: Scalar::Random::PP::OO::Util::get_metaclass_by_name( $args{for} ); |
4467
|
|
|
|
|
|
|
|
4468
|
0
|
0
|
|
|
|
|
if(!$for){ |
4469
|
0
|
|
|
|
|
|
Carp::confess("You must pass an initialized class, but '$args{for}' has no metaclass"); |
4470
|
|
|
|
|
|
|
} |
4471
|
|
|
|
|
|
|
|
4472
|
0
|
0
|
|
|
|
|
if ( Scalar::Random::PP::OO::Util::is_a_metarole($for) ) { |
4473
|
0
|
|
|
|
|
|
return _make_new_metaclass( $for, $args{role_metaroles}, 'role' ); |
4474
|
|
|
|
|
|
|
} |
4475
|
|
|
|
|
|
|
else { |
4476
|
0
|
|
|
|
|
|
return _make_new_metaclass( $for, $args{class_metaroles}, 'class' ); |
4477
|
|
|
|
|
|
|
} |
4478
|
|
|
|
|
|
|
} |
4479
|
|
|
|
|
|
|
|
4480
|
|
|
|
|
|
|
sub _make_new_metaclass { |
4481
|
0
|
|
|
0
|
|
|
my($for, $roles, $primary) = @_; |
4482
|
|
|
|
|
|
|
|
4483
|
0
|
0
|
|
|
|
|
return $for unless keys %{$roles}; |
|
0
|
|
|
|
|
|
|
4484
|
|
|
|
|
|
|
|
4485
|
0
|
0
|
|
|
|
|
my $new_metaclass = exists($roles->{$primary}) |
4486
|
|
|
|
|
|
|
? _make_new_class( ref $for, $roles->{$primary} ) # new class with traits |
4487
|
|
|
|
|
|
|
: ref $for; |
4488
|
|
|
|
|
|
|
|
4489
|
0
|
|
|
|
|
|
my %classes; |
4490
|
|
|
|
|
|
|
|
4491
|
0
|
|
|
|
|
|
for my $key ( grep { $_ ne $primary } keys %{$roles} ) { |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
4492
|
0
|
|
|
|
|
|
my $metaclass; |
4493
|
0
|
|
0
|
|
|
|
my $attr = $for->can($metaclass = ($key . '_metaclass')) |
4494
|
|
|
|
|
|
|
|| $for->can($metaclass = ($key . '_class')) |
4495
|
|
|
|
|
|
|
|| $for->throw_error("Unknown metaclass '$key'"); |
4496
|
|
|
|
|
|
|
|
4497
|
0
|
|
|
|
|
|
$classes{ $metaclass } |
4498
|
|
|
|
|
|
|
= _make_new_class( $for->$attr(), $roles->{$key} ); |
4499
|
|
|
|
|
|
|
} |
4500
|
|
|
|
|
|
|
|
4501
|
0
|
|
|
|
|
|
return $new_metaclass->reinitialize( $for, %classes ); |
4502
|
|
|
|
|
|
|
} |
4503
|
|
|
|
|
|
|
|
4504
|
|
|
|
|
|
|
|
4505
|
|
|
|
|
|
|
sub _fixup_old_style_args { |
4506
|
0
|
|
|
0
|
|
|
my $args = shift; |
4507
|
|
|
|
|
|
|
|
4508
|
0
|
0
|
0
|
|
|
|
return if $args->{class_metaroles} || $args->{roles_metaroles}; |
4509
|
|
|
|
|
|
|
|
4510
|
0
|
0
|
|
|
|
|
$args->{for} = delete $args->{for_class} |
4511
|
|
|
|
|
|
|
if exists $args->{for_class}; |
4512
|
|
|
|
|
|
|
|
4513
|
0
|
|
|
|
|
|
my @old_keys = qw( |
4514
|
|
|
|
|
|
|
attribute_metaclass_roles |
4515
|
|
|
|
|
|
|
method_metaclass_roles |
4516
|
|
|
|
|
|
|
wrapped_method_metaclass_roles |
4517
|
|
|
|
|
|
|
instance_metaclass_roles |
4518
|
|
|
|
|
|
|
constructor_class_roles |
4519
|
|
|
|
|
|
|
destructor_class_roles |
4520
|
|
|
|
|
|
|
error_class_roles |
4521
|
|
|
|
|
|
|
|
4522
|
|
|
|
|
|
|
application_to_class_class_roles |
4523
|
|
|
|
|
|
|
application_to_role_class_roles |
4524
|
|
|
|
|
|
|
application_to_instance_class_roles |
4525
|
|
|
|
|
|
|
application_role_summation_class_roles |
4526
|
|
|
|
|
|
|
); |
4527
|
|
|
|
|
|
|
|
4528
|
0
|
0
|
|
|
|
|
my $for = Scalar::Util::blessed($args->{for}) |
4529
|
|
|
|
|
|
|
? $args->{for} |
4530
|
|
|
|
|
|
|
: Scalar::Random::PP::OO::Util::get_metaclass_by_name( $args->{for} ); |
4531
|
|
|
|
|
|
|
|
4532
|
0
|
|
|
|
|
|
my $top_key; |
4533
|
0
|
0
|
|
|
|
|
if( Scalar::Random::PP::OO::Util::is_a_metaclass($for) ){ |
4534
|
0
|
|
|
|
|
|
$top_key = 'class_metaroles'; |
4535
|
|
|
|
|
|
|
|
4536
|
0
|
0
|
|
|
|
|
$args->{class_metaroles}{class} = delete $args->{metaclass_roles} |
4537
|
|
|
|
|
|
|
if exists $args->{metaclass_roles}; |
4538
|
|
|
|
|
|
|
} |
4539
|
|
|
|
|
|
|
else { |
4540
|
0
|
|
|
|
|
|
$top_key = 'role_metaroles'; |
4541
|
|
|
|
|
|
|
|
4542
|
0
|
0
|
|
|
|
|
$args->{role_metaroles}{role} = delete $args->{metaclass_roles} |
4543
|
|
|
|
|
|
|
if exists $args->{metaclass_roles}; |
4544
|
|
|
|
|
|
|
} |
4545
|
|
|
|
|
|
|
|
4546
|
0
|
|
|
|
|
|
for my $old_key (@old_keys) { |
4547
|
0
|
|
|
|
|
|
my ($new_key) = $old_key =~ /^(.+)_(?:class|metaclass)_roles$/; |
4548
|
|
|
|
|
|
|
|
4549
|
0
|
0
|
|
|
|
|
$args->{$top_key}{$new_key} = delete $args->{$old_key} |
4550
|
|
|
|
|
|
|
if exists $args->{$old_key}; |
4551
|
|
|
|
|
|
|
} |
4552
|
|
|
|
|
|
|
|
4553
|
0
|
|
|
|
|
|
return; |
4554
|
|
|
|
|
|
|
} |
4555
|
|
|
|
|
|
|
|
4556
|
|
|
|
|
|
|
|
4557
|
|
|
|
|
|
|
sub apply_base_class_roles { |
4558
|
0
|
|
|
0
|
0
|
|
my %options = @_; |
4559
|
|
|
|
|
|
|
|
4560
|
0
|
|
|
|
|
|
my $for = $options{for_class}; |
4561
|
|
|
|
|
|
|
|
4562
|
0
|
|
|
|
|
|
my $meta = Scalar::Random::PP::OO::Util::class_of($for); |
4563
|
|
|
|
|
|
|
|
4564
|
0
|
|
|
|
|
|
my $new_base = _make_new_class( |
4565
|
|
|
|
|
|
|
$for, |
4566
|
|
|
|
|
|
|
$options{roles}, |
4567
|
|
|
|
|
|
|
[ $meta->superclasses() ], |
4568
|
|
|
|
|
|
|
); |
4569
|
|
|
|
|
|
|
|
4570
|
0
|
0
|
|
|
|
|
$meta->superclasses($new_base) |
4571
|
|
|
|
|
|
|
if $new_base ne $meta->name(); |
4572
|
0
|
|
|
|
|
|
return; |
4573
|
|
|
|
|
|
|
} |
4574
|
|
|
|
|
|
|
|
4575
|
|
|
|
|
|
|
sub _make_new_class { |
4576
|
0
|
|
|
0
|
|
|
my($existing_class, $roles, $superclasses) = @_; |
4577
|
|
|
|
|
|
|
|
4578
|
0
|
0
|
|
|
|
|
if(!$superclasses){ |
4579
|
0
|
0
|
|
|
|
|
return $existing_class if !$roles; |
4580
|
|
|
|
|
|
|
|
4581
|
0
|
|
|
|
|
|
my $meta = Scalar::Random::PP::OO::Meta::Class->initialize($existing_class); |
4582
|
|
|
|
|
|
|
|
4583
|
0
|
|
0
|
|
|
|
return $existing_class |
4584
|
0
|
0
|
|
|
|
|
if !grep { !ref($_) && !$meta->does_role($_) } @{$roles}; |
|
0
|
|
|
|
|
|
|
4585
|
|
|
|
|
|
|
} |
4586
|
|
|
|
|
|
|
|
4587
|
0
|
0
|
|
|
|
|
return Scalar::Random::PP::OO::Meta::Class->create_anon_class( |
4588
|
|
|
|
|
|
|
superclasses => $superclasses ? $superclasses : [$existing_class], |
4589
|
|
|
|
|
|
|
roles => $roles, |
4590
|
|
|
|
|
|
|
cache => 1, |
4591
|
|
|
|
|
|
|
)->name(); |
4592
|
|
|
|
|
|
|
} |
4593
|
|
|
|
|
|
|
|
4594
|
|
|
|
|
|
|
; |
4595
|
|
|
|
|
|
|
|
4596
|
|
|
|
|
|
|
package Scalar::Random::PP::OO; |
4597
|
|
|
|
|
|
|
|
4598
|
|
|
|
|
|
|
our $VERSION = '0.07'; |
4599
|
|
|
|
|
|
|
|
4600
|
|
|
|
|
|
|
Scalar::Random::PP::OO::Exporter->setup_import_methods(also => 'Scalar::Random::PP::OO::TOP'); |
4601
|
|
|
|
|
|
|
|
4602
|
|
|
|
|
|
|
1; |