File Coverage

blib/lib/JSON/YY.pm
Criterion Covered Total %
statement 78 82 95.1
branch 13 16 81.2
condition 7 16 43.7
subroutine 22 24 91.6
pod 8 8 100.0
total 128 146 87.6


line stmt bran cond sub pod time code
1             package JSON::YY;
2              
3 14     14   1354828 use strict;
  14         22  
  14         456  
4 14     14   54 use warnings;
  14         22  
  14         747  
5 14     14   92 use Carp;
  14         20  
  14         4888  
6              
7             our $VERSION = '0.02';
8              
9             require XSLoader;
10             XSLoader::load('JSON::YY', $VERSION);
11              
12             our @EXPORT_OK = qw(encode_json decode_json decode_json_ro);
13              
14             my @DOC_KEYWORDS = qw(jdoc jget jgetp jset jdel jhas jclone jencode
15             jstr jnum jbool jnull jarr jobj jtype jlen jkeys jdecode
16             jiter jnext jkey jpatch jmerge jfrom jvals jeq
17             jpp jraw jread jwrite jpaths jfind
18             jis_obj jis_arr jis_str jis_num jis_int jis_real jis_bool jis_null);
19              
20             # functional API — fast XS path, always utf8
21             *encode_json = \&_xs_encode_json;
22             *decode_json = \&_xs_decode_json;
23             *decode_json_ro = \&_xs_decode_json_ro;
24              
25             my %SETTERS = (
26             utf8 => \&_set_utf8,
27             pretty => \&_set_pretty,
28             canonical => \&_set_canonical,
29             allow_nonref => \&_set_allow_nonref,
30             allow_unknown => \&_set_allow_unknown,
31             allow_blessed => \&_set_allow_blessed,
32             convert_blessed => \&_set_convert_blessed,
33             max_depth => \&_set_max_depth,
34             );
35              
36             sub import {
37 21     21   478 my $class = shift;
38 21         34 my @exports;
39             my @flags;
40 21         29 my $want_doc = 0;
41 21         51 for my $arg (@_) {
42 33 100       120 if ($arg eq ':doc') {
    100          
43 9         43 $want_doc = 1;
44             } elsif ($arg =~ /^-(.+)/) {
45 2         11 push @flags, $1;
46             } else {
47 22         83 push @exports, $arg;
48             }
49             }
50 21         94 my $caller = caller;
51 21 100       97 if ($want_doc) {
52 14     14   104 no strict 'refs';
  14         26  
  14         1822  
53 9         19 for my $kw (@DOC_KEYWORDS) {
54 360         424 *{"${caller}::${kw}"} = \&{"_xs_${kw}"};
  360         973  
  360         549  
55             }
56             }
57 21 100       45 if (@flags) {
58 1         3 my $coder = $class->new;
59 1         2 for my $f (@flags) {
60 2 50       4 my $setter = $SETTERS{$f}
61             or Carp::croak("unknown flag: -$f");
62 2         5 $coder->$setter(1);
63             }
64 14     14   68 no strict 'refs';
  14         22  
  14         1488  
65 1     1   3 *{"${caller}::encode_json"} = sub { $coder->encode($_[0]) };
  1         4  
  1         155048  
66 1     1   3 *{"${caller}::decode_json"} = sub { $coder->decode($_[0]) };
  1         2  
  1         851  
67             }
68 21 100       125401 if (@exports) {
69 14     14   88 no strict 'refs';
  14         45  
  14         5201  
70 11         14 for my $e (@exports) {
71             Carp::croak("'$e' is not exported by JSON::YY")
72 22 50       32 unless grep { $_ eq $e } @EXPORT_OK;
  66         170  
73 22         21 *{"${caller}::$e"} = \&{$e};
  22         84192  
  22         52  
74             }
75             }
76             }
77              
78             # chaining setters
79 10   50 10 1 52 sub utf8 { $_[0]->_set_utf8($_[1] // 1); $_[0] }
  10         26  
80 3   50 3 1 17 sub pretty { $_[0]->_set_pretty($_[1] // 1); $_[0] }
  3         46  
81 0   0 0 1 0 sub canonical { $_[0]->_set_canonical($_[1] // 1); $_[0] }
  0         0  
82 2   100 2 1 8 sub allow_nonref { $_[0]->_set_allow_nonref($_[1] // 1); $_[0] }
  2         3  
83 0   0 0 1 0 sub allow_unknown { $_[0]->_set_allow_unknown($_[1] // 1); $_[0] }
  0         0  
84 1   50 1 1 6 sub allow_blessed { $_[0]->_set_allow_blessed($_[1] // 1); $_[0] }
  1         2  
85 1   50 1 1 6 sub convert_blessed { $_[0]->_set_convert_blessed($_[1] // 1); $_[0] }
  1         2  
86 2   50 2 1 13 sub max_depth { $_[0]->_set_max_depth($_[1] // 512); $_[0] }
  2         4  
87              
88             # wrap XS new to accept keyword args
89             {
90             my $orig_new = JSON::YY->can('new');
91 14     14   76 no warnings 'redefine';
  14         23  
  14         3681  
92             *new = sub {
93 16     16   636701 my ($class, %args) = @_;
94 16         168 my $self = $orig_new->($class);
95 16         47 for my $k (keys %args) {
96 8 50       28 my $setter = $SETTERS{$k}
97             or Carp::croak("unknown option: $k");
98 8         28 $self->$setter($args{$k});
99             }
100 16         62 $self;
101             };
102             }
103              
104             # Doc overloading: stringify to JSON, boolean always true, eq/ne deep compare
105             package JSON::YY::Doc;
106             use overload
107 2     2   173171 '""' => sub { JSON::YY::_doc_stringify($_[0]) },
108 1     1   77 'bool' => sub { 1 },
109 1     1   7 'eq' => sub { JSON::YY::_doc_eq($_[0], $_[1]) },
110 1     1   6 'ne' => sub { !JSON::YY::_doc_eq($_[0], $_[1]) },
111 14     14   6576 fallback => 1;
  14         16967  
  14         174  
112              
113             package JSON::YY;
114             1;
115              
116             __END__