File Coverage

blib/lib/Anonymous/Object.pm
Criterion Covered Total %
statement 206 305 67.5
branch 84 128 65.6
condition 25 39 64.1
subroutine 45 47 95.7
pod 18 18 100.0
total 378 537 70.3


line stmt bran cond sub pod time code
1             package Anonymous::Object;
2 9     9   483166 use strict;
  9         71  
  9         260  
3 9     9   83 use warnings;
  9         20  
  9         276  
4 9     9   4525 use Data::Dumper;
  9         49212  
  9         682  
5             our $VERSION = 0.05;
6              
7             our $UNIQUE;
8             BEGIN {
9 9     9   37 $Data::Dumper::Deparse = 1;
10 9         17053 $UNIQUE = 0;
11             }
12              
13             sub new {
14 39 100   39 1 23587 my ( $cls, %args ) = ( shift(), scalar @_ == 1 ? %{ $_[0] } : @_ );
  37         164  
15 39         102 my $self = bless {}, $cls;
16 39         666 my %accessors = (
17             object_name => { default => 'Anonymous::Object' },
18             meta => { default => {}, },
19             default => { default => {}, },
20             types => { default => {}, },
21             type_library => { default => 'Types::Standard' },
22             type_map => {
23             default => {
24             HASH => 'HashRef',
25             ARRAY => 'ArrayRef',
26             STRING => 'Str',
27             SCALAR => 'ScalarRef',
28             REF => 'Ref',
29             CODE => 'CodeRef',
30             GLOB => 'GlobRef',
31             NUM => 'Num',
32             INT => 'Int',
33             default => 'Any'
34             }
35             }
36             );
37 39         156 for my $accessor ( keys %accessors ) {
38             my $param = defined $args{$accessor}
39             ? $args{$accessor}
40 214 100       445 : $accessors{$accessor}->{default};
41             my $value
42             = $self->$accessor( $accessors{$accessor}->{builder}
43 214 50       711 ? $accessors{$accessor}->{builder}->( $self, $param )
44             : $param );
45 212 50 33     560 unless ( !$accessors{$accessor}->{required} || defined $value ) {
46 2         4 die "$accessor accessor is required";
47             }
48             }
49 37         305 return $self;
50             }
51              
52             sub clean {
53 21     21 1 48 my $class = ref $_[0];
54             return $class->new({
55             object_name => $_[0]->{object_name},
56             type_library => $_[0]->{type_library},
57             type_map => $_[0]->{type_map}
58 21         128 });
59             }
60              
61             sub object_name {
62 37     37 1 218 my ($self, $value) = @_;
63 35 50       78 if ( defined $value ) {
64 35 50       70 if ( ref $value ) {
65 0         0 die qq{Str: invalid value $value for accessor object_name}
66             }
67 35         79 $self->{object_name} = $value;
68             }
69 35         69 return $self->{object_name};
70             }
71              
72             sub default {
73 83     85 1 152 my ( $self, $value ) = @_;
74 83 100       172 if ( defined $value ) {
75 40 50 50     129 if ( ( ref($value) || "" ) ne "HASH" ) {
76 0         0 die qq{HashRef: invalid value $value for accessor default};
77             }
78 40         81 $self->{default} = $value;
79             }
80 83         232 return $self->{default};
81             }
82              
83             sub meta {
84 249     249 1 1687 my ( $self, $value ) = @_;
85 249 100       443 if ( defined $value ) {
86 40 100 100     141 if ( ( ref($value) || "" ) ne "HASH" ) {
87 4         57 die qq{HashRef: invalid value $value for accessor meta};
88             }
89 36         73 $self->{meta} = $value;
90             }
91 245         764 return $self->{meta};
92             }
93              
94             sub types {
95 56     56 1 135 my ( $self, $value ) = @_;
96 56 100       119 if ( defined $value ) {
97 35 50 50     110 if ( ( ref($value) || "" ) ne "HASH" ) {
98 0         0 die qq{HashRef: invalid value $value for accessor types};
99             }
100 35         73 $self->{types} = $value;
101             }
102 56         249 return $self->{types};
103             }
104              
105             sub type_library {
106 56     56 1 111 my ($self, $value) = @_;
107 56 100       119 if ( defined $value ) {
108 35 50       74 if ( ref $value ) {
109 0         0 die qq{Str: invalid value $value for accessor type_library}
110             }
111 35         73 $self->{type_library} = $value;
112             }
113 56         105 return $self->{type_library};
114             }
115              
116             sub type_map {
117 45     45 1 90 my ( $self, $value ) = @_;
118 45 100       113 if ( defined $value ) {
119 35 50 50     126 if ( ( ref($value) || "" ) ne "HASH" ) {
120 0         0 die qq{HashRef: invalid value $value for accessor type_map};
121             }
122 35         80 $self->{type_map} = $value;
123             }
124 45         85 return $self->{type_map};
125             }
126              
127             sub hash_to_object {
128 7     7 1 642 my ( $self, $hash, %accessors ) = @_;
129 7 100 100     42 if ( ( ref($hash) || "" ) ne "HASH" ) {
130 2 50       6 $hash = defined $hash ? $hash : 'undef';
131 2         18 die
132             qq{HashRef: invalid value $hash for variable \$hash in method hash_to_object};
133             }
134 5         21 $self = $self->clean();
135 5         28 $self->default($hash);
136 5         9 for my $key ( keys %{$hash} ) {
  5         20  
137 30         101 $self->add_method(
138             {
139             name => $key,
140             %accessors
141             }
142             );
143             }
144 5         17 return $self->build;
145             }
146              
147             sub hash_to_nested_object {
148 14     14 1 43 my ( $self, $hash, %accessors ) = @_;
149 14 50 50     49 if ( ( ref($hash) || "" ) ne "HASH" ) {
150 0 0       0 $hash = defined $hash ? $hash : 'undef';
151 0         0 die
152             qq{HashRef: invalid value $hash for variable \$hash in method hash_to_object};
153             }
154 14         38 $self = $self->clean();
155 14         30 for my $key ( keys %{$hash} ) {
  14         44  
156 20         34 my $val = $hash->{$key};
157 20   100     67 my $ref = ref $val || "";
158 20 100       48 if ($ref eq 'HASH') {
    100          
159 8         24 $val = $self->hash_to_nested_object(
160             $val,
161             %accessors
162             );
163             } elsif ($ref eq 'ARRAY') {
164 4         21 $val = $self->array_to_nested_object(
165             $val,
166             %accessors
167             );
168             }
169             $self->add_method(
170             {
171 20         115 name => $key,
172             default => $val,
173             nested => 1,
174             %accessors
175             }
176             );
177             }
178 14         37 return $self->build;
179             }
180              
181             sub array_to_nested_object {
182 4     4 1 13 my ( $self, $array, %accessors ) = @_;
183 4 50 50     38 if ( ( ref($array) || "" ) ne "ARRAY" ) {
184 0 0       0 $array = defined $array ? $array : 'undef';
185 0         0 die
186             qq{ArrayRef: invalid value $array for variable \$array in method array_to_object};
187             }
188 4         12 for (my $i = 0; $i < scalar @{$array}; $i++) {
  14         47  
189 10         20 my $val = $array->[$i];
190 10   100     33 my $ref = ref $val || "";
191 10 100       30 if ($ref eq 'HASH') {
    50          
192 4         20 $val = $self->hash_to_nested_object(
193             $val,
194             %accessors
195             );
196             } elsif ($ref eq 'ARRAY') {
197 0         0 $val = $self->array_to_nested_object(
198             $val,
199             %accessors
200             );
201             }
202 10         27 $array->[$i] = $val;
203             }
204 4         12 return $array;
205             }
206              
207             sub add_new {
208 23     23 1 679 my ( $self, $new ) = @_;
209 23 100 100     94 if ( ( ref($new) || "" ) ne "HASH" ) {
210 2 50       8 $new = defined $new ? $new : 'undef';
211 2         17 die
212             qq{HashRef: invalid value $new for variable \$new in method add_new};
213             }
214              
215             return sprintf q|return bless { %s }, __PACKAGE__;|, join q|,|,
216 53         143 map { sprintf q|%s => %s|, $_, $self->stringify_struct( $new->{$_} ) }
217 21         49 keys %{$new};
  21         71  
218              
219             }
220              
221             sub add_methods {
222 2     2 1 653 my ( $self, $methods ) = @_;
223 2 50 100     20 if ( !defined($methods) || ( ref($methods) || "" ) ne "ARRAY" ) {
      33        
224 2 50       6 $methods = defined $methods ? $methods : 'undef';
225 2         18 die
226             qq{ArrayRef: invalid value $methods for variable \$methods in method add_methods};
227             }
228              
229 0         0 for my $method ( @{$methods} ) {
  0         0  
230 0         0 $self->add_method($method);
231             }
232              
233             }
234              
235             sub add_method {
236 54     54 1 794 my ( $self, $method ) = @_;
237 54 100 100     185 if ( ( ref($method) || "" ) ne "HASH" ) {
238 2 50       5 $method = defined $method ? $method : 'undef';
239 2         19 die
240             qq{HashRef: invalid value $method for variable \$method in method add_method};
241             }
242 52 50 33     237 if ( ( ! defined $method->{name} || ref($method->{name}) ) ) {
243 0 0       0 $method->{name} = defined $method->{name} ? $method->{name} : 'undef';
244 0         0 die
245             qq{Str: invalid value $method->{name} for variable \$method->{name} in method add_method};
246             }
247              
248 52         90 my $name = $method->{name};
249 52 100       103 if ( $method->{clearer} ) {
250 1         6 $self->meta->{ q|clear_| . $name }
251             = qq|return delete \$_[0]->{$name};|;
252             }
253 52 100       101 if ( $method->{predicate} ) {
254 1         15 $self->meta->{ q|has_| . $name }
255             = qq|return exists \$_[0]->{$name};|;
256             }
257 52 100       108 if ( $method->{get} ) {
258 1         4 $self->meta->{ q|get_| . $name }
259             = qq|return \$_[0]->{$name};|;
260             }
261 52 100       102 if ( $method->{set} ) {
262 12         25 my $set = q|my ($self, $val) = @_; |;
263             $method->{type} = $self->identify_type($method->{default})
264 12 100       39 if ($method->{autotype});
265 12 100       38 if ($method->{type}) {
266 8         27 $self->add_type($method->{type});
267 8         20 $set .= qq|$method->{type}\->(\$val); |;
268             }
269 12 100       32 my $merge = $method->{merge} ? '|| $first' : '';
270             $set .= qq|
271             if (defined \$self->{$name}) {
272             my \$recurse;
273             \$recurse = sub {
274             my (\$first, \$second) = \@_;
275             my \$fref = Scalar::Util::reftype(\$first) \|\| "";
276             my \$sref = Scalar::Util::reftype(\$second) \|\| "";
277             if (\$fref eq 'ARRAY' && \$sref eq 'ARRAY') {
278             for (my \$i = 0; \$i < scalar \@{ \$first }; \$i++) {
279             my (\$f, \$s) = (\$first->[0], \$second->[0]);
280             \$second->[\$i] = \$recurse->(\$first->[\$i], \$second->[\$i]);
281             }
282             } elsif (\$fref eq 'HASH' && \$sref eq 'HASH') {
283             my \@keys = (keys \%{ \$first }, keys \%{ \$second });
284             for my \$key ( \@keys ) {
285             \$second->{\$key} = \$recurse->(\$first->{\$key}, \$second->{\$key});
286             }
287             \$second = bless \$second, ref \$first;
288             }
289             return \$second${merge};
290             };
291             \$val = \$recurse->(\$self->{$name}, \$val);
292             }
293 12 100       44 | if ($method->{nested});
294 12         32 $set .= qq|
295             \$self->{$name} = \$val;
296             return \$self->{$name};
297             |;
298 12         29 $self->meta->{ q|set_| . $name } = $set;
299             }
300 52 100       114 if ( $method->{ref} ) {
301 1         4 $self->meta->{ q|ref_| . $name }
302             = qq|return ref \$_[0]->{$name};|;
303             }
304 52 100       107 if ( $method->{reftype} ) {
305 1         4 $self->meta->{ q|reftype_| . $name }
306             = qq|return Scalar::Util::reftype \$_[0]->{$name};|;
307             }
308 52 100       113 if ( exists $method->{default} ) {
309 22         58 $self->default->{ $name } = $method->{default};
310             }
311 52 50       117 unless ($method->{code}) {
312 52         143 $method->{code} = qq|return \$_[0]->{$name}|;
313             }
314 52         122 $self->meta->{ $name } = $method->{code};
315 52         187 return $self;
316             }
317              
318             sub build {
319 21     21 1 41 my ($self) = @_;
320              
321              
322 21         43 $self->meta->{new} = $self->add_new( $self->default );
323              
324 21         103 my $class = sprintf q|%s::%s|, $self->{object_name}, $UNIQUE++;
325 21         47 my @methods;
326 21         33 for my $method ( keys %{ $self->meta } ) {
  21         41  
327             push @methods, sprintf q|sub %s { %s }|, $method,
328 97         201 $self->meta->{$method};
329             }
330             my $c = sprintf(
331             q|
332             package %s;
333             use Scalar::Util qw//;
334             use %s qw/%s/;
335             %s
336             1;
337 21         67 |, $class, $self->type_library, join(" ", keys %{$self->types}), join( "\n", @methods) );
  21         55  
338 21 0   12   1869 eval $c;
  24 50   14   185  
  25 50   13   94  
  31 0   11   295  
  17 0   11   3164  
  17 0   8   502015  
  24 0   1   7519  
  21 0   2   265  
  22 0   3   51  
  14 50   2   160  
  39     2   127  
  8     2   69  
  8     1   552  
  5     5   32  
  5     5   18  
  4     4   64  
  4     5   26  
  6     5   19  
  5     4   348  
  1     3   49  
  1     10   2  
  1     10   6  
  1     0   4  
  1     0   2  
  1     1   5  
  1         4  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         10  
  1         8  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         3  
  1         5  
  1         57  
  1         2  
  1         6  
  1         3  
  1         4  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  4         9  
  4         18  
  4         13  
  4         21  
  0         0  
  0         0  
  0         0  
  0         0  
  1         2  
  1         3  
  1         4  
  1         2  
  3         9  
  1         5  
  4         16  
339 21         574 return $class->new;
340             }
341              
342             sub stringify_struct {
343 58     58 1 155 my ( $self, $struct ) = @_;
344 62 100       345 $struct = ref $struct ? Dumper $struct : "'$struct'";
345 57 50       5995 return 'undefined' unless defined $struct;
346 60         2048 $struct =~ s/\$VAR1 = //;
347 59         8171 $struct =~ s/\s*\n*\s*package Module\:\:Generate\;|use warnings\;|use strict\;//g;
348 56         766 $struct =~ s/{\s*\n*/{/;
349 58         181 $struct =~ s/;$//;
350 58         414 return $struct;
351             }
352              
353             sub add_type {
354 9     17 1 26 my ($self, $value) = @_;
355 10 100 33     44 if ( ! defined $value || ref $value ) {
356 2         12 die qq{Str: invalid value $value for method push_type};
357             }
358 9         30 $self->{types}->{$value}++;
359             }
360              
361             sub identify_type {
362 12     15 1 30 my ($self, $value) = @_;
363 12         37 my $type_map = $self->type_map;
364 11         34 my $ref = ref $value;
365             return $type_map->{default}
366 43 100       89 if (! defined $value);
367             return $type_map->{$ref} || $type_map->{REF}
368 43 100 66     141 if ($ref);
369 36 50       93 return $type_map->{NUM} if $value =~ m/\d+\.\d+/;
370 40 100       216 return $type_map->{INT} if $value =~ m/\d+/;
371 13 50       114 return $type_map->{STRING} if $value =~ m/\s+/;
372             }
373              
374              
375             1;
376              
377             __END__