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   231 use strict;
  47         86  
  47         1197  
4 47     47   225 use warnings;
  47         77  
  47         1248  
5 47     47   321 use Exporter qw(import);
  47         75  
  47         1254  
6              
7 47     47   268 use B;
  47         103  
  47         1866  
8 47     47   247 use Carp;
  47         96  
  47         2915  
9 47     47   251 use Scalar::Util qw(blessed looks_like_number);
  47         84  
  47         2391  
10 47     47   231 use JSON;
  47         85  
  47         387  
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 7947 my $instance = shift;
25              
26 1761         2387 my $ref_type;
27              
28 1761 100       5768 if (!defined $instance) {
    100          
29 247         741 return "null";
30             }
31             elsif ($ref_type = ref $instance) {
32 626 100       2440 if (!blessed $instance) {
    50          
33 576         2181 return $REF_TYPE_MAP{$ref_type};
34             }
35             elsif (JSON::is_bool($instance)) {
36 50         460 return "boolean";
37             }
38             else {
39 0         0 croak(sprintf("Unknown reference type (ref_type: %s)", $ref_type));
40             }
41             }
42             else {
43 888         5920 my $flags = B::svref_2object(\$instance)->FLAGS;
44              
45 888 100       3763 if (( $flags & B::SVp_IOK ) == B::SVp_IOK) {
    100          
    50          
46 349         1285 return "integer";
47             }
48             elsif (( $flags & B::SVp_NOK ) == B::SVp_NOK ) {
49 60         241 return "number";
50             }
51             elsif (( $flags & B::SVp_POK ) == B::SVp_POK) {
52 479         1629 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 4379 my ($instance) = @_;
62              
63 638         1311 my $type_strict = detect_instance_type($instance);
64              
65 638 100       2531 if ( $type_strict eq "integer" ) {
    100          
    100          
66 152         569 return "integer_or_string";
67             }
68             elsif ( $type_strict eq "number" ) {
69 20         89 return "number_or_string";
70             }
71             elsif ( $type_strict eq "string" ) {
72 226 100       990 if ( looks_like_number($instance) ) {
73 40 100       321 return "integer_or_string" if $instance =~ m/^(?:[+-])?[1-9]?\d+$/;
74 19         74 return "number_or_string";
75             }
76             }
77 426         1701 return $type_strict;
78             }
79              
80             sub escape_json_pointer {
81 773     773 0 1133 my $property = shift;
82 773 50       1674 return unless defined $property;
83              
84             # according to http://tools.ietf.org/html/rfc6901#section-4
85 773         1391 $property =~ s!~!~0!g; # replace tilde first
86 773         1001 $property =~ s!/!~1!g;
87              
88 773         2888 return $property;
89             }
90             1;