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 44     44   189 use strict;
  44         63  
  44         984  
4 44     44   184 use warnings;
  44         71  
  44         1022  
5 44     44   250 use Exporter qw(import);
  44         67  
  44         1072  
6              
7 44     44   235 use B;
  44         80  
  44         1574  
8 44     44   201 use Carp;
  44         82  
  44         2292  
9 44     44   192 use Scalar::Util qw(blessed looks_like_number);
  44         67  
  44         1982  
10 44     44   198 use JSON;
  44         106  
  44         249  
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 1721     1721 0 7204 my $instance = shift;
25              
26 1721         2115 my $ref_type;
27              
28 1721 100       4735 if (!defined $instance) {
    100          
29 247         668 return "null";
30             }
31             elsif ($ref_type = ref $instance) {
32 624 100       2270 if (!blessed $instance) {
    50          
33 574         1918 return $REF_TYPE_MAP{$ref_type};
34             }
35             elsif (JSON::is_bool($instance)) {
36 50         449 return "boolean";
37             }
38             else {
39 0         0 croak(sprintf("Unknown reference type (ref_type: %s)", $ref_type));
40             }
41             }
42             else {
43 850         9380 my $flags = B::svref_2object(\$instance)->FLAGS;
44              
45 850 100       3208 if (( $flags & B::SVp_IOK ) == B::SVp_IOK) {
    100          
    50          
46 349         1031 return "integer";
47             }
48             elsif (( $flags & B::SVp_NOK ) == B::SVp_NOK ) {
49 60         263 return "number";
50             }
51             elsif (( $flags & B::SVp_POK ) == B::SVp_POK) {
52 441         1253 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 619     619 0 3565 my ($instance) = @_;
62              
63 619         1178 my $type_strict = detect_instance_type($instance);
64              
65 619 100       2446 if ( $type_strict eq "integer" ) {
    100          
    100          
66 152         472 return "integer_or_string";
67             }
68             elsif ( $type_strict eq "number" ) {
69 20         77 return "number_or_string";
70             }
71             elsif ( $type_strict eq "string" ) {
72 207 100       1071 if ( looks_like_number($instance) ) {
73 38 100       226 return "integer_or_string" if $instance =~ m/^(?:[+-])?[1-9]?\d+$/;
74 18         61 return "number_or_string";
75             }
76             }
77 409         1498 return $type_strict;
78             }
79              
80             sub escape_json_pointer {
81 773     773 0 1017 my $property = shift;
82 773 50       1463 return unless defined $property;
83              
84             # according to http://tools.ietf.org/html/rfc6901#section-4
85 773         1171 $property =~ s!~!~0!g; # replace tilde first
86 773         901 $property =~ s!/!~1!g;
87              
88 773         2533 return $property;
89             }
90             1;