File Coverage

blib/lib/Venus/Json.pm
Criterion Covered Total %
statement 82 97 84.5
branch 18 24 75.0
condition 2 6 33.3
subroutine 18 23 78.2
pod 3 12 25.0
total 123 162 75.9


line stmt bran cond sub pod time code
1             package Venus::Json;
2              
3 2     2   1194 use 5.018;
  2         9  
4              
5 2     2   22 use strict;
  2         6  
  2         42  
6 2     2   10 use warnings;
  2         13  
  2         74  
7              
8             use overload (
9 2         18 '""' => 'explain',
10             '~~' => 'explain',
11             fallback => 1,
12 2     2   20 );
  2         187  
13              
14 2     2   213 use Venus::Class 'attr', 'base', 'with';
  2         13  
  2         18  
15              
16             base 'Venus::Kind::Utility';
17              
18             with 'Venus::Role::Valuable';
19             with 'Venus::Role::Buildable';
20             with 'Venus::Role::Accessible';
21             with 'Venus::Role::Explainable';
22              
23             # ATTRIBUTES
24              
25             attr 'decoder';
26             attr 'encoder';
27              
28             # BUILDERS
29              
30             sub build_arg {
31 4     4 0 9 my ($self, $data) = @_;
32              
33             return {
34 4         14 value => $data
35             };
36             }
37              
38             sub build_args {
39 8     8 0 18 my ($self, $data) = @_;
40              
41 8 50 33     61 if (keys %$data == 1 && exists $data->{value}) {
42 8         31 return $data;
43             }
44             return {
45 0         0 value => $data
46             };
47             }
48              
49             sub build_nil {
50 0     0 0 0 my ($self, $data) = @_;
51              
52             return {
53 0         0 value => $data
54             };
55             }
56              
57             sub build_self {
58 8     8 0 26 my ($self, $data) = @_;
59              
60 8         26 return $self->config;
61             }
62              
63             # METHODS
64              
65             sub config {
66 8     8 0 22 my ($self, $package) = @_;
67              
68 8 50 33     30 $package ||= $self->package
69             or $self->error({throw => 'error_on_config'});
70              
71 8         62 $package = $package->new
72             ->canonical
73             ->allow_nonref
74             ->allow_unknown
75             ->allow_blessed
76             ->convert_blessed
77             ->pretty;
78              
79 8 50       1689 if ($package->can('escape_slash')) {
80 8         116 $package->escape_slash;
81             }
82              
83             # Cpanel::JSON::XS
84 8 50       155 if ($package->isa('Cpanel::JSON::XS')) {
85             $self->decoder(sub {
86 0     0   0 my ($text) = @_;
87 0         0 $package->decode($text);
88 0         0 });
89             $self->encoder(sub {
90 0     0   0 my ($data) = @_;
91 0         0 $package->encode($data);
92 0         0 });
93             }
94              
95             # JSON::XS
96 8 50       54 if ($package->isa('JSON::XS')) {
97             $self->decoder(sub {
98 0     0   0 my ($text) = @_;
99 0         0 $package->decode($text);
100 0         0 });
101             $self->encoder(sub {
102 0     0   0 my ($data) = @_;
103 0         0 $package->encode($data);
104 0         0 });
105             }
106              
107             # JSON::PP
108 8 50       32 if ($package->isa('JSON::PP')) {
109             $self->decoder(sub {
110 1     1   5 my ($text) = @_;
111 1         5 $package->decode($text);
112 8         54 });
113             $self->encoder(sub {
114 8     8   19 my ($data) = @_;
115 8         29 $package->encode($data);
116 8         48 });
117             }
118              
119 8         19 return $self;
120             }
121              
122             sub decode {
123 1     1 1 4 my ($self, $data) = @_;
124              
125             # double-traversing the data structure due to lack of serialization hooks
126 1         4 return $self->set(FROM_BOOL($self->decoder->($data)));
127             }
128              
129             sub encode {
130 8     8 1 23 my ($self) = @_;
131              
132             # double-traversing the data structure due to lack of serialization hooks
133 8         30 return $self->encoder->(TO_BOOL($self->get));
134             }
135              
136             sub explain {
137 3     3 0 385 my ($self) = @_;
138              
139 3         9 return $self->encode;
140             }
141              
142             sub package {
143 13     13 0 78 my ($self) = @_;
144              
145 13         20 state $engine;
146              
147 13 100       54 return $engine if defined $engine;
148              
149 2         9 my %packages = (
150             'JSON::XS' => '3.0',
151             'JSON::PP' => '2.27105',
152             'Cpanel::JSON::XS' => '4.09',
153             );
154 2         17 for my $package (
155             grep defined,
156             $ENV{VENUS_JSON_PACKAGE},
157             qw(Cpanel::JSON::XS JSON::XS JSON::PP)
158             )
159             {
160 6         20 my $criteria = "require $package; $package->VERSION($packages{$package})";
161 6 100       9 if (do {local $@; eval "$criteria"; $@}) {
  6         36  
  6         377  
  6         43  
162 4         13 next;
163             }
164             else {
165 2         6 $engine = $package;
166 2         14 last;
167             }
168             }
169              
170 2         9 return $engine;
171             }
172              
173             sub FROM_BOOL {
174 5     5 0 585 my ($value) = @_;
175              
176 5         19 require Venus::Boolean;
177              
178 5 100       17 if (ref($value) eq 'HASH') {
179 1         6 for my $key (keys %$value) {
180 2         7 $value->{$key} = FROM_BOOL($value->{$key});
181             }
182 1         16 return $value;
183             }
184              
185 4 100       7 if (ref($value) eq 'ARRAY') {
186 1         4 for my $key (keys @$value) {
187 2         7 $value->[$key] = FROM_BOOL($value->[$key]);
188             }
189 1         4 return $value;
190             }
191              
192 3         11 return Venus::Boolean::TO_BOOL(Venus::Boolean::FROM_BOOL($value));
193             }
194              
195             sub TO_BOOL {
196 30     30 0 54 my ($value) = @_;
197              
198 30         1426 require Venus::Boolean;
199              
200 30 100       83 if (ref($value) eq 'HASH') {
201 4         19 $value = {
202             %$value
203             };
204 4         14 for my $key (keys %$value) {
205 12         31 $value->{$key} = TO_BOOL($value->{$key});
206             }
207 4         23 return $value;
208             }
209              
210 26 100       64 if (ref($value) eq 'ARRAY') {
211 6         18 $value = [
212             @$value
213             ];
214 6         18 for my $key (keys @$value) {
215 10         25 $value->[$key] = TO_BOOL($value->[$key]);
216             }
217 6         16 return $value;
218             }
219              
220 20         54 return Venus::Boolean::TO_BOOL_JPO($value);
221             }
222              
223             # ERRORS
224              
225             sub error_on_config {
226 1     1 1 3 my ($self) = @_;
227              
228             return {
229 1         7 name => 'on.config',
230             message => 'No suitable JSON package',
231             raise => true,
232             };
233             }
234              
235             1;
236              
237              
238              
239             =head1 NAME
240              
241             Venus::Json - Json Class
242              
243             =cut
244              
245             =head1 ABSTRACT
246              
247             Json Class for Perl 5
248              
249             =cut
250              
251             =head1 SYNOPSIS
252              
253             package main;
254              
255             use Venus::Json;
256              
257             my $json = Venus::Json->new(
258             value => { name => ['Ready', 'Robot'], version => 0.12, stable => !!1, }
259             );
260              
261             # $json->encode;
262              
263             =cut
264              
265             =head1 DESCRIPTION
266              
267             This package provides methods for reading and writing L
268             data. B This package requires that a suitable JSON library is installed,
269             currently either C C<3.0+>, C C<2.27105+>, or
270             C C<4.09+>. You can use the C environment
271             variable to include or prioritize your preferred JSON library.
272              
273             =cut
274              
275             =head1 ATTRIBUTES
276              
277             This package has the following attributes:
278              
279             =cut
280              
281             =head2 decoder
282              
283             decoder(CodeRef)
284              
285             This attribute is read-write, accepts C<(CodeRef)> values, and is optional.
286              
287             =cut
288              
289             =head2 encoder
290              
291             encoder(CodeRef)
292              
293             This attribute is read-write, accepts C<(CodeRef)> values, and is optional.
294              
295             =cut
296              
297             =head1 INHERITS
298              
299             This package inherits behaviors from:
300              
301             L
302              
303             =cut
304              
305             =head1 INTEGRATES
306              
307             This package integrates behaviors from:
308              
309             L
310              
311             L
312              
313             L
314              
315             L
316              
317             =cut
318              
319             =head1 METHODS
320              
321             This package provides the following methods:
322              
323             =cut
324              
325             =head2 decode
326              
327             decode(string $json) (any)
328              
329             The decode method decodes the JSON string, sets the object value, and returns
330             the decoded value.
331              
332             I>
333              
334             =over 4
335              
336             =item decode example 1
337              
338             # given: synopsis;
339              
340             my $decode = $json->decode('{"codename":["Ready","Robot"],"stable":true}');
341              
342             # { codename => ["Ready", "Robot"], stable => 1 }
343              
344             =back
345              
346             =cut
347              
348             =head2 encode
349              
350             encode() (string)
351              
352             The encode method encodes the objects value as a JSON string and returns the
353             encoded string.
354              
355             I>
356              
357             =over 4
358              
359             =item encode example 1
360              
361             # given: synopsis;
362              
363             my $encode = $json->encode;
364              
365             # '{ "name": ["Ready", "Robot"], "stable": true, "version": 0.12 }'
366              
367             =back
368              
369             =cut
370              
371             =head1 ERRORS
372              
373             This package may raise the following errors:
374              
375             =cut
376              
377             =over 4
378              
379             =item error: C
380              
381             This package may raise an error_on_config exception.
382              
383             B
384              
385             # given: synopsis;
386              
387             my $input = {
388             throw => 'error_on_config',
389             };
390              
391             my $error = $json->catch('error', $input);
392              
393             # my $name = $error->name;
394              
395             # "on_config"
396              
397             # my $message = $error->message;
398              
399             # "No suitable JSON package"
400              
401             =back
402              
403             =head1 AUTHORS
404              
405             Awncorp, C
406              
407             =cut
408              
409             =head1 LICENSE
410              
411             Copyright (C) 2000, Awncorp, C.
412              
413             This program is free software, you can redistribute it and/or modify it under
414             the terms of the Apache license version 2.0.
415              
416             =cut