File Coverage

blib/lib/Venus/Json.pm
Criterion Covered Total %
statement 82 101 81.1
branch 18 24 75.0
condition 2 6 33.3
subroutine 18 24 75.0
pod 4 13 30.7
total 124 168 73.8


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