File Coverage

blib/lib/Abstract/Meta/Attribute/Method.pm
Criterion Covered Total %
statement 351 423 82.9
branch 129 238 54.2
condition 49 83 59.0
subroutine 70 80 87.5
pod 47 47 100.0
total 646 871 74.1


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__