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