line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Abstract::Meta::Attribute::Method; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
|
4
|
5
|
|
|
5
|
|
31
|
use strict; |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
165
|
|
5
|
5
|
|
|
5
|
|
27
|
use warnings; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
144
|
|
6
|
5
|
|
|
5
|
|
25
|
use Carp 'confess'; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
248
|
|
7
|
5
|
|
|
5
|
|
33
|
use vars qw($VERSION); |
|
5
|
|
|
|
|
17
|
|
|
5
|
|
|
|
|
46670
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
$VERSION = 0.06; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 NAME |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
Abstract::Meta::Attribute::Method - Method generator. |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 DESCRIPTION |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
Generates methods for attribute's definition. |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 SYNOPSIS |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
use Abstract::Meta::Class ':all'; |
23
|
|
|
|
|
|
|
has '$.attr1' => (default => 0); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=head2 methods |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=over |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=item generate_scalar_accessor_method |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=cut |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
sub generate_scalar_accessor_method { |
34
|
35
|
|
|
35
|
1
|
51
|
my $attr = shift; |
35
|
35
|
|
|
|
|
109
|
my $mutator = $attr->mutator; |
36
|
35
|
|
|
|
|
104
|
my $storage_key = $attr->storage_key; |
37
|
35
|
|
|
|
|
94
|
my $transistent = $attr->transistent; |
38
|
35
|
|
|
|
|
98
|
my $on_read = $attr->on_read; |
39
|
35
|
|
|
|
|
89
|
my $array_storage_type = $attr->storage_type eq 'Array'; |
40
|
|
|
|
|
|
|
$array_storage_type ? |
41
|
|
|
|
|
|
|
($transistent ? sub { |
42
|
0
|
|
|
0
|
|
0
|
my ($self, @args) = @_; |
43
|
0
|
0
|
|
|
|
0
|
$self->$mutator(@args) if scalar(@args) >= 1; |
44
|
0
|
0
|
|
|
|
0
|
my $result = $on_read |
45
|
|
|
|
|
|
|
? $on_read ->($self, $attr, 'accessor') |
46
|
|
|
|
|
|
|
: get_attribute($self, $storage_key); |
47
|
0
|
|
|
|
|
0
|
$result; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
: ( |
50
|
|
|
|
|
|
|
$on_read ? |
51
|
|
|
|
|
|
|
sub { |
52
|
0
|
|
|
0
|
|
0
|
my ($self, @args) = @_; |
53
|
0
|
0
|
|
|
|
0
|
$self->$mutator(@args) if scalar(@args) >= 1; |
54
|
0
|
0
|
|
|
|
0
|
my $result = $on_read |
55
|
|
|
|
|
|
|
? $on_read ->($self, $attr, 'accessor') |
56
|
|
|
|
|
|
|
: $self->[$storage_key]; |
57
|
0
|
|
|
|
|
0
|
$result; |
58
|
|
|
|
|
|
|
} : |
59
|
|
|
|
|
|
|
sub { |
60
|
0
|
|
|
0
|
|
0
|
my ($self, @args) = @_; |
61
|
0
|
0
|
|
|
|
0
|
$self->$mutator(@args) if @args >= 1; |
62
|
0
|
|
|
|
|
0
|
$self->[$storage_key]; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
) |
65
|
|
|
|
|
|
|
) |
66
|
|
|
|
|
|
|
: |
67
|
|
|
|
|
|
|
sub { |
68
|
60
|
|
|
60
|
|
7564
|
my ($self, @args) = @_; |
69
|
60
|
100
|
|
|
|
177
|
$self->$mutator(@args) if scalar(@args) >= 1; |
70
|
60
|
100
|
|
|
|
173
|
my $result = $on_read |
|
|
50
|
|
|
|
|
|
71
|
|
|
|
|
|
|
? $on_read ->($self, $attr, 'accessor') |
72
|
|
|
|
|
|
|
: $transistent ? get_attribute($self, $storage_key) : $self->{$storage_key}; |
73
|
60
|
|
|
|
|
199
|
$result; |
74
|
35
|
0
|
|
|
|
337
|
}; |
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=item generate_code_accessor_method |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=cut |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
sub generate_code_accessor_method { |
83
|
1
|
|
|
1
|
1
|
2
|
my $attr = shift; |
84
|
1
|
|
|
|
|
3
|
$attr->generate_scalar_accessor_method; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=item generate_mutator_method |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
=cut |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub generate_mutator_method { |
93
|
58
|
|
|
58
|
1
|
91
|
my $attr = shift; |
94
|
58
|
|
|
|
|
156
|
my $storage_key = $attr->storage_key; |
95
|
58
|
|
|
|
|
173
|
my $transistent = $attr->transistent; |
96
|
58
|
|
|
|
|
144
|
my $accessor = $attr->accessor; |
97
|
58
|
|
|
|
|
162
|
my $required = $attr->required; |
98
|
58
|
|
|
|
|
157
|
my $default = $attr->default; |
99
|
58
|
|
|
|
|
155
|
my $associated_class = $attr->associated_class; |
100
|
58
|
|
|
|
|
150
|
my $perl_type = $attr->perl_type; |
101
|
58
|
|
|
|
|
165
|
my $index_by = $attr->index_by; |
102
|
58
|
|
|
|
|
157
|
my $on_change = $attr->on_change; |
103
|
58
|
|
|
|
|
194
|
my $data_type_validation = $attr->data_type_validation; |
104
|
58
|
|
|
|
|
160
|
my $on_validate = $attr->on_validate; |
105
|
58
|
|
|
|
|
146
|
my $array_storage_type = $attr->storage_type eq 'Array'; |
106
|
|
|
|
|
|
|
$array_storage_type ? |
107
|
|
|
|
|
|
|
sub { |
108
|
0
|
|
|
0
|
|
0
|
my ($self, $value) = @_; |
109
|
0
|
0
|
0
|
|
|
0
|
if (! defined $value && defined $default) { |
110
|
0
|
0
|
|
|
|
0
|
if (ref($default) eq 'CODE') { |
111
|
0
|
|
|
|
|
0
|
$value = $default->($self, $attr); |
112
|
|
|
|
|
|
|
} else { |
113
|
0
|
|
|
|
|
0
|
$value = $default; |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
0
|
0
|
|
|
|
0
|
$on_validate->($self, $attr, 'mutator', \$value) if $on_validate; |
118
|
0
|
0
|
|
|
|
0
|
if ($data_type_validation) { |
119
|
0
|
0
|
0
|
|
|
0
|
$value = index_association_data($value, $accessor, $index_by) |
120
|
|
|
|
|
|
|
if ($associated_class && $perl_type eq 'Hash'); |
121
|
0
|
|
|
|
|
0
|
$attr->validate_data_type($self, $value, $accessor, $associated_class, $perl_type); |
122
|
0
|
0
|
|
|
|
0
|
if($required) { |
123
|
0
|
0
|
|
|
|
0
|
if ($perl_type eq 'Hash') { |
|
|
0
|
|
|
|
|
|
124
|
0
|
0
|
|
|
|
0
|
confess "attribute $accessor is required" |
125
|
|
|
|
|
|
|
unless scalar %$value; |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
} elsif ($perl_type eq 'Array') { |
128
|
0
|
0
|
|
|
|
0
|
confess "attribute $accessor is required" |
129
|
|
|
|
|
|
|
unless scalar @$value; |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
} else { |
134
|
0
|
0
|
0
|
|
|
0
|
confess "attribute $accessor is required" |
135
|
|
|
|
|
|
|
if $required && ! defined $value; |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
0
|
0
|
0
|
|
|
0
|
$on_change->($self, $attr, 'mutator', \$value) or return $self |
|
|
|
0
|
|
|
|
|
139
|
|
|
|
|
|
|
if ($on_change && defined $value); |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
|
142
|
0
|
0
|
|
|
|
0
|
if ($transistent) { |
143
|
0
|
|
|
|
|
0
|
set_attribute($self, $storage_key, $value); |
144
|
|
|
|
|
|
|
} else { |
145
|
0
|
|
|
|
|
0
|
$self->[$storage_key] = $value; |
146
|
|
|
|
|
|
|
} |
147
|
0
|
|
|
|
|
0
|
$self; |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
: |
150
|
|
|
|
|
|
|
sub { |
151
|
113
|
|
|
113
|
|
2252
|
my ($self, $value) = @_; |
152
|
113
|
100
|
100
|
|
|
382
|
if (! defined $value && defined $default) { |
153
|
25
|
100
|
|
|
|
83
|
if (ref($default) eq 'CODE') { |
154
|
18
|
|
|
|
|
62
|
$value = $default->($self, $attr); |
155
|
|
|
|
|
|
|
} else { |
156
|
7
|
|
|
|
|
12
|
$value = $default; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
113
|
100
|
|
|
|
220
|
$on_validate->($self, $attr, 'mutator', \$value) if $on_validate; |
161
|
112
|
100
|
|
|
|
193
|
if ($data_type_validation) { |
162
|
72
|
100
|
100
|
|
|
268
|
$value = index_association_data($value, $accessor, $index_by) |
163
|
|
|
|
|
|
|
if ($associated_class && $perl_type eq 'Hash'); |
164
|
72
|
|
|
|
|
194
|
$attr->validate_data_type($self, $value, $accessor, $associated_class, $perl_type); |
165
|
67
|
100
|
|
|
|
148
|
if($required) { |
166
|
11
|
100
|
|
|
|
40
|
if ($perl_type eq 'Hash') { |
|
|
50
|
|
|
|
|
|
167
|
5
|
100
|
|
|
|
286
|
confess "attribute $accessor is required" |
168
|
|
|
|
|
|
|
unless scalar %$value; |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
} elsif ($perl_type eq 'Array') { |
171
|
6
|
100
|
|
|
|
426
|
confess "attribute $accessor is required" |
172
|
|
|
|
|
|
|
unless scalar @$value; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
} else { |
176
|
40
|
100
|
100
|
|
|
411
|
confess "attribute $accessor is required" |
177
|
|
|
|
|
|
|
if $required && ! defined $value; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
|
181
|
102
|
100
|
100
|
|
|
297
|
$on_change->($self, $attr, 'mutator', \$value) or return $self |
|
|
|
66
|
|
|
|
|
182
|
|
|
|
|
|
|
if ($on_change && defined $value); |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
|
185
|
101
|
100
|
|
|
|
211
|
if ($transistent) { |
186
|
3
|
|
|
|
|
10
|
set_attribute($self, $storage_key, $value); |
187
|
|
|
|
|
|
|
} else { |
188
|
98
|
|
|
|
|
330
|
$self->{$storage_key} = $value; |
189
|
|
|
|
|
|
|
} |
190
|
101
|
|
|
|
|
334
|
$self; |
191
|
58
|
100
|
|
|
|
678
|
}; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=item index_association_data |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=cut |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
sub index_association_data { |
200
|
11
|
|
|
11
|
1
|
70
|
my ($data, $attr_name, $index) = @_; |
201
|
11
|
100
|
|
|
|
33
|
return $data if ref($data) eq 'HASH'; |
202
|
5
|
|
|
|
|
8
|
my %result; |
203
|
5
|
100
|
66
|
|
|
46
|
if($index && $$data[0]->can($index)) { |
204
|
4
|
|
|
|
|
7
|
%result = (map {($_->$index, $_)} @$data); |
|
10
|
|
|
|
|
21
|
|
205
|
|
|
|
|
|
|
} else { |
206
|
1
|
|
|
|
|
2
|
%result = (map {($_ . "", $_)} @$data); |
|
1
|
|
|
|
|
6
|
|
207
|
|
|
|
|
|
|
} |
208
|
5
|
|
|
|
|
13
|
\%result; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
=item validate_data_type |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
=cut |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub validate_data_type { |
217
|
72
|
|
|
72
|
1
|
127
|
my ($attr, $self, $value, $accessor, $associated_class, $perl_type) = @_; |
218
|
72
|
|
|
|
|
185
|
my $array_storage_type = $attr->storage_type eq 'Array'; |
219
|
72
|
100
|
|
|
|
233
|
if ($perl_type eq 'Array') { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
220
|
22
|
50
|
|
|
|
68
|
confess "$accessor must be $perl_type type" |
221
|
|
|
|
|
|
|
unless (ref($value) eq 'ARRAY'); |
222
|
22
|
100
|
|
|
|
56
|
if ($associated_class) { |
223
|
|
|
|
|
|
|
validate_associated_class($attr, $self, $_) |
224
|
12
|
|
|
|
|
33
|
for @$value; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
} elsif ($perl_type eq 'Hash') { |
227
|
21
|
50
|
|
|
|
60
|
confess "$accessor must be $perl_type type" |
228
|
|
|
|
|
|
|
unless (ref($value) eq 'HASH'); |
229
|
21
|
100
|
|
|
|
101
|
if ($associated_class) { |
230
|
|
|
|
|
|
|
validate_associated_class($attr, $self, $_) |
231
|
11
|
|
|
|
|
44
|
for values %$value; |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
} elsif ($associated_class) { |
234
|
29
|
|
|
|
|
62
|
my $transistent = $attr->transistent; |
235
|
29
|
|
|
|
|
64
|
my $storage_key = $attr->storage_key; |
236
|
29
|
50
|
|
|
|
105
|
my $current_value = $transistent ? get_attribute($self, $storage_key) : ($array_storage_type ? $self->[$storage_key] : $self->{$storage_key}); |
|
|
50
|
|
|
|
|
|
237
|
29
|
50
|
100
|
|
|
123
|
return if ($value && $current_value && $value eq $current_value); |
|
|
|
66
|
|
|
|
|
238
|
29
|
|
|
|
|
65
|
$attr->deassociate($self); |
239
|
29
|
100
|
|
|
|
61
|
if (defined $value) { |
240
|
22
|
|
|
|
|
36
|
validate_associated_class($attr, $self, $value); |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=item validate_associated_class |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
=cut |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
sub validate_associated_class { |
251
|
43
|
|
|
43
|
1
|
54
|
my ($attr, $self, $value) = @_; |
252
|
43
|
|
|
|
|
94
|
my $associated_class = $attr->associated_class; |
253
|
43
|
|
|
|
|
103
|
my $name = $attr->name; |
254
|
43
|
50
|
|
|
|
97
|
my $value_type = ref($value) |
255
|
|
|
|
|
|
|
or confess "$name must be of the $associated_class type"; |
256
|
43
|
100
|
|
|
|
110
|
return &associate_the_other_end if $value_type eq $associated_class; |
257
|
3
|
50
|
|
|
|
18
|
return &associate_the_other_end if $value->isa($associated_class); |
258
|
3
|
|
|
|
|
440
|
confess "$name must be of the $associated_class type, is $value_type"; |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=item pending_transation |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=cut |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
{ my %pending_association; |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
=item start_association_process |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
Start association process (to avoid infinitive look of associating the others ends) |
272
|
|
|
|
|
|
|
Takes obj reference. |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=cut |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
sub start_association_process { |
277
|
21
|
|
|
21
|
1
|
24
|
my ($self) = @_; |
278
|
21
|
|
|
|
|
56
|
$pending_association{$self} = 1; |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=item has_pending_association |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
Returns true is object is during association process. |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=cut |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
sub has_pending_association { |
289
|
43
|
|
|
43
|
1
|
50
|
my ($self) = @_; |
290
|
43
|
|
|
|
|
212
|
$pending_association{$self}; |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=item end_association_process |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
Compleetes association process. |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=cut |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
sub end_association_process { |
301
|
21
|
|
|
21
|
1
|
22
|
my ($self) = @_; |
302
|
21
|
|
|
|
|
127
|
delete $pending_association{$self}; |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
} |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=item associate_the_other_end |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
Associate current object reference to the the other end associated class. |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
TODO |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=cut |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
sub associate_the_other_end { |
317
|
40
|
|
|
40
|
1
|
51
|
my ($attr, $self, $value) = @_; |
318
|
40
|
|
|
|
|
88
|
my $the_other_end = $attr->the_other_end; |
319
|
40
|
|
|
|
|
85
|
my $name = $attr->name; |
320
|
40
|
100
|
100
|
|
|
135
|
return if ! $the_other_end || has_pending_association($self); |
321
|
18
|
|
|
|
|
47
|
my $associated_class = $attr->associated_class; |
322
|
18
|
|
|
|
|
54
|
my $the_other_end_attribute = $associated_class->meta->attribute($the_other_end); |
323
|
|
|
|
|
|
|
|
324
|
18
|
100
|
|
|
|
185
|
confess "missing other end attribute on ". ref($value) . "::" . $the_other_end |
325
|
|
|
|
|
|
|
unless $the_other_end_attribute; |
326
|
|
|
|
|
|
|
|
327
|
17
|
100
|
|
|
|
38
|
confess "invalid definition for " . ref($self) ."::". $name |
328
|
|
|
|
|
|
|
. " - associatied class not defined on " . ref($value) ."::" . $the_other_end |
329
|
|
|
|
|
|
|
unless $the_other_end_attribute->associated_class; |
330
|
|
|
|
|
|
|
|
331
|
16
|
|
|
|
|
33
|
start_association_process($value); |
332
|
16
|
|
|
|
|
18
|
eval { |
333
|
16
|
|
|
|
|
39
|
my $association_call = 'associate_' . lc($the_other_end_attribute->perl_type) . '_as_the_other_end'; |
334
|
16
|
|
|
|
|
59
|
$attr->$association_call($self, $value); |
335
|
|
|
|
|
|
|
}; |
336
|
16
|
|
|
|
|
25
|
end_association_process($value); |
337
|
16
|
50
|
|
|
|
73
|
die $@ if $@; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=item associate_scalar_as_the_other_end |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=cut |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
sub associate_scalar_as_the_other_end { |
347
|
14
|
|
|
14
|
1
|
18
|
my ($attr, $self, $value) = @_; |
348
|
14
|
|
|
|
|
31
|
my $the_other_end = $attr->the_other_end; |
349
|
14
|
|
|
|
|
32
|
$value->$the_other_end($self); |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
=item associate_hash_as_the_other_end |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
=cut |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
sub associate_hash_as_the_other_end { |
358
|
1
|
|
|
1
|
1
|
3
|
my ($attr, $self, $value) = @_; |
359
|
1
|
|
|
|
|
3
|
my $the_other_end = $attr->the_other_end; |
360
|
1
|
|
|
|
|
4
|
my $associated_class = $attr->associated_class; |
361
|
1
|
|
|
|
|
4
|
my $the_other_end_attribute = $associated_class->meta->attribute($the_other_end); |
362
|
1
|
|
|
|
|
6
|
my $item_accessor = $the_other_end_attribute->item_accessor; |
363
|
1
|
|
|
|
|
3
|
my $index_by = $the_other_end_attribute->index_by; |
364
|
1
|
50
|
|
|
|
4
|
if ($index_by) { |
365
|
1
|
|
|
|
|
3
|
$value->$item_accessor($self->$index_by, $self); |
366
|
|
|
|
|
|
|
} else { |
367
|
0
|
|
|
|
|
0
|
$value->$item_accessor($self . "", $self); |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
=item associate_array_as_the_other_end |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
=cut |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
sub associate_array_as_the_other_end { |
377
|
1
|
|
|
1
|
1
|
1
|
my ($attr, $self, $value) = @_; |
378
|
1
|
|
|
|
|
4
|
my $the_other_end = $attr->the_other_end; |
379
|
1
|
|
|
|
|
3
|
my $associated_class = $attr->associated_class; |
380
|
1
|
|
|
|
|
4
|
my $the_other_end_attribute = $associated_class->meta->attribute($the_other_end); |
381
|
1
|
|
|
|
|
6
|
my $other_end_accessor = $the_other_end_attribute->accessor; |
382
|
1
|
|
|
|
|
15
|
my $setter = "push_${other_end_accessor}"; |
383
|
1
|
|
|
|
|
4
|
$value->$setter($self); |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=item deassociate |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
Deassociates assoication values |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=cut |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
sub deassociate { |
394
|
31
|
|
|
31
|
1
|
40
|
my ($attr, $self) = @_; |
395
|
31
|
|
|
|
|
64
|
my $transistent = $attr->transistent; |
396
|
31
|
|
|
|
|
67
|
my $storage_key = $attr->storage_key; |
397
|
31
|
|
|
|
|
72
|
my $array_storage_type = $attr->storage_type eq 'Array'; |
398
|
31
|
50
|
|
|
|
114
|
my $value = ($transistent ? get_attribute($self, $storage_key) : ($array_storage_type ? $self->[$storage_key] : $self->{$storage_key})) or return; |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
399
|
12
|
|
|
|
|
28
|
my $the_other_end = $attr->the_other_end; |
400
|
12
|
100
|
100
|
|
|
40
|
return if ! $the_other_end || has_pending_association($value); |
401
|
5
|
|
|
|
|
10
|
start_association_process($self); |
402
|
5
|
|
|
|
|
13
|
my $associated_class = $attr->associated_class; |
403
|
5
|
|
|
|
|
15
|
my $the_other_end_attribute = $associated_class->meta->attribute($the_other_end); |
404
|
5
|
|
|
|
|
12
|
my $deassociation_call = 'deassociate_' . lc($the_other_end_attribute->perl_type) . '_as_the_other_end'; |
405
|
5
|
100
|
|
|
|
19
|
if(ref($value) eq 'ARRAY') { |
|
|
100
|
|
|
|
|
|
406
|
1
|
|
|
|
|
7
|
$the_other_end_attribute->$deassociation_call($self, $_) for @$value; |
407
|
|
|
|
|
|
|
} elsif(ref($value) eq 'HASH') { |
408
|
1
|
|
|
|
|
6
|
$the_other_end_attribute->$deassociation_call($self, $value->{$_}) for(keys %$value); |
409
|
|
|
|
|
|
|
} else { |
410
|
3
|
|
|
|
|
33
|
$the_other_end_attribute->$deassociation_call($self, $value); |
411
|
|
|
|
|
|
|
} |
412
|
5
|
|
|
|
|
12
|
end_association_process($self); |
413
|
|
|
|
|
|
|
} |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
=item deassociate_scalar_as_the_other_end |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
=cut |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
sub deassociate_scalar_as_the_other_end { |
421
|
6
|
|
|
6
|
1
|
11
|
my ($attr, $self, $the_other_end_obj) = @_; |
422
|
6
|
50
|
|
|
|
14
|
$the_other_end_obj or return; |
423
|
6
|
|
|
|
|
15
|
my $accessor = $attr->accessor; |
424
|
6
|
|
|
|
|
14
|
$the_other_end_obj->$accessor(undef); |
425
|
6
|
|
|
|
|
16
|
undef; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
=item deassociate_hash_as_the_other_end |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=cut |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
sub deassociate_hash_as_the_other_end { |
434
|
1
|
|
|
1
|
1
|
2
|
my ($attr, $self, $the_other_end_obj) = @_; |
435
|
1
|
|
|
|
|
3
|
my $accessor = $attr->accessor; |
436
|
1
|
|
|
|
|
3
|
my $value = $the_other_end_obj->$accessor; |
437
|
1
|
|
|
|
|
4
|
my $index_by = $attr->index_by; |
438
|
1
|
50
|
|
|
|
4
|
if ($index_by) { |
439
|
1
|
50
|
|
|
|
3
|
delete $value->{$self->$index_by} if exists($value->{$self->$index_by}); |
440
|
|
|
|
|
|
|
} else { |
441
|
0
|
|
|
|
|
0
|
my @keys = keys %$value; |
442
|
0
|
|
|
|
|
0
|
foreach my $k (@keys) { |
443
|
0
|
0
|
|
|
|
0
|
if ($value->{$k} eq $self) { |
444
|
0
|
|
|
|
|
0
|
delete $value->{$k}; |
445
|
0
|
|
|
|
|
0
|
return; |
446
|
|
|
|
|
|
|
} |
447
|
|
|
|
|
|
|
} |
448
|
|
|
|
|
|
|
} |
449
|
1
|
|
|
|
|
3
|
undef; |
450
|
|
|
|
|
|
|
} |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=item deassociate_array_as_the_other_end |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
=cut |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
sub deassociate_array_as_the_other_end { |
458
|
1
|
|
|
1
|
1
|
3
|
my ($attr, $self, $the_other_end_obj) = @_; |
459
|
1
|
|
|
|
|
4
|
my $accessor = $attr->accessor; |
460
|
1
|
|
|
|
|
4
|
my $value = $the_other_end_obj->$accessor; |
461
|
1
|
|
|
|
|
2
|
for my $i (0 .. $#{$value}) { |
|
1
|
|
|
|
|
3
|
|
462
|
3
|
100
|
|
|
|
9
|
if ($value->[$i] eq $self) { |
463
|
1
|
|
|
|
|
4
|
splice @$value, $i--, 1; |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
} |
466
|
1
|
|
|
|
|
2
|
undef; |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
|
470
|
|
|
|
|
|
|
=item generate_scalar_mutator_method |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=cut |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
sub generate_scalar_mutator_method { |
475
|
34
|
|
|
34
|
1
|
87
|
shift()->generate_mutator_method; |
476
|
|
|
|
|
|
|
} |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
=item generate_code_mutator_method |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=cut |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
sub generate_code_mutator_method { |
484
|
1
|
|
|
1
|
1
|
3
|
shift()->generate_mutator_method; |
485
|
|
|
|
|
|
|
} |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=item generate_array_accessor_method |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=cut |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
sub generate_array_accessor_method { |
493
|
11
|
|
|
11
|
1
|
24
|
my $attr = shift; |
494
|
11
|
|
|
|
|
35
|
my $mutator = $attr->mutator; |
495
|
11
|
|
|
|
|
40
|
my $storage_key = $attr->storage_key; |
496
|
11
|
|
|
|
|
33
|
my $transistent = $attr->transistent; |
497
|
11
|
|
|
|
|
43
|
my $on_read = $attr->on_read; |
498
|
11
|
|
|
|
|
33
|
my $array_storage_type = $attr->storage_type eq 'Array'; |
499
|
|
|
|
|
|
|
$array_storage_type ? |
500
|
|
|
|
|
|
|
sub { |
501
|
0
|
|
|
0
|
|
0
|
my ($self, @args) = @_; |
502
|
0
|
0
|
|
|
|
0
|
$self->$mutator(@args) if scalar(@args) >= 1; |
503
|
0
|
0
|
0
|
|
|
0
|
my $result = $on_read ? $on_read->($self, $attr, 'accessor') |
|
|
0
|
|
|
|
|
|
504
|
|
|
|
|
|
|
: ($transistent ? get_attribute($self, $storage_key) : ($self->[$storage_key] ||= [])); |
505
|
0
|
0
|
|
|
|
0
|
wantarray ? @$result : $result; |
506
|
|
|
|
|
|
|
} |
507
|
|
|
|
|
|
|
: |
508
|
|
|
|
|
|
|
sub { |
509
|
23
|
|
|
23
|
|
8944
|
my ($self, @args) = @_; |
510
|
23
|
100
|
|
|
|
68
|
$self->$mutator(@args) if scalar(@args) >= 1; |
511
|
23
|
50
|
100
|
|
|
127
|
my $result = $on_read ? $on_read->($self, $attr, 'accessor') |
|
|
50
|
|
|
|
|
|
512
|
|
|
|
|
|
|
: ($transistent ? get_attribute($self, $storage_key) : ($self->{$storage_key} ||= [])); |
513
|
23
|
100
|
|
|
|
73
|
wantarray ? @$result : $result; |
514
|
11
|
100
|
|
|
|
108
|
}; |
515
|
|
|
|
|
|
|
} |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
=item generate_array_mutator_method |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=cut |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
sub generate_array_mutator_method { |
523
|
11
|
|
|
11
|
1
|
33
|
shift()->generate_mutator_method; |
524
|
|
|
|
|
|
|
} |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
=item generate_hash_accessor_method |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=cut |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
sub generate_hash_accessor_method { |
532
|
12
|
|
|
12
|
1
|
23
|
my $attr = shift; |
533
|
12
|
|
|
|
|
44
|
my $mutator = $attr->mutator; |
534
|
12
|
|
|
|
|
37
|
my $storage_key = $attr->storage_key; |
535
|
12
|
|
|
|
|
34
|
my $transistent = $attr->transistent; |
536
|
12
|
|
|
|
|
44
|
my $on_read = $attr->on_read; |
537
|
12
|
|
|
|
|
42
|
my $array_storage_type = $attr->storage_type eq 'Array'; |
538
|
|
|
|
|
|
|
$attr->associated_class |
539
|
|
|
|
|
|
|
? $attr->generate_to_many_accessor_method |
540
|
|
|
|
|
|
|
: ($array_storage_type ? |
541
|
|
|
|
|
|
|
sub { |
542
|
0
|
|
|
0
|
|
0
|
my ($self, @args) = @_; |
543
|
0
|
0
|
|
|
|
0
|
$self->$mutator(@args) if scalar(@args) >= 1; |
544
|
0
|
0
|
0
|
|
|
0
|
my $result = $on_read |
|
|
0
|
|
|
|
|
|
545
|
|
|
|
|
|
|
? $on_read->($self, $attr, 'accessor') |
546
|
|
|
|
|
|
|
: ($transistent ? get_attribute($self, $storage_key) : ($self->[$storage_key] ||= {})); |
547
|
0
|
0
|
|
|
|
0
|
wantarray ? %$result : $result; |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
: sub { |
550
|
11
|
|
|
11
|
|
2822
|
my ($self, @args) = @_; |
551
|
11
|
100
|
|
|
|
46
|
$self->$mutator(@args) if scalar(@args) >= 1; |
552
|
11
|
100
|
100
|
|
|
58
|
my $result = $on_read |
|
|
100
|
|
|
|
|
|
553
|
|
|
|
|
|
|
? $on_read->($self, $attr, 'accessor') |
554
|
|
|
|
|
|
|
: ($transistent ? get_attribute($self, $storage_key) : ($self->{$storage_key} ||= {})); |
555
|
11
|
100
|
|
|
|
62
|
wantarray ? %$result : $result; |
556
|
12
|
100
|
|
|
|
38
|
}); |
|
|
100
|
|
|
|
|
|
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
=item generate_to_many_accessor_method |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
=cut |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
sub generate_to_many_accessor_method { |
565
|
3
|
|
|
3
|
1
|
5
|
my $attr = shift; |
566
|
3
|
|
|
|
|
8
|
my $mutator = $attr->mutator; |
567
|
3
|
|
|
|
|
23
|
my $storage_key = $attr->storage_key; |
568
|
3
|
|
|
|
|
9
|
my $transistent = $attr->transistent; |
569
|
3
|
|
|
|
|
9
|
my $on_read = $attr->on_read; |
570
|
3
|
|
|
|
|
8
|
my $array_storage_type = $attr->storage_type eq 'Array'; |
571
|
|
|
|
|
|
|
$array_storage_type ? |
572
|
|
|
|
|
|
|
sub { |
573
|
0
|
|
|
0
|
|
0
|
my ($self, @args) = @_; |
574
|
0
|
0
|
|
|
|
0
|
$self->$mutator(@args) if scalar(@args) >= 1; |
575
|
0
|
0
|
0
|
|
|
0
|
my $result = $on_read |
|
|
0
|
|
|
|
|
|
576
|
|
|
|
|
|
|
? $on_read->($self, $attr, 'accessor') |
577
|
|
|
|
|
|
|
: ($transistent ? get_attribute($self, $storage_key) : ($self->[$storage_key] ||= {})); |
578
|
0
|
0
|
|
|
|
0
|
wantarray ? %$result : $result; |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
: |
581
|
|
|
|
|
|
|
sub { |
582
|
12
|
|
|
12
|
|
568
|
my ($self, @args) = @_; |
583
|
12
|
50
|
|
|
|
34
|
$self->$mutator(@args) if scalar(@args) >= 1; |
584
|
12
|
50
|
50
|
|
|
46
|
my $result = $on_read |
|
|
50
|
|
|
|
|
|
585
|
|
|
|
|
|
|
? $on_read->($self, $attr, 'accessor') |
586
|
|
|
|
|
|
|
: ($transistent ? get_attribute($self, $storage_key) : ($self->{$storage_key} ||= {})); |
587
|
12
|
50
|
|
|
|
35
|
wantarray ? %$result : $result; |
588
|
3
|
50
|
|
|
|
46
|
}; |
589
|
|
|
|
|
|
|
} |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
=item generate_hash_mutator_method |
593
|
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
=cut |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
sub generate_hash_mutator_method { |
597
|
12
|
|
|
12
|
1
|
35
|
shift()->generate_mutator_method; |
598
|
|
|
|
|
|
|
} |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
=item generate_hash_item_accessor_method |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
=cut |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
sub generate_hash_item_accessor_method { |
606
|
8
|
|
|
8
|
1
|
17
|
my $attr = shift; |
607
|
8
|
|
|
|
|
33
|
my $accesor = $attr->accessor; |
608
|
8
|
|
|
|
|
27
|
my $on_change = $attr->on_change; |
609
|
8
|
|
|
|
|
26
|
my $on_read = $attr->on_read; |
610
|
|
|
|
|
|
|
sub { |
611
|
11
|
|
|
11
|
|
6350
|
my $self = shift; |
612
|
11
|
|
|
|
|
23
|
my ($key, $value) = (@_); |
613
|
11
|
|
|
|
|
36
|
my $hash_ref = $self->$accesor(); |
614
|
11
|
100
|
|
|
|
31
|
if(defined $value) { |
615
|
2
|
100
|
50
|
|
|
12
|
$on_change->($self, $attr, 'item_accessor', \$value, $key) or return $hash_ref->{$key} |
616
|
|
|
|
|
|
|
if ($on_change); |
617
|
2
|
|
|
|
|
24
|
$hash_ref->{$key} = $value; |
618
|
|
|
|
|
|
|
} |
619
|
11
|
100
|
|
|
|
73
|
$on_read ? $on_read->($self, $attr, 'item_accessor', $key) : $hash_ref->{$key}; |
620
|
8
|
|
|
|
|
67
|
}; |
621
|
|
|
|
|
|
|
} |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=item generate_hash_add_method |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
=cut |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
sub generate_hash_add_method { |
629
|
3
|
|
|
3
|
1
|
4
|
my $attr = shift; |
630
|
3
|
|
|
|
|
7
|
my $accessor = $attr->accessor; |
631
|
3
|
|
|
|
|
8
|
my $item_accessor = $attr->item_accessor; |
632
|
3
|
|
|
|
|
14
|
my $on_change = $attr->on_change; |
633
|
3
|
|
|
|
|
8
|
my $on_read = $attr->on_read; |
634
|
3
|
|
|
|
|
8
|
my $index_by = $attr->index_by; |
635
|
|
|
|
|
|
|
sub { |
636
|
0
|
|
|
0
|
|
0
|
my ($self, @values) = @_; |
637
|
0
|
|
|
|
|
0
|
my $hash_ref = $self->$accessor(); |
638
|
0
|
|
|
|
|
0
|
foreach my $value (@values) { |
639
|
0
|
0
|
|
|
|
0
|
next unless ref($value); |
640
|
0
|
0
|
|
|
|
0
|
my $key = ($index_by ? $value->$index_by : $value . "") or confess "unknown key hash at add_$accessor"; |
|
|
0
|
|
|
|
|
|
641
|
0
|
|
|
|
|
0
|
$attr->validate_associated_class($self, $value); |
642
|
0
|
0
|
0
|
|
|
0
|
$on_change->($self, $attr, 'item_accessor', \$value, $key) or return $hash_ref->{$key} |
643
|
|
|
|
|
|
|
if ($on_change); |
644
|
0
|
|
|
|
|
0
|
$hash_ref->{$key} = $value; |
645
|
|
|
|
|
|
|
} |
646
|
0
|
|
|
|
|
0
|
$self; |
647
|
3
|
|
|
|
|
22
|
}; |
648
|
|
|
|
|
|
|
} |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
=item generate_scalar_reset_method |
652
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
=cut |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
sub generate_scalar_reset_method { |
656
|
8
|
|
|
8
|
1
|
12
|
my $attr = shift; |
657
|
8
|
|
|
|
|
22
|
my $mutator = $attr->mutator; |
658
|
8
|
|
|
|
|
20
|
my $index_by = $attr->index_by; |
659
|
|
|
|
|
|
|
sub { |
660
|
1
|
|
|
1
|
|
2
|
my ($self, ) = @_; |
661
|
1
|
|
|
|
|
3
|
$self->$mutator(undef); |
662
|
8
|
|
|
|
|
54
|
}; |
663
|
|
|
|
|
|
|
} |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
=item generate_scalar_has_method |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
=cut |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
sub generate_scalar_has_method { |
671
|
8
|
|
|
8
|
1
|
11
|
my $attr = shift; |
672
|
|
|
|
|
|
|
sub { |
673
|
2
|
|
|
2
|
|
498
|
my ($self, ) = @_; |
674
|
2
|
|
|
|
|
5
|
!! $attr->get_value($self); |
675
|
8
|
|
|
|
|
46
|
}; |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
|
679
|
|
|
|
|
|
|
=item generate_hash_reset_method |
680
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
=cut |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
sub generate_hash_reset_method { |
684
|
3
|
|
|
3
|
1
|
6
|
my $attr = shift; |
685
|
3
|
|
|
|
|
10
|
my $mutator = $attr->mutator; |
686
|
3
|
|
|
|
|
8
|
my $index_by = $attr->index_by; |
687
|
|
|
|
|
|
|
sub { |
688
|
1
|
|
|
1
|
|
3
|
my ($self, ) = @_; |
689
|
1
|
|
|
|
|
5
|
$self->$mutator({}); |
690
|
3
|
|
|
|
|
19
|
}; |
691
|
|
|
|
|
|
|
} |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
|
695
|
|
|
|
|
|
|
=item generate_hash_has_method |
696
|
|
|
|
|
|
|
|
697
|
|
|
|
|
|
|
=cut |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
sub generate_hash_has_method { |
700
|
3
|
|
|
3
|
1
|
13
|
my $attr = shift; |
701
|
|
|
|
|
|
|
sub { |
702
|
2
|
|
|
2
|
|
5
|
my ($self, ) = @_; |
703
|
2
|
|
|
|
|
9
|
my $value = $attr->get_value($self); |
704
|
2
|
|
66
|
|
|
21
|
!! ($value && keys %$value); |
705
|
3
|
|
|
|
|
26
|
}; |
706
|
|
|
|
|
|
|
} |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
=item generate_array_reset_method |
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
=cut |
713
|
|
|
|
|
|
|
|
714
|
|
|
|
|
|
|
sub generate_array_reset_method { |
715
|
3
|
|
|
3
|
1
|
5
|
my $attr = shift; |
716
|
3
|
|
|
|
|
8
|
my $mutator = $attr->mutator; |
717
|
3
|
|
|
|
|
14
|
my $index_by = $attr->index_by; |
718
|
|
|
|
|
|
|
sub { |
719
|
1
|
|
|
1
|
|
2
|
my ($self, ) = @_; |
720
|
1
|
|
|
|
|
4
|
$self->$mutator([]); |
721
|
3
|
|
|
|
|
18
|
}; |
722
|
|
|
|
|
|
|
} |
723
|
|
|
|
|
|
|
|
724
|
|
|
|
|
|
|
|
725
|
|
|
|
|
|
|
=item generate_array_has_method |
726
|
|
|
|
|
|
|
|
727
|
|
|
|
|
|
|
=cut |
728
|
|
|
|
|
|
|
|
729
|
|
|
|
|
|
|
sub generate_array_has_method { |
730
|
3
|
|
|
3
|
1
|
11
|
my $attr = shift; |
731
|
|
|
|
|
|
|
sub { |
732
|
2
|
|
|
2
|
|
379
|
my ($self, ) = @_; |
733
|
2
|
|
|
|
|
5
|
my $value = $attr->get_value($self); |
734
|
2
|
|
66
|
|
|
15
|
!! ($value && @$value); |
735
|
3
|
|
|
|
|
18
|
}; |
736
|
|
|
|
|
|
|
} |
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
=item generate_hash_remove_method |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
=cut |
742
|
|
|
|
|
|
|
|
743
|
|
|
|
|
|
|
#TODO add on_remove trigger |
744
|
|
|
|
|
|
|
|
745
|
|
|
|
|
|
|
sub generate_hash_remove_method { |
746
|
3
|
|
|
3
|
1
|
6
|
my $attr = shift; |
747
|
3
|
|
|
|
|
35
|
my $accessor = $attr->accessor; |
748
|
3
|
|
|
|
|
9
|
my $item_accessor = $attr->item_accessor; |
749
|
3
|
|
|
|
|
8
|
my $the_other_end = $attr->the_other_end; |
750
|
3
|
|
|
|
|
8
|
my $meta = Abstract::Meta::Class::meta_class($attr->associated_class); |
751
|
3
|
100
|
66
|
|
|
39
|
my $reflective_attribute = $the_other_end && $meta ? $meta->attribute($the_other_end) : undef; |
752
|
3
|
|
|
|
|
8
|
my $index_by = $attr->index_by; |
753
|
|
|
|
|
|
|
sub { |
754
|
2
|
|
|
2
|
|
939
|
my ($self, @values) = @_; |
755
|
2
|
|
|
|
|
7
|
my $hash_ref = $self->$accessor(); |
756
|
2
|
|
|
|
|
5
|
foreach my $value (@values) { |
757
|
2
|
100
|
|
|
|
7
|
next unless ref($value); |
758
|
1
|
50
|
33
|
|
|
8
|
my $key = ($index_by && ref($value) ? $value->$index_by : $value . ""); |
759
|
1
|
|
|
|
|
5
|
$attr->deassociate($self); |
760
|
1
|
50
|
|
|
|
3
|
$reflective_attribute->set_value($hash_ref->{$key}, undef) |
761
|
|
|
|
|
|
|
if $reflective_attribute; |
762
|
1
|
|
|
|
|
2
|
delete $hash_ref->{$key}; |
763
|
|
|
|
|
|
|
} |
764
|
2
|
|
|
|
|
5
|
$self; |
765
|
3
|
|
|
|
|
29
|
}; |
766
|
|
|
|
|
|
|
} |
767
|
|
|
|
|
|
|
|
768
|
|
|
|
|
|
|
|
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
=item generate_array_item_accessor_method |
771
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
=cut |
773
|
|
|
|
|
|
|
|
774
|
|
|
|
|
|
|
sub generate_array_item_accessor_method { |
775
|
3
|
|
|
3
|
1
|
8
|
my $attr = shift; |
776
|
3
|
|
|
|
|
19
|
my $accesor = $attr->accessor; |
777
|
3
|
|
|
|
|
11
|
my $on_change = $attr->on_change; |
778
|
3
|
|
|
|
|
10
|
my $on_read = $attr->on_read; |
779
|
|
|
|
|
|
|
sub { |
780
|
6
|
|
|
6
|
|
2824
|
my $self = shift; |
781
|
6
|
|
|
|
|
12
|
my ($index, $value) = (@_); |
782
|
6
|
|
|
|
|
19
|
my $hash_ref = $self->$accesor(); |
783
|
6
|
100
|
|
|
|
18
|
if (defined $value) { |
784
|
1
|
50
|
50
|
|
|
9
|
$on_change->($self, $attr, 'item_accessor', \$value, $index) or return $hash_ref->[$index] |
785
|
|
|
|
|
|
|
if ($on_change); |
786
|
1
|
|
|
|
|
12
|
$hash_ref->[$index] = $value; |
787
|
|
|
|
|
|
|
} |
788
|
6
|
50
|
|
|
|
29
|
$on_read ? $on_read->($self, $attr, 'item_accessor', $index) : $hash_ref->[$index]; |
789
|
3
|
|
|
|
|
27
|
}; |
790
|
|
|
|
|
|
|
} |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
=item generate_array_push_method |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
=cut |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
sub generate_array_push_method { |
798
|
11
|
|
|
11
|
1
|
18
|
my $attr = shift; |
799
|
11
|
|
|
|
|
35
|
my $accesor = $attr->accessor; |
800
|
|
|
|
|
|
|
sub { |
801
|
2
|
|
|
2
|
|
33
|
my $self = shift; |
802
|
2
|
|
|
|
|
8
|
my $array_ref = $self->$accesor(); |
803
|
2
|
|
|
|
|
10
|
push @$array_ref, @_; |
804
|
11
|
|
|
|
|
107
|
}; |
805
|
|
|
|
|
|
|
} |
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
=item generate_array_pop_method |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
=cut |
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
sub generate_array_pop_method { |
813
|
11
|
|
|
11
|
1
|
17
|
my $attr = shift; |
814
|
11
|
|
|
|
|
31
|
my $accesor = $attr->accessor; |
815
|
|
|
|
|
|
|
sub { |
816
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
817
|
1
|
|
|
|
|
3
|
my $array_ref = $self->$accesor(); |
818
|
1
|
|
|
|
|
4
|
pop @$array_ref; |
819
|
11
|
|
|
|
|
87
|
}; |
820
|
|
|
|
|
|
|
} |
821
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
|
823
|
|
|
|
|
|
|
=item generate_array_shift_method |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
=cut |
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
sub generate_array_shift_method { |
828
|
11
|
|
|
11
|
1
|
21
|
my $attr = shift; |
829
|
11
|
|
|
|
|
39
|
my $accesor = $attr->accessor; |
830
|
|
|
|
|
|
|
sub { |
831
|
1
|
|
|
1
|
|
2
|
my $self = shift; |
832
|
1
|
|
|
|
|
4
|
my $array_ref= $self->$accesor(); |
833
|
1
|
|
|
|
|
4
|
shift @$array_ref; |
834
|
11
|
|
|
|
|
159
|
}; |
835
|
|
|
|
|
|
|
} |
836
|
|
|
|
|
|
|
|
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
=item generate_array_unshift_method |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
=cut |
841
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
sub generate_array_unshift_method { |
843
|
11
|
|
|
11
|
1
|
18
|
my $attr = shift; |
844
|
11
|
|
|
|
|
42
|
my $accesor = $attr->accessor; |
845
|
|
|
|
|
|
|
sub { |
846
|
1
|
|
|
1
|
|
2
|
my $self = shift; |
847
|
1
|
|
|
|
|
4
|
my $array_ref = $self->$accesor(); |
848
|
1
|
|
|
|
|
5
|
unshift @$array_ref, @_; |
849
|
11
|
|
|
|
|
71
|
}; |
850
|
|
|
|
|
|
|
} |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
=item generate_array_count_method |
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
=cut |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
sub generate_array_count_method { |
858
|
11
|
|
|
11
|
1
|
18
|
my $attr = shift; |
859
|
11
|
|
|
|
|
30
|
my $accesor = $attr->accessor; |
860
|
|
|
|
|
|
|
sub { |
861
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
862
|
1
|
|
|
|
|
3
|
my $array_ref = $self->$accesor(); |
863
|
1
|
|
|
|
|
4
|
scalar @$array_ref; |
864
|
11
|
|
|
|
|
73
|
}; |
865
|
|
|
|
|
|
|
} |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
=item generate_array_add_method |
869
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
=cut |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
sub generate_array_add_method { |
873
|
3
|
|
|
3
|
1
|
6
|
my $attr = shift; |
874
|
3
|
|
|
|
|
8
|
my $accesor = $attr->accessor; |
875
|
3
|
|
|
|
|
7
|
my $accessor = $attr->accessor; |
876
|
3
|
|
|
|
|
9
|
my $the_other_end = $attr->the_other_end; |
877
|
3
|
|
|
|
|
17
|
my $associated_class = $attr->associated_class; |
878
|
|
|
|
|
|
|
sub { |
879
|
0
|
|
|
0
|
|
0
|
my ($self, @values) = @_; |
880
|
0
|
|
|
|
|
0
|
my $array_ref = $self->$accesor(); |
881
|
0
|
|
|
|
|
0
|
foreach my $value (@values) { |
882
|
0
|
|
|
|
|
0
|
$attr->validate_associated_class($self, $value, $accessor, $associated_class, $the_other_end); |
883
|
0
|
|
|
|
|
0
|
push @$array_ref, $value; |
884
|
|
|
|
|
|
|
} |
885
|
0
|
|
|
|
|
0
|
$self; |
886
|
3
|
|
|
|
|
24
|
}; |
887
|
|
|
|
|
|
|
} |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
|
890
|
|
|
|
|
|
|
=item generate_array_remove_method |
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
=cut |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
#TODO add on_remove trigger |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
sub generate_array_remove_method { |
897
|
3
|
|
|
3
|
1
|
7
|
my $attr = shift; |
898
|
3
|
|
|
|
|
7
|
my $accesor = $attr->accessor; |
899
|
3
|
|
|
|
|
9
|
my $accessor = $attr->accessor; |
900
|
3
|
|
|
|
|
8
|
my $the_other_end = $attr->the_other_end; |
901
|
3
|
|
|
|
|
8
|
my $meta = Abstract::Meta::Class::meta_class($attr->associated_class); |
902
|
3
|
100
|
66
|
|
|
18
|
my $reflective_attribute = $the_other_end && $meta ? $meta->attribute($the_other_end) : undef; |
903
|
|
|
|
|
|
|
sub { |
904
|
1
|
|
|
1
|
|
5
|
my ($self, @values) = @_; |
905
|
1
|
|
|
|
|
3
|
my $array_ref = $self->$accesor(); |
906
|
1
|
|
|
|
|
2
|
foreach my $value(@values) { |
907
|
1
|
|
|
|
|
2
|
for my $i (0 .. $#{$array_ref}) { |
|
1
|
|
|
|
|
3
|
|
908
|
3
|
100
|
100
|
|
|
19
|
if ($array_ref->[$i] && $array_ref->[$i] eq $value) { |
909
|
1
|
50
|
|
|
|
3
|
$reflective_attribute->set_value($value, undef) |
910
|
|
|
|
|
|
|
if $reflective_attribute; |
911
|
1
|
|
|
|
|
4
|
splice @$array_ref, $i--, 1; |
912
|
|
|
|
|
|
|
} |
913
|
|
|
|
|
|
|
} |
914
|
|
|
|
|
|
|
} |
915
|
1
|
|
|
|
|
3
|
$self; |
916
|
3
|
|
|
|
|
24
|
}; |
917
|
|
|
|
|
|
|
} |
918
|
|
|
|
|
|
|
|
919
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
=item generate |
921
|
|
|
|
|
|
|
|
922
|
|
|
|
|
|
|
Returns code reference. |
923
|
|
|
|
|
|
|
|
924
|
|
|
|
|
|
|
=cut |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
sub generate { |
927
|
222
|
|
|
222
|
1
|
323
|
my ($self, $method_name) = @_; |
928
|
222
|
|
|
|
|
572
|
my $call = "generate_" . lc($self->perl_type) . "_${method_name}_method"; |
929
|
222
|
|
|
|
|
974
|
$self->$call; |
930
|
|
|
|
|
|
|
} |
931
|
|
|
|
|
|
|
|
932
|
|
|
|
|
|
|
|
933
|
|
|
|
|
|
|
=item set_value |
934
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
Sets value for attribute |
936
|
|
|
|
|
|
|
|
937
|
|
|
|
|
|
|
=cut |
938
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
sub set_value { |
940
|
0
|
|
|
0
|
1
|
0
|
my ($attr, $self, $value) = @_; |
941
|
0
|
|
|
|
|
0
|
my $array_storage_type = $attr->storage_type eq 'Array'; |
942
|
0
|
|
|
|
|
0
|
my $storage_key = $attr->storage_key; |
943
|
0
|
|
|
|
|
0
|
my $transistent = $attr->transistent; |
944
|
0
|
0
|
|
|
|
0
|
if($transistent) { |
|
|
0
|
|
|
|
|
|
945
|
0
|
|
|
|
|
0
|
set_attribute($self, $storage_key, $value); |
946
|
|
|
|
|
|
|
} elsif($array_storage_type) { |
947
|
0
|
|
|
|
|
0
|
$self->[$storage_key] = $value; |
948
|
|
|
|
|
|
|
} else { |
949
|
0
|
|
|
|
|
0
|
$self->{$storage_key} = $value; |
950
|
|
|
|
|
|
|
} |
951
|
|
|
|
|
|
|
} |
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
|
954
|
|
|
|
|
|
|
=item get_value |
955
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
Returns value for attribute |
957
|
|
|
|
|
|
|
|
958
|
|
|
|
|
|
|
=cut |
959
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
sub get_value { |
961
|
73
|
|
|
73
|
1
|
130
|
my ($attr, $self) = @_; |
962
|
73
|
|
|
|
|
182
|
my $storage_key = $attr->storage_key; |
963
|
73
|
|
|
|
|
187
|
my $transistent = $attr->transistent; |
964
|
73
|
|
|
|
|
209
|
my $array_storage_type = $attr->storage_type eq 'Array'; |
965
|
73
|
100
|
|
|
|
200
|
if ($transistent) { |
|
|
50
|
|
|
|
|
|
966
|
2
|
|
|
|
|
7
|
return get_attribute($self, $storage_key); |
967
|
|
|
|
|
|
|
} elsif($array_storage_type) { |
968
|
0
|
|
|
|
|
0
|
$self->[$storage_key]; |
969
|
|
|
|
|
|
|
} else { |
970
|
71
|
|
|
|
|
316
|
return $self->{$storage_key}; |
971
|
|
|
|
|
|
|
} |
972
|
|
|
|
|
|
|
} |
973
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
{ |
976
|
|
|
|
|
|
|
|
977
|
|
|
|
|
|
|
my %storage; |
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
=item get_attribute |
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
Return object's attribute value |
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
=cut |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
sub get_attribute { |
986
|
6
|
|
|
6
|
1
|
13
|
my ($self, $key) = @_; |
987
|
6
|
|
100
|
|
|
25
|
my $object = $storage{$self} ||= {}; |
988
|
6
|
|
|
|
|
25
|
return $object->{$key}; |
989
|
|
|
|
|
|
|
} |
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
=item set_attribute |
993
|
|
|
|
|
|
|
|
994
|
|
|
|
|
|
|
Sets for passed in object attribue's value |
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
=cut |
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
sub set_attribute { |
999
|
3
|
|
|
3
|
1
|
6
|
my ($self, $key, $value) = @_; |
1000
|
3
|
|
100
|
|
|
27
|
my $object = $storage{$self} ||= {}; |
1001
|
3
|
|
|
|
|
12
|
$object->{$key} = $value; |
1002
|
|
|
|
|
|
|
} |
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
=item delete_object |
1006
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
Deletes passed in object's attribute |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
=cut |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
sub delete_object { |
1012
|
2
|
|
|
2
|
1
|
4
|
my ($self) = @_; |
1013
|
2
|
|
|
|
|
12
|
delete $storage{$self}; |
1014
|
|
|
|
|
|
|
} |
1015
|
|
|
|
|
|
|
} |
1016
|
|
|
|
|
|
|
|
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
1; |
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
__END__ |