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   3372367 use strict;
  67         591  
  67         1489  
5 67     67   256 use Carp ();
  67         88  
  67         766  
6 67     67   233 use Exporter;
  67         138  
  67         2821  
7 67     67   5148 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   201 $JSON::VERSION = '4.10';
13 67 50       212 $JSON::DEBUG = 0 unless (defined $JSON::DEBUG);
14 67 50       95532 $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   481 my $pkg = shift;
91 67         108 my @what_to_export;
92             my $no_export;
93              
94 67         122 for my $tag (@_) {
95 11 100       30 if ($tag eq '-support_by_pp') {
    50          
    50          
96 10 50       28 if (!$_ALLOW_UNSUPPORTED++) {
97 10 100       115 JSON::Backend::XS
98             ->support_by_pp(@PPOnlyMethods) if ($JSON::Backend->is_xs);
99             }
100 10         31 next;
101             }
102             elsif ($tag eq '-no_export') {
103 0         0 $no_export++, next;
104             }
105             elsif ( $tag eq '-convert_blessed_universally' ) {
106 1         10 my $org_encode = $JSON::Backend->can('encode');
107 1 50   11   61 eval q|
  11     10   5229  
  11         53148  
  11         220  
  10         56  
  10         15  
  10         2039  
  10         51  
  10         14  
  10         1092  
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         3 next;
124             }
125 0         0 push @what_to_export, $tag;
126             }
127              
128 67 50       190 return if ($no_export);
129              
130 67         77642 __PACKAGE__->export_to_level(1, $pkg, @what_to_export);
131             }
132              
133              
134             # OBSOLETED
135              
136             sub jsonToObj {
137 2     2 0 15 my $alternative = 'from_json';
138 2 50 0     36 if (defined $_[0] and UNIVERSAL::isa($_[0], 'JSON')) {
139 0         0 shift @_; $alternative = 'decode';
  2         18  
140             }
141 3         32 Carp::carp "'jsonToObj' will be obsoleted. Please use '$alternative' instead.";
142 3         9 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 470 if (
      66        
159             ref($_[0]) eq 'JSON'
160             or (@_ > 2 and $_[0] eq 'JSON')
161             ) {
162 1         172 Carp::croak "to_json should not be called as a method.";
163             }
164 7         31 my $json = JSON->new;
165              
166 7 100 66     33 if (@_ == 2 and ref $_[1] eq 'HASH') {
167 4         6 my $opt = $_[1];
168 4         10 for my $method (keys %$opt) {
169 4         78 $json->$method( $opt->{$method} );
170             }
171             }
172              
173 7         22 $json->encode($_[0]);
174             }
175              
176              
177             sub from_json ($@) {
178 5 50 33 5 1 25 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         52 my $json = JSON->new;
182              
183 5 100 66     15 if (@_ == 2 and ref $_[1] eq 'HASH') {
184 1         2 my $opt = $_[1];
185 1         5 for my $method (keys %$opt) {
186 1         20 $json->$method( $opt->{$method} );
187             }
188             }
189              
190 5         18 return $json->decode( $_[0] );
191             }
192              
193              
194              
195 9     9 1 1203 sub true { $JSON::true }
196              
197 5     5 1 16 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 22 pop() ? $JSON::true : $JSON::false
202             }
203              
204 3     3 1 2760 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 1451 my $proto = shift;
211 34         396 $JSON::Backend;
212             }
213              
214             #*module = *backend;
215              
216              
217             sub is_xs {
218 2     2 1 3 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 58 my ($self, $name, $value) = @_;
232              
233 36 50       77 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       116 if ( my $method = $self->can('get_' . $name) ) {
251 36 50       65 if ($name eq 'max_size') {
252 0         0 my $value = $self->$method();
253 0 0       0 return $value == 1 ? 0 : $value;
254             }
255 36         452 $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   29 my ($module, $opt) = @_;
270              
271 10 50       46 $JSON::DEBUG and Carp::carp "Load $module.";
272 10   50     39 my $required_version = $RequiredVersion{$module} || '';
273              
274 10     10   561 eval qq|
275             use $module $required_version ();
276             |;
277              
278 10 50       32 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         21 return 1;
287             }
288              
289             sub _load_xs {
290 10     10   19 my ($module, $opt) = @_;
291 10 50       31 __load_xs($module, $opt) or return;
292              
293 10         6384 my $data = join("", ); # this code is from Jcode 2.xx.
294 10         564 close(DATA);
295 10         1630 eval $data;
296 10         188 JSON::Backend::XS->init($module);
297              
298 10         14 return 1;
299             };
300              
301              
302             sub __load_pp {
303 68     68   1723 my ($module, $opt) = @_;
304              
305 68 100       198 $JSON::DEBUG and Carp::carp "Load $module.";
306 68   100     395 my $required_version = $RequiredVersion{$module} || '';
307              
308 62     62   37491 eval qq| use $module $required_version () |;
  62         52600  
  62         666  
  68         3966  
309              
310 152 50       1549 if ($@) {
311 90 50       994 if ( $module eq 'JSON::PP' ) {
312 6 50       110 $JSON::DEBUG and Carp::carp "Can't load $module ($@), so try to load JSON::backportPP";
313 6         56 $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       21 Carp::croak $@ if $@;
318             }
319 72         146 $JSON::BackendModulePP = $module;
320 72         187 return 1;
321             }
322              
323             sub _load_pp {
324 67     67   161 my ($module, $opt) = @_;
325 67         190 __load_pp($module, $opt);
326              
327 67         397 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   159 my ($class, $module) = @_;
338              
339             # name may vary, but the module should (always) be a JSON::PP
340              
341 67         220 local $^W;
342 67     67   501 no strict qw(refs); # this routine may be called after JSON::Backend::XS init was called.
  67         117  
  67         17908  
343 67         103 *{"JSON::decode_json"} = \&{"JSON::PP::decode_json"};
  67         298  
  67         184  
344 67         120 *{"JSON::encode_json"} = \&{"JSON::PP::encode_json"};
  67         176  
  67         129  
345 67         114 *{"JSON::is_bool"} = \&{"JSON::PP::is_bool"};
  67         182  
  67         182  
346              
347 67         104 $JSON::true = ${"JSON::PP::true"};
  67         138  
348 67         133 $JSON::false = ${"JSON::PP::false"};
  67         158  
349              
350 67         520 push @JSON::Backend::PP::ISA, 'JSON::PP';
351 57         493 push @JSON::ISA, $class;
352 57         149 $JSON::Backend = $class;
353 57         92 $JSON::BackendModule = $module;
354 67         720 my $version = ${"$class\::VERSION"} = $module->VERSION;
  137         465  
355 137         367 $version =~ s/_//;
356 67 50       319 if ($version < 3.99) {
357 2         7 push @XSOnlyMethods, qw/allow_tags get_allow_tags/;
358             } else {
359 74         234 push @Properties, 'allow_tags';
360             }
361              
362 62         143 for my $method (@XSOnlyMethods) {
363 5         17 *{"JSON::$method"} = sub {
364 5     17   14 Carp::carp("$method is not supported by $module $version.");
365 40         117 $_[0];
366 5         13 };
367             }
368              
369 97         241 return 1;
370             }
371              
372 45     10   137 sub is_xs { 0 };
373 8     3   29 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__