File Coverage

blib/lib/JSON/TypeEncoder.pm
Criterion Covered Total %
statement 70 70 100.0
branch 26 28 92.8
condition n/a
subroutine 14 14 100.0
pod 0 2 0.0
total 110 114 96.4


line stmt bran cond sub pod time code
1             package JSON::TypeEncoder;
2 2     2   66095 use 5.012002;
  2         14  
3 2     2   10 use strict;
  2         4  
  2         37  
4 2     2   8 use warnings;
  2         4  
  2         58  
5              
6 2     2   1139 use Types::Standard -types;
  2         147800  
  2         19  
7              
8             our $VERSION = "0.01";
9              
10             sub new {
11 48     48 0 88038 my $class = shift;
12 48         134 bless { }, $class;
13             }
14              
15             sub encoder {
16 48     48 0 176 my ($self, $type) = @_;
17 48         104 my $src = sprintf('sub {
18             my $obj = shift;
19             return %s
20             }', $self->_json_src('$obj', $type));
21              
22 48         4568 my $code = eval $src; ## no critic
23 48 50       151 die "error string eval: $@, src: $src" if $@;
24 48         128 return $code;
25             }
26              
27             sub _json_src {
28 102     102   220 my ($self, $obj_src, $type) = @_;
29              
30 102         125 my $maybe;
31 102 100       228 if (_is_subtype($type, Maybe)) {
32 17         123 $type = $type->parameters->[0];
33 17         90 $maybe = !!1;
34             }
35              
36 102 50       234 my $src = _is_subtype($type, Dict) ? $self->_json_src_dict($obj_src, $type)
    100          
    100          
    100          
    100          
    100          
37             : _is_subtype($type, Tuple) ? $self->_json_src_tuple($obj_src, $type)
38             : _is_subtype($type, ArrayRef) ? $self->_json_src_arrayref($obj_src, $type)
39             : _is_subtype($type, Bool) ? $self->_json_src_bool($obj_src)
40             : _is_subtype($type, Num) ? $self->_json_src_num($obj_src)
41             : _is_subtype($type, Str) ? $self->_json_src_str($obj_src)
42             : die "cannot parse type: $type";
43              
44 102 100       246 if ($maybe) {
45 17         47 $src = qq!defined($obj_src) ? $src : 'null'!
46             }
47              
48 102         248 return $src;
49             }
50              
51             sub _json_src_dict {
52 26     26   221 my ($self, $obj_src, $type) = @_;
53 26         43 my @src;
54 26         38 my %types = @{$type->parameters};
  26         50  
55 26         167 my @keys = sort keys %types;
56 26         78 for (my $i = 0; $i < @keys; $i++) {
57 29         48 my $key = $keys[$i];
58 29         44 my $stype = $types{$key};
59 29         60 my $sobj_src = "${obj_src}->{$key}";
60              
61 29         42 my $optional;
62 29 100       73 if (_is_subtype($stype, Optional)) {
63 6         45 $stype = $stype->parameters->[0];
64 6         22 $optional = !!1;
65             }
66              
67 29         68 my $value_src = $self->_json_src($sobj_src, $stype);
68 29 100       61 my $comma = $i == 0 ? '' : ',';
69 29         68 my $src = qq!$comma"$key":' . ($value_src) . '!;
70              
71 29 100       58 if ($optional) {
72 6         16 $src = qq!' . (exists($sobj_src) ? '$src' : '') . '!
73             }
74              
75 29         93 push @src => $src;
76             }
77              
78 26         152 sprintf(q!'{%s}'!, join "", @src);
79             }
80              
81             sub _json_src_tuple {
82 7     7   58 my ($self, $obj_src, $type) = @_;
83 7         12 my @src;
84 7         10 my @types = @{$type->parameters};
  7         15  
85 7         42 for my $i (0 .. $#types) {
86 15         47 my $src = $self->_json_src("${obj_src}->[$i]", $types[$i]);
87 15         36 $src = qq!' . ($src) . '!;
88 15         34 push @src => $src;
89             }
90 7         39 sprintf(q!'[%s]'!, join ",", @src);
91             }
92              
93             sub _json_src_arrayref {
94 10     10   86 my ($self, $obj_src, $type) = @_;
95 10         14 my @src;
96 10         22 my $stype = $type->parameters->[0];
97 10         43 my $src = $self->_json_src('$_', $stype);
98 10         45 sprintf(q!'[' . (do {my $src; for (@{%s}) { $src .= (%s) . ',' }; substr($src,0,-1) }) . ']'!, $obj_src, $src);
99             }
100              
101             sub _json_src_str {
102 20     20   161 my ($self, $value_src) = @_;
103 20         46 qq!'"' . $value_src . '"'!
104             }
105              
106             sub _json_src_num {
107 23     23   176 my ($self, $value_src) = @_;
108 23         58 qq!$value_src+0!
109             }
110              
111             sub _json_src_bool {
112 16     16   133 my ($self, $value_src) = @_;
113 16         40 qq[$value_src ? 'true' : 'false']
114             }
115              
116             sub _is_subtype {
117 2745     2745   18293 my ($type, $other) = @_;
118 2745 100       6874 return unless $type;
119 2370 100       11856 $type->name eq $other->name || _is_subtype($type->parent, $other)
120             }
121              
122             1;
123             __END__