File Coverage

blib/lib/Class/Accessor/FactoryTyped.pm
Criterion Covered Total %
statement 102 149 68.4
branch 27 82 32.9
condition 12 66 18.1
subroutine 25 46 54.3
pod 2 2 100.0
total 168 345 48.7


line stmt bran cond sub pod time code
1 3     3   22610 use 5.008;
  3         11  
  3         114  
2 3     3   15 use strict;
  3         7  
  3         82  
3 3     3   16 use warnings;
  3         3  
  3         157  
4              
5             package Class::Accessor::FactoryTyped;
6             BEGIN {
7 3     3   70 $Class::Accessor::FactoryTyped::VERSION = '1.100970';
8             }
9              
10             # ABSTRACT: Accessors whose values come from a factory
11 3     3   17 use Carp 'croak';
  3         5  
  3         189  
12 3     3   6284 use Data::Miscellany 'set_push';
  3         4379  
  3         220  
13 3     3   3008 use UNIVERSAL::require;
  3         5727  
  3         32  
14 3         24 use parent qw(
15             Class::Accessor::Complex
16             Class::Accessor::Installer
17 3     3   114 );
  3         7  
18             __PACKAGE__->mk_class_array_accessors(
19             qw(factory_typed_accessors factory_typed_array_accessors));
20              
21             sub mk_factory_typed_accessors {
22 3     3 1 4540 my ($self, $factory_class_name, @args) = @_;
23 3   33     31 my $class = ref $self || $self;
24 3 50       497 $factory_class_name->require or die $@;
25 3         21693 while (@args) {
26 6         128 my $type = shift @args;
27 6 50       21 my $list = shift @args or die "No slot names for $class";
28              
29             # Allow a list of hashrefs.
30 6 50       28 my @list = (ref($list) eq 'ARRAY') ? @$list : ($list);
31 6         10 for my $obj_def (@list) {
32 6         12 my ($name, @composites);
33 6 50       19 if (!ref $obj_def) {
34 6         13 $name = $obj_def;
35             } else {
36 0         0 $name = $obj_def->{slot};
37 0         0 my $composites = $obj_def->{comp_mthds};
38 0 0       0 @composites =
    0          
39             ref($composites) eq 'ARRAY' ? @$composites
40             : defined $composites ? ($composites)
41             : ();
42             }
43 6         16 for my $meth (@composites) {
44             $self->install_accessor(
45             name => $meth,
46             code => sub {
47 0 0 0 0   0 local $DB::sub = local *__ANON__ = "${class}::{$meth}"
48             if defined &DB::DB && !$Devel::DProf::VERSION;
49 0         0 my ($self, @args) = @_;
50 0         0 $self->$name()->$meth(@args);
51             },
52 0         0 );
53 0         0 $self->document_accessor(
54             name => $meth,
55             purpose => <
56             Calls $meth() with the given arguments on the object stored in the $name slot.
57             If there is no such object, a new $type object is constructed - no arguments
58             are passed to the constructor - and stored in the $name slot before forwarding
59             $meth() onto it.
60             EODOC
61             examples => [ "\$obj->$meth(\@args);", "\$obj->$meth;", ],
62             );
63             }
64 6         11 my $expected_class;
65              
66             # use a class list to the target package to keep track of which
67             # framework_objects the class has, for introspection purposes
68 6         54 $self->factory_typed_accessors_push($name);
69             $self->install_accessor(
70             name => $name,
71             code => sub {
72 4 50 33 4   1433 local $DB::sub = local *__ANON__ = "${class}::${name}"
        4      
        4      
73             if defined &DB::DB && !$Devel::DProf::VERSION;
74 4         10 my ($self, @args) = @_;
75 4 50       12 unless ($expected_class) {
76 4         33 $expected_class =
77             $factory_class_name->get_registered_class($type);
78 4 50       48 die "no factory class name for type [$type]"
79             unless $expected_class;
80              
81             # need to load the class to do UNIVERSAL::isa stuff on the
82             # class name
83 4 50       26 $expected_class->require or die $@;
84             }
85              
86             # if (ref $args[0] eq $expected_class) {
87 4 50 33     10365 if (defined($args[0])
    50 33        
88             && UNIVERSAL::isa($args[0], $expected_class)) {
89 0         0 return $self->{$name} = $args[0];
90             } elsif (@args || !defined $self->{$name}) {
91              
92             # We accept a hashref of args as well and have to deref it
93             # first, since we're going to push args onto the @args
94             # array.
95 0         0 @args =
96             (scalar(@args == 1) && ref($args[0]) eq 'HASH')
97 4 50 33     21 ? %{ $args[0] }
98             : @args;
99              
100             # Create an object if args are given, or autovivify one if
101             # no args are given and it doesn't exist yet.
102 4         38 return $self->{$name} =
103             $factory_class_name->make_object_for_type($type,
104             @args);
105             }
106              
107             # Still here? Hm, shouldn't happen, but return the value anyway.
108 0         0 $self->{$name};
109             }
110 6         125 );
111             $self->install_accessor(
112             name => [ "clear_${name}", "${name}_clear" ],
113             code => sub {
114 0 0 0 0   0 local $DB::sub = local *__ANON__ = "${class}::${name}_clear"
        0      
        0      
115             if defined &DB::DB && !$Devel::DProf::VERSION;
116 0         0 $_[0]->{$name} = undef;
117             }
118 6         254 );
119             $self->install_accessor(
120             name => [ "exists_${name}", "${name}_exists" ],
121             code => sub {
122 0 0 0 0   0 local $DB::sub = local *__ANON__ =
        0      
        0      
123             "${class}::${name}_exists"
124             if defined &DB::DB && !$Devel::DProf::VERSION;
125 0         0 exists $_[0]->{$name};
126             }
127 6         347 );
128             }
129             }
130 3         110 $self; # for chaining
131             }
132              
133             sub mk_factory_typed_array_accessors {
134 3     3 1 40 my ($self, $factory_class_name, @args) = @_;
135 3   33     26 my $class = ref $self || $self;
136 3 50       32 $factory_class_name->require or die $@;
137 3         132 while (@args) {
138 3         8 my $object_type_const = shift @args;
139 3 50       15 my $list = shift @args or die "No slot names for $class";
140              
141             # Allow a list of hashrefs.
142 3 50       15 my @list = (ref($list) eq 'ARRAY') ? @$list : ($list);
143 3         7 for my $field (@list) {
144 3         9 my $normalize = "${field}_normalize";
145             $self->install_accessor(
146             name => $normalize,
147             code => sub {
148 1 50 33 1   5 local $DB::sub = local *__ANON__ = "${class}::${normalize}"
        1      
149             if defined &DB::DB && !$Devel::DProf::VERSION;
150 1         3 my $self = shift;
151 2 50       9 map {
152 2 50       10 ref $_
153             ? $_
154             : $factory_class_name->make_object_for_type(
155             $object_type_const, $_,);
156             }
157             map {
158 1         3 ref $_ eq 'ARRAY' ? @$_ : ($_)
159             } @_;
160             }
161 3         32 );
162              
163             # use a class list to the target package to keep track of which
164             # framework_list_objects the class has, for introspection purposes
165 3         93 $self->factory_typed_array_accessors_push($field);
166             $self->install_accessor(
167             name => $field,
168             code => sub {
169 1 50 33 1   6 local $DB::sub = local *__ANON__ = "${class}::${field}"
        1      
170             if defined &DB::DB && !$Devel::DProf::VERSION;
171 1         2 my $self = shift;
172 1 50       5 defined $self->{$field} or $self->{$field} = [];
173 1 50       3 @{ $self->{$field} } = $self->$normalize(@_) if @_;
  0         0  
174 1 50       5 wantarray ? @{ $self->{$field} } : $self->{$field};
  1         5  
175             }
176 3         35 );
177             $self->install_accessor(
178             name => [ "pop_${field}", "${field}_pop" ],
179             code => sub {
180 1 50 33 1   519 local $DB::sub = local *__ANON__ = "${class}::${field}_pop"
        1      
181             if defined &DB::DB && !$Devel::DProf::VERSION;
182 1         3 my ($self) = @_;
183 1         2 pop @{ $self->{$field} };
  1         5  
184             }
185 3         99 );
186             $self->install_accessor(
187             name => [ "set_push_${field}", "${field}_set_push" ],
188             code => sub {
189 0 0 0 0   0 local $DB::sub = local *__ANON__ =
        0      
190             "${class}::${field}_set_push"
191             if defined &DB::DB && !$Devel::DProf::VERSION;
192 0         0 my ($self, @values) = @_;
193 0         0 set_push @{ $self->{$field} }, $self->$normalize(@values);
  0         0  
194             }
195 3         112 );
196             $self->install_accessor(
197             name => [ "push_${field}", "${field}_push" ],
198             code => sub {
199 1 50 33 1   2731 local $DB::sub = local *__ANON__ = "${class}::${field}_push"
        1      
200             if defined &DB::DB && !$Devel::DProf::VERSION;
201 1         4 my ($self, @values) = @_;
202 1         2 push @{ $self->{$field} }, $self->$normalize(@values);
  1         17  
203             }
204 3         115 );
205             $self->install_accessor(
206             name => [ "shift_${field}", "${field}_shift" ],
207             code => sub {
208 0 0 0 0   0 local $DB::sub = local *__ANON__ =
        0      
209             "${class}::${field}_shift"
210             if defined &DB::DB && !$Devel::DProf::VERSION;
211 0         0 my ($self) = @_;
212 0         0 shift @{ $self->{$field} };
  0         0  
213             }
214 3         111 );
215             $self->install_accessor(
216             name => [ "unshift_${field}", "${field}_unshift" ],
217             code => sub {
218 0 0 0 0   0 local $DB::sub = local *__ANON__ =
        0      
219             "${class}::${field}_unshift"
220             if defined &DB::DB && !$Devel::DProf::VERSION;
221 0         0 my ($self, @values) = @_;
222 0         0 unshift @{ $self->{$field} }, $self->$normalize(@values);
  0         0  
223             }
224 3         112 );
225             $self->install_accessor(
226             name => [ "splice_${field}", "${field}_splice" ],
227             code => sub {
228 0 0 0 0   0 local $DB::sub = local *__ANON__ =
        0      
229             "${class}::${field}_splice"
230             if defined &DB::DB && !$Devel::DProf::VERSION;
231 0         0 my ($self, $offset, $len, @list) = @_;
232 0         0 splice(@{ $self->{$field} }, $offset, $len, @list);
  0         0  
233             }
234 3         111 );
235             $self->install_accessor(
236             name => [ "clear_${field}", "${field}_clear" ],
237             code => sub {
238 0 0 0 0   0 local $DB::sub = local *__ANON__ =
        0      
239             "${class}::${field}_clear"
240             if defined &DB::DB && !$Devel::DProf::VERSION;
241 0         0 my ($self) = @_;
242 0         0 @{ $self->{$field} } = ();
  0         0  
243             }
244 3         117 );
245             $self->install_accessor(
246             name => [ "count_${field}", "${field}_count" ],
247             code => sub {
248 1 50 33 1   10 local $DB::sub = local *__ANON__ =
        1      
249             "${class}::${field}_count"
250             if defined &DB::DB && !$Devel::DProf::VERSION;
251 1         3 my ($self) = @_;
252 1 50       4 exists $self->{$field} ? scalar @{ $self->{$field} } : 0;
  1         9  
253             }
254 3         130 );
255             $self->install_accessor(
256             name => [ "index_${field}", "${field}_index" ],
257             code => sub {
258 1 50 33 1   530 local $DB::sub = local *__ANON__ =
        1      
259             "${class}::${field}_index"
260             if defined &DB::DB && !$Devel::DProf::VERSION;
261 1         2 my $self = shift;
262 1         2 my (@indices) = @_;
263 1         2 my @Result;
264 1         5 push @Result, $self->{$field}->[$_] for @indices;
265 1 50       8 return $Result[0] if @_ == 1;
266 0 0       0 wantarray ? @Result : \@Result;
267             }
268 3         111 );
269             $self->install_accessor(
270             name => [ "set_${field}", "${field}_set" ],
271             code => sub {
272 0 0 0 0   0 local $DB::sub = local *__ANON__ = "${class}::${field}_set"
        0      
273             if defined &DB::DB && !$Devel::DProf::VERSION;
274 0         0 my $self = shift;
275 0         0 my @args = @_;
276 0 0       0 croak "${field}_set expects an even number of fields\n"
277             if @args % 2;
278 0         0 while (my ($index, $value) = splice @args, 0, 2) {
279 0         0 $self->{$field}->[$index] = $self->$normalize($value);
280             }
281 0         0 return @_ / 2;
282             }
283 3         107 );
284             $self->install_accessor(
285             name => [ "ref_${field}", "${field}_ref" ],
286             code => sub {
287 0 0 0 0   0 local $DB::sub = local *__ANON__ = "${class}::${field}_ref"
        0      
288             if defined &DB::DB && !$Devel::DProf::VERSION;
289 0         0 my ($self) = @_;
290 0         0 $self->{$field};
291             }
292 3         109 );
293             }
294             }
295 3         110 $self; # for chaining
296             }
297             1;
298              
299              
300             __END__