File Coverage

blib/lib/JSON/MaybeXS.pm
Criterion Covered Total %
statement 61 71 85.9
branch 19 24 79.1
condition 13 24 54.1
subroutine 15 15 100.0
pod 5 5 100.0
total 113 139 81.2


line stmt bran cond sub pod time code
1             package JSON::MaybeXS;
2              
3 7     7   1069168 use strict;
  7         18  
  7         339  
4 7     7   62 use warnings FATAL => 'all';
  7         15  
  7         588  
5 7     7   48 use base qw(Exporter);
  7         19  
  7         3423  
6              
7             our $VERSION = '1.004008';
8             $VERSION =~ tr/_//d;
9              
10             sub _choose_json_module {
11 7 100   7   34 return 'Cpanel::JSON::XS' if $INC{'Cpanel/JSON/XS.pm'};
12 6 50 33     32 return 'JSON::XS' if $INC{'JSON/XS.pm'} && eval { JSON::XS->VERSION(3.0); 1 };
  0         0  
  0         0  
13              
14 6         15 my @err;
15              
16 6 100       7 return 'Cpanel::JSON::XS' if eval { require Cpanel::JSON::XS; 1; };
  6         2775  
  2         15388  
17 4         62 push @err, "Error loading Cpanel::JSON::XS: $@";
18              
19 4 50       7 return 'JSON::XS' if eval { require JSON::XS; JSON::XS->VERSION(3.0); 1; };
  4         19  
  0         0  
  0         0  
20 4         422 push @err, "Error loading JSON::XS: $@";
21              
22 4 100       13 return 'JSON::PP' if eval { require JSON::PP; 1 };
  4         24  
  3         39895  
23 1         15 push @err, "Error loading JSON::PP: $@";
24              
25 1         46 die join( "\n", "Couldn't load a JSON module:", @err );
26              
27             }
28              
29             BEGIN {
30 7     7   29 our $JSON_Class = _choose_json_module();
31 6         361 $JSON_Class->import(qw(encode_json decode_json));
32 7     7   65 no strict 'refs';
  7         15  
  7         465  
33             *$_ = $JSON_Class->can($_)
34 6         1506 for qw(true false);
35             }
36              
37             our @EXPORT = qw(encode_json decode_json JSON);
38             my @EXPORT_ALL = qw(is_bool);
39             our @EXPORT_OK = qw(is_bool to_json from_json);
40             our %EXPORT_TAGS = ( all => [ @EXPORT, @EXPORT_ALL ],
41             legacy => [ @EXPORT, @EXPORT_OK ],
42             );
43              
44 26     26 1 675352 sub JSON () { our $JSON_Class }
45              
46             sub new {
47 5     5 1 166677 shift;
48 5 100       36 my %args = @_ == 1 ? %{$_[0]} : @_;
  1         5  
49 5         70 my $new = (our $JSON_Class)->new;
50 5         49 $new->$_($args{$_}) for keys %args;
51 5         108 return $new;
52             }
53              
54 6     6   62 use Scalar::Util ();
  6         18  
  6         350  
55 6     6   55 use constant HAVE_BUILTIN => "$]" >= 5.036;
  6         12  
  6         759  
56 6     6   43 use if HAVE_BUILTIN, experimental => 'builtin';
  6         27  
  6         2030  
57              
58             sub is_bool {
59 104 50   104 1 33230 die 'is_bool is not a method' if @_ > 1;
60              
61 104 100 100     745 HAVE_BUILTIN and builtin::is_bool($_[0])
      66        
62             or
63             !!Scalar::Util::blessed($_[0])
64             and ($_[0]->isa('JSON::PP::Boolean')
65             or $_[0]->isa('Cpanel::JSON::XS::Boolean')
66             or $_[0]->isa('JSON::XS::Boolean'));
67             }
68              
69             # (mostly) CopyPasta from JSON.pm version 2.90
70 6     6   31870 use Carp ();
  6         12  
  6         2645  
71              
72             sub from_json ($@) {
73 2 100 66 2 1 151307 if ( ref($_[0]) =~ /^JSON/ or $_[0] =~ /^JSON/ ) {
74 1         241 Carp::croak "from_json should not be called as a method.";
75             }
76 1         7 my $json = JSON()->new;
77              
78 1 50 33     17 if (@_ == 2 and ref $_[1] eq 'HASH') {
79 0         0 my $opt = $_[1];
80 0         0 for my $method (keys %$opt) {
81 0         0 $json->$method( $opt->{$method} );
82             }
83             }
84              
85 1         4 return $json->decode( $_[0] );
86             }
87              
88             sub to_json ($@) {
89 2 100 66 2 1 1009 if (
      33        
90             ref($_[0]) =~ /^JSON/
91             or (@_ > 2 and $_[0] =~ /^JSON/)
92             ) {
93 1         116 Carp::croak "to_json should not be called as a method.";
94             }
95 1         21 my $json = JSON()->new;
96              
97 1 50 33     18 if (@_ == 2 and ref $_[1] eq 'HASH') {
98 0         0 my $opt = $_[1];
99 0         0 for my $method (keys %$opt) {
100 0         0 $json->$method( $opt->{$method} );
101             }
102             }
103              
104 1         7 $json->encode($_[0]);
105             }
106              
107             1;
108              
109             =head1 NAME
110              
111             JSON::MaybeXS - Use L with a fallback to L and L
112              
113             =head1 SYNOPSIS
114              
115             use JSON::MaybeXS;
116              
117             my $data_structure = decode_json($json_input);
118              
119             my $json_output = encode_json($data_structure);
120              
121             my $json = JSON()->new;
122              
123             my $json_with_args = JSON::MaybeXS->new(utf8 => 1); # or { utf8 => 1 }
124              
125             =head1 DESCRIPTION
126              
127             This module first checks to see if either L or
128             L (at at least version 3.0)
129             is already loaded, in which case it uses that module. Otherwise
130             it tries to load L, then L, then L
131             in order, and either uses the first module it finds or throws an error.
132              
133             It then exports the C and C functions from the
134             loaded module, along with a C constant that returns the class name
135             for calling C on.
136              
137             If you're writing fresh code rather than replacing L usage, you might
138             want to pass options as constructor args rather than calling mutators, so
139             we provide our own C method that supports that.
140              
141             =head1 EXPORTS
142              
143             C, C and C are exported by default; C
144             is exported on request.
145              
146             To import only some symbols, specify them on the C line:
147              
148             use JSON::MaybeXS qw(encode_json decode_json is_bool); # functions only
149              
150             use JSON::MaybeXS qw(JSON); # JSON constant only
151              
152             To import all available sensible symbols (C, C, and
153             C), use C<:all>:
154              
155             use JSON::MaybeXS ':all';
156              
157             To import all symbols including those needed by legacy apps that use L:
158              
159             use JSON::MaybeXS ':legacy';
160              
161             This imports the C and C symbols as well as everything in
162             C<:all>. NOTE: This is to support legacy code that makes extensive
163             use of C and C which you are not yet in a position to
164             refactor. DO NOT use this import tag in new code, in order to avoid
165             the crawling horrors of getting UTF-8 support subtly wrong. See the
166             documentation for L for further details.
167              
168             =head2 encode_json
169              
170             This is the C function provided by the selected implementation
171             module, and takes a perl data structure which is serialised to JSON text.
172              
173             my $json_text = encode_json($data_structure);
174              
175             =head2 decode_json
176              
177             This is the C function provided by the selected implementation
178             module, and takes a string of JSON text to deserialise to a perl data structure.
179              
180             my $data_structure = decode_json($json_text);
181              
182             =head2 to_json
183              
184             This function is equivalent to calling C<< JSON()->new->encode($data_structure) >>.
185             It takes a perl data structure which is serialised to JSON text without encoding
186             it to UTF-8. You should only use this function if you expect another layer to
187             handle the UTF-8 encoding of the resulting JSON text.
188              
189             my $json_text = to_json($data_structure);
190              
191             Additional arguments can be passed and will be handled as in L,
192             this is included to support legacy code B.
193              
194             =head2 from_json
195              
196             This function is equivalent to calling C<< JSON()->new->decode($json_text) >>. It
197             takes a string of unencoded JSON text to deserialise to a perl data structure. You
198             should only use this function if another layer is already handling the UTF-8
199             decoding of the input JSON text.
200              
201             my $data_structure = from_json($json_text);
202              
203             Additional arguments can be passed and will be handled as in L,
204             this is included to support legacy code B.
205              
206             =head2 JSON
207              
208             The C constant returns the selected implementation module's name for
209             use as a class name - so:
210              
211             my $json_obj = JSON()->new; # returns a Cpanel::JSON::XS or JSON::PP object
212              
213             and that object can then be used normally:
214              
215             my $data_structure = $json_obj->decode($json_text); # etc.
216              
217             The use of parentheses here is optional, and only used as a hint to the reader
218             that this use of C is a I call, I a class name.
219              
220             =head2 is_bool
221              
222             $is_boolean = is_bool($scalar)
223              
224             Returns true if the passed scalar represents either C or
225             C, two constants that act like C<1> and C<0>, respectively
226             and are used to represent JSON C and C values in Perl.
227              
228             Since this is a bare sub in the various backend classes, it cannot be called as
229             a class method like the other interfaces; it must be called as a function, with
230             no invocant. It supports the representation used in all JSON backends.
231              
232             Available since version 1.002004.
233              
234             =head1 CONSTRUCTOR
235              
236             =head2 new
237              
238             With L, L and L you are required to call
239             mutators to set options, such as:
240              
241             my $json = $class->new->utf8(1)->pretty(1);
242              
243             Since this is a trifle irritating and noticeably un-perlish, we also offer:
244              
245             my $json = JSON::MaybeXS->new(utf8 => 1, pretty => 1);
246              
247             which works equivalently to the above (and in the usual tradition will accept
248             a hashref instead of a hash, should you so desire).
249              
250             The resulting object is blessed into the underlying backend, which offers (at
251             least) the methods C and C.
252              
253             =head1 BOOLEANS
254              
255             To include JSON-aware booleans (C, C) in your data, just do:
256              
257             use JSON::MaybeXS;
258             my $true = JSON()->true;
259             my $false = JSON()->false;
260              
261             The booleans are also available as subs or methods on JSON::MaybeXS.
262              
263             use JSON::MaybeXS ();
264             my $true = JSON::MaybeXS::true;
265             my $true = JSON::MaybeXS->true;
266             my $false = JSON::MaybeXS::false;
267             my $false = JSON::MaybeXS->false;
268              
269             =head1 CONVERTING FROM JSON::Any
270              
271             L used to be the favoured compatibility layer above the various
272             JSON backends, but over time has grown a lot of extra code to deal with legacy
273             backends (e.g. L) that are no longer needed. This is a rough guide of translating such code:
274              
275             Change code from:
276              
277             use JSON::Any;
278             my $json = JSON::Any->new->objToJson($data); # or to_json($data), or Dump($data)
279              
280             to:
281              
282             use JSON::MaybeXS;
283             my $json = encode_json($data);
284              
285              
286             Change code from:
287              
288             use JSON::Any;
289             my $data = JSON::Any->new->jsonToObj($json); # or from_json($json), or Load($json)
290              
291             to:
292              
293             use JSON::MaybeXS;
294             my $json = decode_json($data);
295              
296             =head1 CAVEATS
297              
298             The C method in this module is technically a factory, not a
299             constructor, because the objects it returns will I be blessed into the
300             C class.
301              
302             If you are using an object returned by this module as a Moo(se) attribute,
303             this type constraint code:
304              
305             is 'json' => ( isa => 'JSON::MaybeXS' );
306              
307             will I do what you expect. Instead, either rely on the C class
308             constant described above, as so:
309              
310             is 'json' => ( isa => JSON::MaybeXS::JSON() );
311              
312             Alternatively, you can use duck typing:
313              
314             use Moose::Util::TypeConstraints 'duck_type';
315             is 'json' => ( isa => Object , duck_type([qw/ encode decode /]));
316              
317             =head1 INSTALLATION
318              
319             At installation time, F will attempt to determine if you have a
320             working compiler available, and therefore whether you are able to run XS code.
321             If so, L will be added to the prerequisite list, unless
322             L is already installed at a high enough version. L may
323             also be upgraded to fix any incompatibility issues.
324              
325             Because running XS code is not mandatory and L (which is in perl
326             core) is used as a fallback backend, this module is safe to be used in a suite
327             of code that is fatpacked or installed into a restricted-resource environment.
328              
329             You can also prevent any XS dependencies from being installed by setting
330             C in F options (or in the C
331             environment variable), or using the C<--pp> or C<--pureperl> flags with the
332             L.
333              
334             =head1 AUTHOR
335              
336             mst - Matt S. Trout (cpan:MSTROUT)
337              
338             =head1 CONTRIBUTORS
339              
340             =over 4
341              
342             =item * Clinton Gormley
343              
344             =item * Karen Etheridge
345              
346             =item * Kieren Diment
347              
348             =back
349              
350             =head1 COPYRIGHT
351              
352             Copyright (c) 2013 the C L and L
353             as listed above.
354              
355             =head1 LICENSE
356              
357             This library is free software and may be distributed under the same terms
358             as perl itself.
359              
360             =cut