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   3521120 use strict;
  67         587  
  67         1487  
5 67     67   306 use Carp ();
  67         122  
  67         857  
6 67     67   255 use Exporter;
  67         96  
  67         2890  
7 67     67   5370 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   217 $JSON::VERSION = '4.08';
13 67 50       211 $JSON::DEBUG = 0 unless (defined $JSON::DEBUG);
14 67 50       99867 $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   483 my $pkg = shift;
91 67         108 my @what_to_export;
92             my $no_export;
93              
94 67         125 for my $tag (@_) {
95 11 100       29 if ($tag eq '-support_by_pp') {
    50          
    50          
96 10 50       31 if (!$_ALLOW_UNSUPPORTED++) {
97 10 100       101 JSON::Backend::XS
98             ->support_by_pp(@PPOnlyMethods) if ($JSON::Backend->is_xs);
99             }
100 10         34 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   11   56 eval q|
  11     10   6494  
  11         61175  
  11         228  
  10         68  
  10         16  
  10         2389  
  10         57  
  10         14  
  10         1324  
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       189 return if ($no_export);
129              
130 67         77067 __PACKAGE__->export_to_level(1, $pkg, @what_to_export);
131             }
132              
133              
134             # OBSOLETED
135              
136             sub jsonToObj {
137 3     3 0 30 my $alternative = 'from_json';
138 2 50 0     8 if (defined $_[0] and UNIVERSAL::isa($_[0], 'JSON')) {
139 2         18 shift @_; $alternative = 'decode';
  0         0  
140             }
141 2         13 Carp::carp "'jsonToObj' will be obsoleted. Please use '$alternative' instead.";
142 3         10 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 773 if (
      66        
159             ref($_[0]) eq 'JSON'
160             or (@_ > 2 and $_[0] eq 'JSON')
161             ) {
162 1         183 Carp::croak "to_json should not be called as a method.";
163             }
164 7         36 my $json = JSON->new;
165              
166 7 100 66     37 if (@_ == 2 and ref $_[1] eq 'HASH') {
167 4         7 my $opt = $_[1];
168 4         11 for my $method (keys %$opt) {
169 4         91 $json->$method( $opt->{$method} );
170             }
171             }
172              
173 7         25 $json->encode($_[0]);
174             }
175              
176              
177             sub from_json ($@) {
178 5 50 33 5 1 28 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         2 my $opt = $_[1];
185 1         4 for my $method (keys %$opt) {
186 1         22 $json->$method( $opt->{$method} );
187             }
188             }
189              
190 5         17 return $json->decode( $_[0] );
191             }
192              
193              
194              
195 9     9 1 1262 sub true { $JSON::true }
196              
197 5     5 1 17 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 17 pop() ? $JSON::true : $JSON::false
202             }
203              
204 3     3 1 2197 sub null { undef; }
205              
206              
207 0     0 0 0 sub require_xs_version { $RequiredVersion{'JSON::XS'}; }
208              
209             sub backend {
210 32     32 1 1595 my $proto = shift;
211 32         417 $JSON::Backend;
212             }
213              
214             #*module = *backend;
215              
216              
217             sub is_xs {
218 2     2 1 4 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       96 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       129 if ( my $method = $self->can('get_' . $name) ) {
251 36 50       61 if ($name eq 'max_size') {
252 0         0 my $value = $self->$method();
253 0 0       0 return $value == 1 ? 0 : $value;
254             }
255 36         487 $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   35 my ($module, $opt) = @_;
270              
271 10 50       50 $JSON::DEBUG and Carp::carp "Load $module.";
272 10   50     43 my $required_version = $RequiredVersion{$module} || '';
273              
274 10     10   667 eval qq|
275             use $module $required_version ();
276             |;
277              
278 10 50       40 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         32 $JSON::BackendModuleXS = $module;
286 10         35 return 1;
287             }
288              
289             sub _load_xs {
290 10     10   20 my ($module, $opt) = @_;
291 10 50       37 __load_xs($module, $opt) or return;
292              
293 10         7690 my $data = join("", ); # this code is from Jcode 2.xx.
294 10         644 close(DATA);
295 10         1826 eval $data;
296 10         233 JSON::Backend::XS->init($module);
297              
298 10         19 return 1;
299             };
300              
301              
302             sub __load_pp {
303 68     68   2066 my ($module, $opt) = @_;
304              
305 68 100       180 $JSON::DEBUG and Carp::carp "Load $module.";
306 68   100     437 my $required_version = $RequiredVersion{$module} || '';
307              
308 62     62   40341 eval qq| use $module $required_version () |;
  62         59264  
  62         633  
  68         3958  
309              
310 152 50       1727 if ($@) {
311 90 50       1168 if ( $module eq 'JSON::PP' ) {
312 6 50       126 $JSON::DEBUG and Carp::carp "Can't load $module ($@), so try to load JSON::backportPP";
313 6         67 $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       31 Carp::croak $@ if $@;
318             }
319 72         147 $JSON::BackendModulePP = $module;
320 72         205 return 1;
321             }
322              
323             sub _load_pp {
324 67     67   175 my ($module, $opt) = @_;
325 67         206 __load_pp($module, $opt);
326              
327 67         752 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   164 my ($class, $module) = @_;
338              
339             # name may vary, but the module should (always) be a JSON::PP
340              
341 67         208 local $^W;
342 67     67   465 no strict qw(refs); # this routine may be called after JSON::Backend::XS init was called.
  67         111  
  67         19548  
343 67         93 *{"JSON::decode_json"} = \&{"JSON::PP::decode_json"};
  67         276  
  67         176  
344 67         118 *{"JSON::encode_json"} = \&{"JSON::PP::encode_json"};
  67         168  
  67         128  
345 67         119 *{"JSON::is_bool"} = \&{"JSON::PP::is_bool"};
  67         194  
  67         199  
346              
347 67         119 $JSON::true = ${"JSON::PP::true"};
  67         130  
348 67         145 $JSON::false = ${"JSON::PP::false"};
  67         145  
349              
350 67         514 push @JSON::Backend::PP::ISA, 'JSON::PP';
351 57         475 push @JSON::ISA, $class;
352 57         143 $JSON::Backend = $class;
353 57         76 $JSON::BackendModule = $module;
354 67         704 my $version = ${"$class\::VERSION"} = $module->VERSION;
  137         465  
355 137         428 $version =~ s/_//;
356 67 50       303 if ($version < 3.99) {
357 2         9 push @XSOnlyMethods, qw/allow_tags get_allow_tags/;
358             } else {
359 74         242 push @Properties, 'allow_tags';
360             }
361              
362 62         160 for my $method (@XSOnlyMethods) {
363 5         26 *{"JSON::$method"} = sub {
364 5     17   13 Carp::carp("$method is not supported by $module $version.");
365 40         138 $_[0];
366 5         19 };
367             }
368              
369 97         254 return 1;
370             }
371              
372 45     10   166 sub is_xs { 0 };
373 8     3   30 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__