File Coverage

blib/lib/JSON/Eval.pm
Criterion Covered Total %
statement 67 75 89.3
branch 25 36 69.4
condition 20 30 66.6
subroutine 10 11 90.9
pod 5 5 100.0
total 127 157 80.8


line stmt bran cond sub pod time code
1 1     1   633 use 5.008006;
  1         3  
2 1     1   4 use strict;
  1         2  
  1         17  
3 1     1   5 use warnings;
  1         1  
  1         125  
4              
5             my $safe_eval = sub {
6             package main;
7             local $@;
8             my $r = eval $_[0];
9             return $r unless $@;
10             package JSON::Eval;
11             require Carp;
12             Carp::croak($@);
13             };
14              
15             package JSON::Eval;
16              
17             our $AUTHORITY = 'cpan:TOBYINK';
18             our $VERSION = '0.002';
19              
20 1     1   6 use Scalar::Util qw(blessed);
  1         2  
  1         722  
21              
22             sub new {
23 1     1 1 426 my $class = shift;
24 1 50       3 my $json = @_ ? $_[0] : do { require JSON::MaybeXS; JSON::MaybeXS->new };
  1         5  
  1         3  
25 1         13 bless \$json, $class;
26             }
27              
28             sub AUTOLOAD {
29 1     1   17 my $self = shift;
30 1         3 our $AUTOLOAD;
31 1         5 ( my $method = $AUTOLOAD ) =~ s/.*:://;
32 1         7 my $r = $$self->$method(@_);
33 1 50       11 return $self if $r == $$self;
34 0         0 $r;
35             }
36              
37             sub decode {
38 1     1 1 582 my $self = shift;
39 1         11 my $o = $$self->decode(@_);
40 1         2 $self->eval_object($o);
41             }
42              
43             sub encode {
44 1     1 1 30 my $self = shift;
45 1         3 my $o = $self->deparse_object(@_);
46 1         24 $$self->encode($o);
47             }
48              
49             sub eval_object {
50 17     17 1 21 my $self = shift;
51 17         19 my ($o) = @_;
52 17 100 100     54 if (ref $o eq 'HASH' and keys(%$o)==1 and exists $o->{'$eval'}) {
      100        
53 4         7 return $safe_eval->($o->{'$eval'});
54             }
55 13 50 100     34 if (ref $o eq 'HASH' and keys(%$o)==1 and exists $o->{'$scalar'}) {
      66        
56 5         10 my $x = $self->eval_object($o->{'$scalar'});
57 5         12 return \$x;
58             }
59 8 100       12 if (ref $o eq 'ARRAY') {
60 3         3 local $_;
61 3 50       19 return [ map(ref($_)?$self->eval_object($_):$_, @$o) ];
62             }
63 5 100       9 if (ref $o eq 'HASH') {
64 1         1 local $_;
65 1 50       3 return { map { $_ => ref($o->{$_})?$self->eval_object($o->{$_}):$o->{$_} } keys %$o };
  3         9  
66             }
67 4         5 $o;
68             }
69              
70             sub deparse_object {
71 18     18 1 25 my $self = shift;
72 18         20 my ($o) = @_;
73 18 100       33 if (ref $o eq 'CODE') {
74 3         405 require PadWalker;
75 3         867 my $lexicals = PadWalker::closed_over($o);
76 3 50       9 if (keys %$lexicals) {
77 0         0 require Carp;
78 0         0 Carp::croak("Cannot serialize coderef that closes over lexical variables to JSON: ".join ",", sort keys %$lexicals);
79             }
80 3         10 require B::Deparse;
81 3         81 my $dp = 'B::Deparse'->new;
82 3         89 $dp->ambient_pragmas(strict => 'all', warnings => 'all');
83 3         1099 return { '$eval' => 'sub ' . $dp->coderef2text($o) };
84             }
85 15 100       22 if (ref $o eq 'ARRAY') {
86 3         3 local $_;
87 3 50       12 return [ map(ref($_)?$self->deparse_object($_):$_, @$o) ];
88             }
89 12 100 100     29 if (ref $o eq 'SCALAR' or ref $o eq 'REF') {
90 5         7 local $_;
91 5         10 return { '$scalar' => $self->deparse_object($$o) };
92             }
93 7 100       10 if (ref $o eq 'HASH') {
94 2         27 local $_;
95 2 100       9 return { map { $_ => ref($o->{$_})?$self->deparse_object($o->{$_}):$o->{$_} } keys %$o };
  4         28  
96             }
97 5 50 66     30 if (blessed($o) and $o->isa('Type::Tiny')) {
98 0 0 0     0 if ($o->has_library and not $o->is_anon and $o->library->has_type($o->name)) {
      0        
99 0         0 require B;
100 0         0 return { '$eval' => sprintf('do { require %s; %s->get_type(%s) }', $o->library, B::perlstring($o->library), B::perlstring($o->name)) };
101             }
102             else {
103 0         0 require Carp;
104 0         0 Carp::croak('Very limited support for serializing Type::Tiny objects right now');
105             }
106             }
107 5 50 66     16 if (blessed($o) and $self->convert_blessed and $o->can('TO_JSON')) {
      66        
108 1         4 my $unblessed = $o->TO_JSON;
109 1         5 return $self->deparse_object($unblessed);
110             }
111 4         13 $o;
112             }
113              
114       0     sub DESTROY { }
115              
116             1;
117              
118             __END__