File Coverage

blib/lib/JSON.pm
Criterion Covered Total %
statement 133 165 80.6
branch 35 70 50.0
condition 12 28 42.8
subroutine 29 33 87.8
pod 10 14 71.4
total 219 310 70.6


line stmt bran cond sub pod time code
1             package JSON;
2              
3              
4 68     68   5859183 use strict;
  68         107  
  68         2072  
5 68     68   273 use Carp ();
  68         100  
  68         1438  
6 68     68   249 use Exporter;
  68         89  
  68         3176  
7 68     68   6376 BEGIN { @JSON::ISA = 'Exporter' }
8              
9             @JSON::EXPORT = qw(from_json to_json jsonToObj objToJson encode_json decode_json);
10              
11             BEGIN {
12 68     68   280 $JSON::VERSION = '4.11';
13 68 50       311 $JSON::DEBUG = 0 unless (defined $JSON::DEBUG);
14 68 50       109549 $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   607 my $pkg = shift;
91 67         171 my @what_to_export;
92             my $no_export;
93              
94 67         145 for my $tag (@_) {
95 11 100       33 if ($tag eq '-support_by_pp') {
    50          
    50          
96 10 50       30 if (!$_ALLOW_UNSUPPORTED++) {
97 10 100       172 JSON::Backend::XS
98             ->support_by_pp(@PPOnlyMethods) if ($JSON::Backend->is_xs);
99             }
100 10         24 next;
101             }
102             elsif ($tag eq '-no_export') {
103 0         0 $no_export++, next;
104             }
105             elsif ( $tag eq '-convert_blessed_universally' ) {
106 1         7 my $org_encode = $JSON::Backend->can('encode');
107 1 50   12   63 eval q|
  12     11   6751  
  12         71108  
  12         264  
  11         73  
  11         18  
  11         2859  
  11         57  
  11         15  
  11         1604  
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       196 return if ($no_export);
129              
130 67         87597 __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     10 if (defined $_[0] and UNIVERSAL::isa($_[0], 'JSON')) {
139 2         24 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 3518 if (
      66        
159             ref($_[0]) eq 'JSON'
160             or (@_ > 2 and $_[0] eq 'JSON')
161             ) {
162 1         195 Carp::croak "to_json should not be called as a method.";
163             }
164 7         33 my $json = JSON->new;
165              
166 7 100 66     35 if (@_ == 2 and ref $_[1] eq 'HASH') {
167 4         5 my $opt = $_[1];
168 4         10 for my $method (keys %$opt) {
169 4         98 $json->$method( $opt->{$method} );
170             }
171             }
172              
173 7         28 $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         15 my $json = JSON->new;
182              
183 5 100 66     15 if (@_ == 2 and ref $_[1] eq 'HASH') {
184 1         1 my $opt = $_[1];
185 1         3 for my $method (keys %$opt) {
186 1         25 $json->$method( $opt->{$method} );
187             }
188             }
189              
190 5         17 return $json->decode( $_[0] );
191             }
192              
193              
194              
195 8     8 1 3474 sub true { $JSON::true }
196              
197 4     4 1 26 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 0 0   0 1 0 pop() ? $JSON::true : $JSON::false
202             }
203              
204 3     3 1 7 sub null { undef; }
205              
206              
207 0     0 0 0 sub require_xs_version { $RequiredVersion{'JSON::XS'}; }
208              
209             sub backend {
210 35     35 1 1103111 my $proto = shift;
211 35         479 $JSON::Backend;
212             }
213              
214             #*module = *backend;
215              
216              
217             sub is_xs {
218 2     2 1 5 return $_[0]->backend->is_xs;
219             }
220              
221              
222             sub is_pp {
223 2     2 1 4 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 53 my ($self, $name, $value) = @_;
232              
233 36 50       76 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       127 if ( my $method = $self->can('get_' . $name) ) {
251 36 50       77 if ($name eq 'max_size') {
252 0         0 my $value = $self->$method();
253 0 0       0 return $value == 1 ? 0 : $value;
254             }
255 36         421 $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 11     11   15 my ($module, $opt) = @_;
270              
271 11 50       28 $JSON::DEBUG and Carp::carp "Load $module.";
272 11   50     40 my $required_version = $RequiredVersion{$module} || '';
273              
274 11     11   918 eval qq|
275             use $module $required_version ();
276             |;
277              
278 11 50       41 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 11         20 $JSON::BackendModuleXS = $module;
286 11         27 return 1;
287             }
288              
289             sub _load_xs {
290 11     11   29 my ($module, $opt) = @_;
291 11 50       32 __load_xs($module, $opt) or return;
292              
293 11         7837 my $data = join("", ); # this code is from Jcode 2.xx.
294 11         759 close(DATA);
295 11         2485 eval $data;
296 11         301 JSON::Backend::XS->init($module);
297              
298 11         42 return 1;
299             };
300              
301              
302             sub __load_pp {
303 68     68   1632 my ($module, $opt) = @_;
304              
305 68 100       240 $JSON::DEBUG and Carp::carp "Load $module.";
306 68   100     482 my $required_version = $RequiredVersion{$module} || '';
307              
308 62     62   43591 eval qq| use $module $required_version () |;
  62         76897  
  62         805  
  68         4781  
309              
310 152 50       1403 if ($@) {
311 90 50       950 if ( $module eq 'JSON::PP' ) {
312 6 50       103 $JSON::DEBUG and Carp::carp "Can't load $module ($@), so try to load JSON::backportPP";
313 6         58 $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 11 50       43 Carp::croak $@ if $@;
318             }
319 73         213 $JSON::BackendModulePP = $module;
320 73         295 return 1;
321             }
322              
323             sub _load_pp {
324 68     68   174 my ($module, $opt) = @_;
325 68         191 __load_pp($module, $opt);
326              
327 68         403 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 68     59   234 my ($class, $module) = @_;
338              
339             # name may vary, but the module should (always) be a JSON::PP
340              
341 68         245 local $^W;
342 68     68   525 no strict qw(refs); # this routine may be called after JSON::Backend::XS init was called.
  68         94  
  68         21698  
343 68         94 *{"JSON::decode_json"} = \&{"JSON::PP::decode_json"};
  68         401  
  68         250  
344 68         133 *{"JSON::encode_json"} = \&{"JSON::PP::encode_json"};
  68         185  
  68         163  
345 68         152 *{"JSON::is_bool"} = \&{"JSON::PP::is_bool"};
  68         247  
  68         216  
346              
347 68         111 $JSON::true = ${"JSON::PP::true"};
  68         176  
348 68         175 $JSON::false = ${"JSON::PP::false"};
  68         188  
349              
350 68         694 push @JSON::Backend::PP::ISA, 'JSON::PP';
351 57         651 push @JSON::ISA, $class;
352 57         174 $JSON::Backend = $class;
353 57         101 $JSON::BackendModule = $module;
354 68         746 my $version = ${"$class\::VERSION"} = $module->VERSION;
  145         515  
355 145         453 $version =~ s/_//;
356 68 50       489 if ($version < 3.99) {
357 59         168 push @XSOnlyMethods, qw/allow_tags get_allow_tags/;
358             } else {
359 17         107 push @Properties, 'allow_tags';
360             }
361              
362 62         151 for my $method (@XSOnlyMethods) {
363 119         459 *{"JSON::$method"} = sub {
364 6     18   228 Carp::carp("$method is not supported by $module $version.");
365 41         166 $_[0];
366 119         446 };
367             }
368              
369 97         319 return 1;
370             }
371              
372 45     10   171 sub is_xs { 0 };
373 8     3   35 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__