File Coverage

blib/lib/JSV/Util/Type.pm
Criterion Covered Total %
statement 47 49 95.9
branch 23 26 88.4
condition n/a
subroutine 10 10 100.0
pod 0 3 0.0
total 80 88 90.9


line stmt bran cond sub pod time code
1             package JSV::Util::Type;
2              
3 47     47   147 use strict;
  47         42  
  47         1027  
4 47     47   121 use warnings;
  47         42  
  47         900  
5 47     47   179 use Exporter qw(import);
  47         42  
  47         936  
6              
7 47     47   148 use B;
  47         63  
  47         1294  
8 47     47   146 use Carp;
  47         116  
  47         1877  
9 47     47   142 use Scalar::Util qw(blessed looks_like_number);
  47         41  
  47         1638  
10 47     47   139 use JSON;
  47         48  
  47         195  
11              
12             our @EXPORT_OK = (qw/
13             detect_instance_type
14             detect_instance_type_loose
15             escape_json_pointer
16             /);
17              
18             our %REF_TYPE_MAP = (
19             HASH => "object",
20             ARRAY => "array",
21             );
22              
23             sub detect_instance_type {
24 1761     1761 0 4073 my $instance = shift;
25              
26 1761         1197 my $ref_type;
27              
28 1761 100       3171 if (!defined $instance) {
    100          
29 247         399 return "null";
30             }
31             elsif ($ref_type = ref $instance) {
32 626 100       1418 if (!blessed $instance) {
    50          
33 576         1179 return $REF_TYPE_MAP{$ref_type};
34             }
35             elsif (JSON::is_bool($instance)) {
36 50         251 return "boolean";
37             }
38             else {
39 0         0 croak(sprintf("Unknown reference type (ref_type: %s)", $ref_type));
40             }
41             }
42             else {
43 888         3621 my $flags = B::svref_2object(\$instance)->FLAGS;
44              
45 888 100       2061 if (( $flags & B::SVp_IOK ) == B::SVp_IOK) {
    100          
    50          
46 349         587 return "integer";
47             }
48             elsif (( $flags & B::SVp_NOK ) == B::SVp_NOK ) {
49 60         138 return "number";
50             }
51             elsif (( $flags & B::SVp_POK ) == B::SVp_POK) {
52 479         833 return "string";
53             }
54             else {
55 0         0 croak(sprintf("Unknown type (flags: %s)", $flags));
56             }
57             }
58             }
59              
60             sub detect_instance_type_loose {
61 638     638 0 2461 my ($instance) = @_;
62              
63 638         794 my $type_strict = detect_instance_type($instance);
64              
65 638 100       1586 if ( $type_strict eq "integer" ) {
    100          
    100          
66 152         288 return "integer_or_string";
67             }
68             elsif ( $type_strict eq "number" ) {
69 20         56 return "number_or_string";
70             }
71             elsif ( $type_strict eq "string" ) {
72 226 100       656 if ( looks_like_number($instance) ) {
73 40 100       228 return "integer_or_string" if $instance =~ m/^(?:[+-])?[1-9]?\d+$/;
74 19         47 return "number_or_string";
75             }
76             }
77 426         881 return $type_strict;
78             }
79              
80             sub escape_json_pointer {
81 773     773 0 539 my $property = shift;
82 773 50       996 return unless defined $property;
83              
84             # according to http://tools.ietf.org/html/rfc6901#section-4
85 773         730 $property =~ s!~!~0!g; # replace tilde first
86 773         542 $property =~ s!/!~1!g;
87              
88 773         1496 return $property;
89             }
90             1;