File Coverage

blib/lib/Data/Object/Cast.pm
Criterion Covered Total %
statement 132 134 98.5
branch 91 120 75.8
condition 11 17 64.7
subroutine 25 25 100.0
pod 5 19 26.3
total 264 315 83.8


line stmt bran cond sub pod time code
1             package Data::Object::Cast;
2              
3 1     1   41807 use 5.014;
  1         5  
4              
5 1     1   7 use strict;
  1         1  
  1         23  
6 1     1   5 use warnings;
  1         3  
  1         27  
7              
8 1     1   619 use Data::Object::Space;
  1         11246  
  1         39  
9              
10 1         1986 use Scalar::Util qw(
11             blessed
12             looks_like_number
13             reftype
14 1     1   7 );
  1         2  
15              
16             our $To = 'Data::Object';
17              
18             our $VERSION = '0.01'; # VERSION
19              
20             # FUNCTIONS
21              
22             sub Deduce {
23 82     82 1 167265 my ($data) = @_;
24              
25 82 100       192 return TypeUndef($data) if not(defined($data));
26 79 100       233 return DeduceBlessed($data) if blessed($data);
27 38         72 return DeduceDefined($data);
28             }
29              
30             sub DeduceDefined {
31 38     38 0 66 my ($data) = @_;
32              
33 38 100       107 return DeduceReferences($data) if ref($data);
34 21 100       71 return DeduceNumberlike($data) if looks_like_number($data);
35 3         10 return DeduceStringLike($data);
36             }
37              
38             sub DeduceBlessed {
39 41     41 0 69 my ($data) = @_;
40              
41 41 100       162 return TypeRegexp($data) if $data->isa('Regexp');
42 38         78 return $data;
43             }
44              
45             sub DeduceReferences {
46 17     17 0 29 my ($data) = @_;
47              
48 17 100       54 return TypeArray($data) if 'ARRAY' eq ref $data;
49 12 100       41 return TypeCode($data) if 'CODE' eq ref $data;
50 9 100       31 return TypeHash($data) if 'HASH' eq ref $data;
51 4         14 return TypeScalar($data); # glob, etc
52             }
53              
54             sub DeduceNumberlike {
55 18     18 0 30 my ($data) = @_;
56              
57 18 100       79 return TypeFloat($data) if $data =~ /\./;
58 15         31 return TypeNumber($data);
59             }
60              
61             sub DeduceStringLike {
62 3     3 0 10 my ($data) = @_;
63              
64 3         8 return TypeString($data);
65             }
66              
67             sub DeduceDeep {
68 4     4 1 29081 my @data = map Deduce($_), @_;
69              
70 4         42 for my $data (@data) {
71 4         10 my $type = TypeName($data);
72              
73 4 100 66     24 if ($type and $type eq 'HASH') {
74 2         10 for my $i (keys %$data) {
75 4         20 my $val = $data->{$i};
76 4 50       13 $data->{$i} = ref($val) ? DeduceDeep($val) : Deduce($val);
77             }
78             }
79 4 100 66     30 if ($type and $type eq 'ARRAY') {
80 2         7 for (my $i = 0; $i < @$data; $i++) {
81 8         49 my $val = $data->[$i];
82 8 50       19 $data->[$i] = ref($val) ? DeduceDeep($val) : Deduce($val);
83             }
84             }
85             }
86              
87 4 100       42 return wantarray ? (@data) : $data[0];
88             }
89              
90             sub Detract {
91 17     17 1 92 my ($data) = (Deduce($_[0]));
92 17         35 my $type = TypeName($data);
93              
94 18 50       39 INSPECT:
95             return $data unless $type;
96              
97 18 100       48 return [@$data] if $type eq 'ARRAY';
98 16 100       60 return {%$data} if $type eq 'HASH';
99 14 50       30 return $$data if $type eq 'BOOLEAN';
100 14 100       34 return $$data if $type eq 'REGEXP';
101 13 100       31 return $$data if $type eq 'FLOAT';
102 12 100       42 return $$data if $type eq 'NUMBER';
103 5 100       18 return $$data if $type eq 'STRING';
104 4 100       18 return undef if $type eq 'UNDEF';
105              
106 3 100 66     17 if ($type eq 'ANY' or $type eq 'SCALAR') {
107 2   50     10 $type = reftype($data) // '';
108              
109 2 50       6 return [@$data] if $type eq 'ARRAY';
110 2 50       5 return {%$data} if $type eq 'HASH';
111 2 50       4 return $$data if $type eq 'BOOLEAN';
112 2 50       6 return $$data if $type eq 'FLOAT';
113 2 50       6 return $$data if $type eq 'NUMBER';
114 2 50       5 return $$data if $type eq 'REGEXP';
115 2 100       15 return $data if $type eq 'SCALAR';
116 1 50       4 return $$data if $type eq 'STRING';
117 1 50       3 return undef if $type eq 'UNDEF';
118              
119 1 50       5 if ($type eq 'REF') {
120 1 50       3 $type = TypeName($data = $$data) and goto INSPECT;
121             }
122             }
123              
124 1 50       5 if ($type eq 'CODE') {
125 1     1   12 return sub { goto $data };
  1         1749  
126             }
127              
128 0         0 return undef;
129             }
130              
131             sub DetractDeep {
132 8     8 1 19 my @data = map Detract($_), @_;
133              
134 8         16 for my $data (@data) {
135 8 100 66     30 if ($data and 'HASH' eq ref $data) {
136 1         5 for my $i (keys %$data) {
137 2         5 my $val = $data->{$i};
138 2 50       10 $data->{$i} = ref($val) ? DetractDeep($val) : Detract($val);
139             }
140             }
141 8 100 66     27 if ($data and 'ARRAY' eq ref $data) {
142 1         6 for (my $i = 0; $i < @$data; $i++) {
143 4         5 my $val = $data->[$i];
144 4 50       16 $data->[$i] = ref($val) ? DetractDeep($val) : Detract($val);
145             }
146             }
147             }
148              
149 8 50       44 return wantarray ? (@data) : $data[0];
150             }
151              
152             sub TypeName {
153 31     31 1 68584 my ($data) = (Deduce($_[0]));
154              
155 31 100       210 return "ARRAY" if $data->isa("${To}::Array");
156 26 50       103 return "BOOLEAN" if $data->isa("${To}::Boolean");
157 26 100       102 return "HASH" if $data->isa("${To}::Hash");
158 21 100       74 return "CODE" if $data->isa("${To}::Code");
159 19 100       70 return "FLOAT" if $data->isa("${To}::Float");
160 17 100       68 return "NUMBER" if $data->isa("${To}::Number");
161 9 100       42 return "STRING" if $data->isa("${To}::String");
162 7 100       45 return "SCALAR" if $data->isa("${To}::Scalar");
163 4 100       25 return "REGEXP" if $data->isa("${To}::Regexp");
164 2 50       21 return "UNDEF" if $data->isa("${To}::Undef");
165              
166 0         0 return undef;
167             }
168              
169             sub TypeArray {
170 5     5 0 14 my $class = "${To}::Array";
171 5         24 my $space = Data::Object::Space->new($class);
172 5         55 my $point = $space->load->can('new');
173              
174 5 50       245 unshift @_, $class and goto $point;
175             }
176              
177             sub TypeCode {
178 3     3 0 10 my $class = "${To}::Code";
179 3         13 my $space = Data::Object::Space->new($class);
180 3         34 my $point = $space->load->can('new');
181              
182 3 50       155 unshift @_, $class and goto $point;
183             }
184              
185             sub TypeFloat {
186 3     3 0 9 my $class = "${To}::Float";
187 3         13 my $space = Data::Object::Space->new($class);
188 3         31 my $point = $space->load->can('new');
189              
190 3 50       138 unshift @_, $class and goto $point;
191             }
192              
193             sub TypeHash {
194 5     5 0 14 my $class = "${To}::Hash";
195 5         28 my $space = Data::Object::Space->new($class);
196 5         53 my $point = $space->load->can('new');
197              
198 5 50       214 unshift @_, $class and goto $point;
199             }
200              
201             sub TypeNumber {
202 15     15 0 34 my $class = "${To}::Number";
203 15         44 my $space = Data::Object::Space->new($class);
204 15         131 my $point = $space->load->can('new');
205              
206 15 50       476 unshift @_, $class and goto $point;
207             }
208              
209             sub TypeRegexp {
210 3     3 0 10 my $class = "${To}::Regexp";
211 3         13 my $space = Data::Object::Space->new($class);
212 3         34 my $point = $space->load->can('new');
213              
214 3 50       170 unshift @_, $class and goto $point;
215             }
216              
217             sub TypeScalar {
218 4     4 0 14 my $class = "${To}::Scalar";
219 4         14 my $space = Data::Object::Space->new($class);
220 4         40 my $point = $space->load->can('new');
221              
222 4 50       168 unshift @_, $class and goto $point;
223             }
224              
225             sub TypeString {
226 3     3 0 9 my $class = "${To}::String";
227 3         11 my $space = Data::Object::Space->new($class);
228 3         32 my $point = $space->load->can('new');
229              
230 3 50       134 unshift @_, $class and goto $point;
231             }
232              
233             sub TypeUndef {
234 3     3 0 11 my $class = "${To}::Undef";
235 3         13 my $space = Data::Object::Space->new($class);
236 3         33 my $point = $space->load->can('new');
237              
238 3 50       131 unshift @_, $class and goto $point;
239             }
240              
241             1;
242              
243             =encoding utf8
244              
245             =head1 NAME
246              
247             Data::Object::Cast
248              
249             =cut
250              
251             =head1 ABSTRACT
252              
253             Data Type Casting for Perl 5
254              
255             =cut
256              
257             =head1 SYNOPSIS
258              
259             package main;
260              
261             use Data::Object::Cast;
262              
263             local $Data::Object::Cast::To = 'Test::Object';
264              
265             # Data::Object::Cast::Deduce([1..4]); # Test::Object::Array
266              
267             =cut
268              
269             =head1 DESCRIPTION
270              
271             This package provides functions for casting native data types to objects and
272             the reverse.
273              
274             =cut
275              
276             =head1 LIBRARIES
277              
278             This package uses type constraints from:
279              
280             L<Types::Standard>
281              
282             =cut
283              
284             =head1 FUNCTIONS
285              
286             This package implements the following functions:
287              
288             =cut
289              
290             =head2 deduce
291              
292             Deduce(Any $value) : Object
293              
294             The Deduce function returns the argument as a data type object.
295              
296             =over 4
297              
298             =item Deduce example #1
299              
300             # given: synopsis
301              
302             Data::Object::Cast::Deduce([1..4])
303              
304             # $array
305              
306             =back
307              
308             =over 4
309              
310             =item Deduce example #2
311              
312             # given: synopsis
313              
314             Data::Object::Cast::Deduce(sub { shift })
315              
316             # $code
317              
318             =back
319              
320             =over 4
321              
322             =item Deduce example #3
323              
324             # given: synopsis
325              
326             Data::Object::Cast::Deduce(1.23)
327              
328             # $float
329              
330             =back
331              
332             =over 4
333              
334             =item Deduce example #4
335              
336             # given: synopsis
337              
338             Data::Object::Cast::Deduce({1..4})
339              
340             # $hash
341              
342             =back
343              
344             =over 4
345              
346             =item Deduce example #5
347              
348             # given: synopsis
349              
350             Data::Object::Cast::Deduce(123)
351              
352             # $number
353              
354             =back
355              
356             =over 4
357              
358             =item Deduce example #6
359              
360             # given: synopsis
361              
362             Data::Object::Cast::Deduce(qr/.*/)
363              
364             # $regexp
365              
366             =back
367              
368             =over 4
369              
370             =item Deduce example #7
371              
372             # given: synopsis
373              
374             Data::Object::Cast::Deduce(\'abc')
375              
376             # $scalar
377              
378             =back
379              
380             =over 4
381              
382             =item Deduce example #8
383              
384             # given: synopsis
385              
386             Data::Object::Cast::Deduce('abc')
387              
388             # $string
389              
390             =back
391              
392             =over 4
393              
394             =item Deduce example #9
395              
396             # given: synopsis
397              
398             Data::Object::Cast::Deduce(undef)
399              
400             # $undef
401              
402             =back
403              
404             =cut
405              
406             =head2 deducedeep
407              
408             DeduceDeep(Any @args) : (Object)
409              
410             The DeduceDeep function returns any arguments as data type objects, including
411             nested data.
412              
413             =over 4
414              
415             =item DeduceDeep example #1
416              
417             # given: synopsis
418              
419             Data::Object::Cast::DeduceDeep([1..4])
420              
421             # $array <$number>
422              
423             =back
424              
425             =over 4
426              
427             =item DeduceDeep example #2
428              
429             # given: synopsis
430              
431             Data::Object::Cast::DeduceDeep({1..4})
432              
433             # $hash <$number>
434              
435             =back
436              
437             =cut
438              
439             =head2 detract
440              
441             Detract(Any $value) : Any
442              
443             The Detract function returns the argument as native Perl data type value.
444              
445             =over 4
446              
447             =item Detract example #1
448              
449             # given: synopsis
450              
451             Data::Object::Cast::Detract(
452             Data::Object::Cast::Deduce(
453             [1..4]
454             )
455             )
456              
457             # $arrayref
458              
459             =back
460              
461             =over 4
462              
463             =item Detract example #2
464              
465             # given: synopsis
466              
467             Data::Object::Cast::Detract(
468             Data::Object::Cast::Deduce(
469             sub { shift }
470             )
471             )
472              
473             # $coderef
474              
475             =back
476              
477             =over 4
478              
479             =item Detract example #3
480              
481             # given: synopsis
482              
483             Data::Object::Cast::Detract(
484             Data::Object::Cast::Deduce(
485             1.23
486             )
487             )
488              
489             # $number
490              
491             =back
492              
493             =over 4
494              
495             =item Detract example #4
496              
497             # given: synopsis
498              
499             Data::Object::Cast::Detract(
500             Data::Object::Cast::Deduce(
501             {1..4}
502             )
503             )
504              
505             # $hashref
506              
507             =back
508              
509             =over 4
510              
511             =item Detract example #5
512              
513             # given: synopsis
514              
515             Data::Object::Cast::Detract(
516             Data::Object::Cast::Deduce(
517             123
518             )
519             )
520              
521             # $number
522              
523             =back
524              
525             =over 4
526              
527             =item Detract example #6
528              
529             # given: synopsis
530              
531             Data::Object::Cast::Detract(
532             Data::Object::Cast::Deduce(
533             qr/.*/
534             )
535             )
536              
537             # $regexp
538              
539             =back
540              
541             =over 4
542              
543             =item Detract example #7
544              
545             # given: synopsis
546              
547             Data::Object::Cast::Detract(
548             Data::Object::Cast::Deduce(
549             \'abc'
550             )
551             )
552              
553             # $scalarref
554              
555             =back
556              
557             =over 4
558              
559             =item Detract example #8
560              
561             # given: synopsis
562              
563             Data::Object::Cast::Detract(
564             Data::Object::Cast::Deduce(
565             'abc'
566             )
567             )
568              
569             # $string
570              
571             =back
572              
573             =over 4
574              
575             =item Detract example #9
576              
577             # given: synopsis
578              
579             Data::Object::Cast::Detract(
580             Data::Object::Cast::Deduce(
581             undef
582             )
583             )
584              
585             # $undef
586              
587             =back
588              
589             =cut
590              
591             =head2 detractdeep
592              
593             DetractDeep(Any @args) : (Any)
594              
595             The DetractDeep function returns any arguments as native Perl data type values,
596             including nested data.
597              
598             =over 4
599              
600             =item DetractDeep example #1
601              
602             # given: synopsis
603              
604             Data::Object::Cast::DetractDeep(
605             Data::Object::Cast::DeduceDeep(
606             [1..4]
607             )
608             )
609              
610             =back
611              
612             =over 4
613              
614             =item DetractDeep example #2
615              
616             # given: synopsis
617              
618             Data::Object::Cast::DetractDeep(
619             Data::Object::Cast::DeduceDeep(
620             {1..4}
621             )
622             )
623              
624             =back
625              
626             =cut
627              
628             =head2 typename
629              
630             TypeName(Any $value) : Maybe[Str]
631              
632             The TypeName function returns the name of the value's data type.
633              
634             =over 4
635              
636             =item TypeName example #1
637              
638             # given: synopsis
639              
640             Data::Object::Cast::TypeName([1..4])
641              
642             # 'ARRAY'
643              
644             =back
645              
646             =over 4
647              
648             =item TypeName example #2
649              
650             # given: synopsis
651              
652             Data::Object::Cast::TypeName(sub { shift })
653              
654             # 'CODE'
655              
656             =back
657              
658             =over 4
659              
660             =item TypeName example #3
661              
662             # given: synopsis
663              
664             Data::Object::Cast::TypeName(1.23)
665              
666             # 'FLOAT'
667              
668             =back
669              
670             =over 4
671              
672             =item TypeName example #4
673              
674             # given: synopsis
675              
676             Data::Object::Cast::TypeName({1..4})
677              
678             # 'HASH'
679              
680             =back
681              
682             =over 4
683              
684             =item TypeName example #5
685              
686             # given: synopsis
687              
688             Data::Object::Cast::TypeName(123)
689              
690             # 'NUMBER'
691              
692             =back
693              
694             =over 4
695              
696             =item TypeName example #6
697              
698             # given: synopsis
699              
700             Data::Object::Cast::TypeName(qr/.*/)
701              
702             # 'REGEXP'
703              
704             =back
705              
706             =over 4
707              
708             =item TypeName example #7
709              
710             # given: synopsis
711              
712             Data::Object::Cast::TypeName(\'abc')
713              
714             # 'STRING'
715              
716             =back
717              
718             =over 4
719              
720             =item TypeName example #8
721              
722             # given: synopsis
723              
724             Data::Object::Cast::TypeName('abc')
725              
726             # 'STRING'
727              
728             =back
729              
730             =over 4
731              
732             =item TypeName example #9
733              
734             # given: synopsis
735              
736             Data::Object::Cast::TypeName(undef)
737              
738             # 'UNDEF'
739              
740             =back
741              
742             =cut
743              
744             =head1 AUTHOR
745              
746             Al Newkirk, C<awncorp@cpan.org>
747              
748             =head1 LICENSE
749              
750             Copyright (C) 2011-2019, Al Newkirk, et al.
751              
752             This is free software; you can redistribute it and/or modify it under the terms
753             of the The Apache License, Version 2.0, as elucidated in the L<"license
754             file"|https://github.com/iamalnewkirk/foobar/blob/master/LICENSE>.
755              
756             =head1 PROJECT
757              
758             L<Wiki|https://github.com/iamalnewkirk/foobar/wiki>
759              
760             L<Project|https://github.com/iamalnewkirk/foobar>
761              
762             L<Initiatives|https://github.com/iamalnewkirk/foobar/projects>
763              
764             L<Milestones|https://github.com/iamalnewkirk/foobar/milestones>
765              
766             L<Contributing|https://github.com/iamalnewkirk/foobar/blob/master/CONTRIBUTE.md>
767              
768             L<Issues|https://github.com/iamalnewkirk/foobar/issues>
769              
770             =cut