File Coverage

blib/lib/JSON.pm
Criterion Covered Total %
statement 134 165 81.2
branch 37 70 52.8
condition 12 28 42.8
subroutine 30 33 90.9
pod 10 14 71.4
total 223 310 71.9


line stmt bran cond sub pod time code
1             package JSON;
2              
3              
4 67     67   3626939 use strict;
  67         613  
  67         1585  
5 67     67   285 use Carp ();
  67         101  
  67         892  
6 67     67   255 use Exporter;
  67         108  
  67         3553  
7 67     67   5508 BEGIN { @JSON::ISA = 'Exporter' }
8              
9             @JSON::EXPORT = qw(from_json to_json jsonToObj objToJson encode_json decode_json);
10              
11             BEGIN {
12 67     67   215 $JSON::VERSION = '4.09';
13 67 50       227 $JSON::DEBUG = 0 unless (defined $JSON::DEBUG);
14 67 50       102769 $JSON::DEBUG = $ENV{ PERL_JSON_DEBUG } if exists $ENV{ PERL_JSON_DEBUG };
15             }
16              
17             my %RequiredVersion = (
18             'JSON::PP' => '2.27203',
19             'JSON::XS' => '2.34',
20             );
21              
22             # XS and PP common methods
23              
24             my @PublicMethods = qw/
25             ascii latin1 utf8 pretty indent space_before space_after relaxed canonical allow_nonref
26             allow_blessed convert_blessed filter_json_object filter_json_single_key_object
27             shrink max_depth max_size encode decode decode_prefix allow_unknown
28             /;
29              
30             my @Properties = qw/
31             ascii latin1 utf8 indent space_before space_after relaxed canonical allow_nonref
32             allow_blessed convert_blessed shrink max_depth max_size allow_unknown
33             /;
34              
35             my @XSOnlyMethods = qw//; # Currently nothing
36              
37             my @PublicMethodsSince4_0 = qw/allow_tags/;
38             my @PropertiesSince4_0 = qw/allow_tags/;
39              
40             my @PPOnlyMethods = qw/
41             indent_length sort_by
42             allow_singlequote allow_bignum loose allow_barekey escape_slash as_nonblessed
43             /; # JSON::PP specific
44              
45              
46             # used in _load_xs and _load_pp ($INSTALL_ONLY is not used currently)
47             my $_INSTALL_DONT_DIE = 1; # When _load_xs fails to load XS, don't die.
48             my $_ALLOW_UNSUPPORTED = 0;
49             my $_UNIV_CONV_BLESSED = 0;
50              
51              
52             # Check the environment variable to decide worker module.
53              
54             unless ($JSON::Backend) {
55             $JSON::DEBUG and Carp::carp("Check used worker module...");
56              
57             my $backend = exists $ENV{PERL_JSON_BACKEND} ? $ENV{PERL_JSON_BACKEND} : 1;
58              
59             if ($backend eq '1') {
60             $backend = 'JSON::XS,JSON::PP';
61             }
62             elsif ($backend eq '0') {
63             $backend = 'JSON::PP';
64             }
65             elsif ($backend eq '2') {
66             $backend = 'JSON::XS';
67             }
68             $backend =~ s/\s+//g;
69              
70             my @backend_modules = split /,/, $backend;
71             while(my $module = shift @backend_modules) {
72             if ($module =~ /JSON::XS/) {
73             _load_xs($module, @backend_modules ? $_INSTALL_DONT_DIE : 0);
74             }
75             elsif ($module =~ /JSON::PP/) {
76             _load_pp($module);
77             }
78             elsif ($module =~ /JSON::backportPP/) {
79             _load_pp($module);
80             }
81             else {
82             Carp::croak "The value of environmental variable 'PERL_JSON_BACKEND' is invalid.";
83             }
84             last if $JSON::Backend;
85             }
86             }
87              
88              
89             sub import {
90 67     67   548 my $pkg = shift;
91 67         124 my @what_to_export;
92             my $no_export;
93              
94 67         132 for my $tag (@_) {
95 11 100       37 if ($tag eq '-support_by_pp') {
    50          
    50          
96 10 50       30 if (!$_ALLOW_UNSUPPORTED++) {
97 10 100       114 JSON::Backend::XS
98             ->support_by_pp(@PPOnlyMethods) if ($JSON::Backend->is_xs);
99             }
100 10         27 next;
101             }
102             elsif ($tag eq '-no_export') {
103 0         0 $no_export++, next;
104             }
105             elsif ( $tag eq '-convert_blessed_universally' ) {
106 1         8 my $org_encode = $JSON::Backend->can('encode');
107 1 50   11   58 eval q|
  11     10   5898  
  11         60404  
  11         228  
  10         59  
  10         16  
  10         2447  
  10         61  
  10         14  
  10         1261  
108             require B;
109             local $^W;
110             no strict 'refs';
111             *{"${JSON::Backend}\::encode"} = sub {
112             # only works with Perl 5.18+
113             local *UNIVERSAL::TO_JSON = sub {
114             my $b_obj = B::svref_2object( $_[0] );
115             return $b_obj->isa('B::HV') ? { %{ $_[0] } }
116             : $b_obj->isa('B::AV') ? [ @{ $_[0] } ]
117             : undef
118             ;
119             };
120             $org_encode->(@_);
121             };
122             | if ( !$_UNIV_CONV_BLESSED++ );
123 1         4 next;
124             }
125 0         0 push @what_to_export, $tag;
126             }
127              
128 67 50       204 return if ($no_export);
129              
130 67         81039 __PACKAGE__->export_to_level(1, $pkg, @what_to_export);
131             }
132              
133              
134             # OBSOLETED
135              
136             sub jsonToObj {
137 3     3 0 32 my $alternative = 'from_json';
138 2 50 0     9 if (defined $_[0] and UNIVERSAL::isa($_[0], 'JSON')) {
139 2         23 shift @_; $alternative = 'decode';
  0         0  
140             }
141 2         13 Carp::carp "'jsonToObj' will be obsoleted. Please use '$alternative' instead.";
142 3         8 return JSON::from_json(@_);
143             };
144              
145             sub objToJson {
146 0     0 0 0 my $alternative = 'to_json';
147 0 50 0     0 if (defined $_[0] and UNIVERSAL::isa($_[0], 'JSON')) {
148 0         0 shift @_; $alternative = 'encode';
  0         0  
149             }
150 0         0 Carp::carp "'objToJson' will be obsoleted. Please use '$alternative' instead.";
151 0         0 JSON::to_json(@_);
152             };
153              
154              
155             # INTERFACES
156              
157             sub to_json ($@) {
158 8 100 66 8 1 786 if (
      66        
159             ref($_[0]) eq 'JSON'
160             or (@_ > 2 and $_[0] eq 'JSON')
161             ) {
162 1         184 Carp::croak "to_json should not be called as a method.";
163             }
164 7         37 my $json = JSON->new;
165              
166 7 100 66     40 if (@_ == 2 and ref $_[1] eq 'HASH') {
167 4         6 my $opt = $_[1];
168 4         11 for my $method (keys %$opt) {
169 4         88 $json->$method( $opt->{$method} );
170             }
171             }
172              
173 7         24 $json->encode($_[0]);
174             }
175              
176              
177             sub from_json ($@) {
178 5 50 33 5 1 30 if ( ref($_[0]) eq 'JSON' or $_[0] eq 'JSON' ) {
179 0         0 Carp::croak "from_json should not be called as a method.";
180             }
181 5         18 my $json = JSON->new;
182              
183 5 100 66     17 if (@_ == 2 and ref $_[1] eq 'HASH') {
184 1         2 my $opt = $_[1];
185 1         4 for my $method (keys %$opt) {
186 1         23 $json->$method( $opt->{$method} );
187             }
188             }
189              
190 5         21 return $json->decode( $_[0] );
191             }
192              
193              
194              
195 9     9 1 1256 sub true { $JSON::true }
196              
197 5     5 1 19 sub false { $JSON::false }
198              
199             sub boolean {
200             # might be called as method or as function, so pop() to get the last arg instead of shift() to get the first
201 4 100   4 1 18 pop() ? $JSON::true : $JSON::false
202             }
203              
204 3     3 1 2247 sub null { undef; }
205              
206              
207 0     0 0 0 sub require_xs_version { $RequiredVersion{'JSON::XS'}; }
208              
209             sub backend {
210 34     34 1 1659 my $proto = shift;
211 34         415 $JSON::Backend;
212             }
213              
214             #*module = *backend;
215              
216              
217             sub is_xs {
218 2     2 1 6 return $_[0]->backend->is_xs;
219             }
220              
221              
222             sub is_pp {
223 2     2 1 5 return $_[0]->backend->is_pp;
224             }
225              
226              
227 0     0 0 0 sub pureperl_only_methods { @PPOnlyMethods; }
228              
229              
230             sub property {
231 36     36 1 57 my ($self, $name, $value) = @_;
232              
233 36 50       107 if (@_ == 1) {
    50          
    50          
234 0         0 my %props;
235 0         0 for $name (@Properties) {
236 0         0 my $method = 'get_' . $name;
237 0 0       0 if ($name eq 'max_size') {
238 0         0 my $value = $self->$method();
239 0 0       0 $props{$name} = $value == 1 ? 0 : $value;
240 0         0 next;
241             }
242 0         0 $props{$name} = $self->$method();
243             }
244 0         0 return \%props;
245             }
246             elsif (@_ > 3) {
247 0         0 Carp::croak('property() can take only the option within 2 arguments.');
248             }
249             elsif (@_ == 2) {
250 36 50       138 if ( my $method = $self->can('get_' . $name) ) {
251 36 50       86 if ($name eq 'max_size') {
252 0         0 my $value = $self->$method();
253 0 0       0 return $value == 1 ? 0 : $value;
254             }
255 36         499 $self->$method();
256             }
257             }
258             else {
259 0         0 $self->$name($value);
260             }
261              
262             }
263              
264              
265              
266             # INTERNAL
267              
268             sub __load_xs {
269 10     10   33 my ($module, $opt) = @_;
270              
271 10 50       57 $JSON::DEBUG and Carp::carp "Load $module.";
272 10   50     37 my $required_version = $RequiredVersion{$module} || '';
273              
274 10     10   624 eval qq|
275             use $module $required_version ();
276             |;
277              
278 10 50       38 if ($@) {
279 0 0 0     0 if (defined $opt and $opt & $_INSTALL_DONT_DIE) {
280 0 0       0 $JSON::DEBUG and Carp::carp "Can't load $module...($@)";
281 0         0 return 0;
282             }
283 0         0 Carp::croak $@;
284             }
285 10         19 $JSON::BackendModuleXS = $module;
286 10         26 return 1;
287             }
288              
289             sub _load_xs {
290 10     10   20 my ($module, $opt) = @_;
291 10 50       35 __load_xs($module, $opt) or return;
292              
293 10         7246 my $data = join("", ); # this code is from Jcode 2.xx.
294 10         640 close(DATA);
295 10         1762 eval $data;
296 10         216 JSON::Backend::XS->init($module);
297              
298 10         17 return 1;
299             };
300              
301              
302             sub __load_pp {
303 68     68   1644 my ($module, $opt) = @_;
304              
305 68 100       212 $JSON::DEBUG and Carp::carp "Load $module.";
306 68   100     451 my $required_version = $RequiredVersion{$module} || '';
307              
308 62     62   42471 eval qq| use $module $required_version () |;
  62         58804  
  62         692  
  68         4214  
309              
310 152 50       1801 if ($@) {
311 90 50       1224 if ( $module eq 'JSON::PP' ) {
312 6 50       468 $JSON::DEBUG and Carp::carp "Can't load $module ($@), so try to load JSON::backportPP";
313 6         72 $module = 'JSON::backportPP';
314 0         0 local $^W; # if PP installed but invalid version, backportPP redefines methods.
315 0         0 eval qq| require $module |;
316             }
317 10 50       29 Carp::croak $@ if $@;
318             }
319 72         157 $JSON::BackendModulePP = $module;
320 72         220 return 1;
321             }
322              
323             sub _load_pp {
324 67     67   181 my ($module, $opt) = @_;
325 67         211 __load_pp($module, $opt);
326              
327 67         831 JSON::Backend::PP->init($module);
328             };
329              
330             #
331             # Helper classes for Backend Module (PP)
332             #
333              
334             package JSON::Backend::PP;
335              
336             sub init {
337 67     59   179 my ($class, $module) = @_;
338              
339             # name may vary, but the module should (always) be a JSON::PP
340              
341 67         233 local $^W;
342 67     67   523 no strict qw(refs); # this routine may be called after JSON::Backend::XS init was called.
  67         121  
  67         19515  
343 67         101 *{"JSON::decode_json"} = \&{"JSON::PP::decode_json"};
  67         324  
  67         198  
344 67         124 *{"JSON::encode_json"} = \&{"JSON::PP::encode_json"};
  67         210  
  67         148  
345 67         112 *{"JSON::is_bool"} = \&{"JSON::PP::is_bool"};
  67         210  
  67         203  
346              
347 67         103 $JSON::true = ${"JSON::PP::true"};
  67         157  
348 67         212 $JSON::false = ${"JSON::PP::false"};
  67         163  
349              
350 67         584 push @JSON::Backend::PP::ISA, 'JSON::PP';
351 57         542 push @JSON::ISA, $class;
352 57         161 $JSON::Backend = $class;
353 57         79 $JSON::BackendModule = $module;
354 67         786 my $version = ${"$class\::VERSION"} = $module->VERSION;
  137         476  
355 137         413 $version =~ s/_//;
356 67 50       377 if ($version < 3.99) {
357 2         6 push @XSOnlyMethods, qw/allow_tags get_allow_tags/;
358             } else {
359 74         246 push @Properties, 'allow_tags';
360             }
361              
362 62         151 for my $method (@XSOnlyMethods) {
363 5         28 *{"JSON::$method"} = sub {
364 5     17   12 Carp::carp("$method is not supported by $module $version.");
365 40         142 $_[0];
366 5         13 };
367             }
368              
369 97         258 return 1;
370             }
371              
372 45     10   144 sub is_xs { 0 };
373 8     3   32 sub is_pp { 1 };
374              
375             #
376             # To save memory, the below lines are read only when XS backend is used.
377             #
378              
379             package JSON;
380              
381             1;
382             __DATA__