summaryrefslogtreecommitdiff
path: root/lib/JSON/Dumper/Compact.pm
blob: ee9d07e2e22b0eb197600927d82d7391c0d3eb7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package JSON::Dumper::Compact;

use JSON::MaybeXS;
use Mu;
use strictures 2;
use namespace::clean;

our $VERSION = '0.004001';
$VERSION =~ tr/_//d;

extends 'Data::Dumper::Compact';

lazy json_obj => sub {
  JSON->new
      ->allow_nonref(1)
      ->relaxed(1)
      ->filter_json_single_key_object(__bless__ => sub {
          bless($_[0][1], $_[0][0]);
        });
}, handles => { _json_decode => 'decode' };

sub _build_dumper { my $j = shift->json_obj; sub { $j->encode($_[0]) } }

sub _format_el { shift->_format(@_).',' }

sub _format_hashkey { $_[0]->json_obj->encode($_[1]).':' }

sub _format_string { '"'.$_[1].'"' }

sub _format_thing { $_[1] }

around _expand_blessed => sub {
  my ($orig, $self) = (shift, shift);
  my ($blessed) = @_;
  return $self->expand($blessed->TO_JSON) if $blessed->can('TO_JSON');
  return $self->$orig(@_);
};

sub _format_blessed {
  my ($self, $payload) = @_;
  my ($content, $class) = @$payload;
  $self->_format([ hash => [
    [ '__bless__' ],
    { '__bless__' => [ array => [ [ string => $class ], $content ] ] },
  ] ]);
}

sub encode { shift->dump(@_) }

sub decode {
  my ($self, $data, $opts) = @_;
  $self->_optify($opts, _json_decode => $data);
}

1;

=head1 NAME

JSON::Dumper::Compact - JSON processing with L<Data::Dumper::Compact> aesthetics

=head1 SYNOPSIS

  use JSON::Dumper::Compact 'jdc';
  
  my $json = jdc($data);

=head1 DESCRIPTION

JSON::Dumper::Compact is a subclass of L<Data::Dumper::Compact> that turns
arrayrefs and hashrefs intead into JSON.

Deep data structures are rendered highly compactly:

  [
    "1556933590.65383", "Fri May  3 18:33:10 2019", 26794, "INFO", 3,
    [ "SRV:8FB66F32" ], [ [
        "/opt/voice-srvc-native/bin/async-srvc-att-gateway-poller", 33,
        "NERV::Voice::SRV::Native::AsyncSRVATTGatewayPoller::main",
    ] ],
    "batch_nena_messages returned", "OK", 6, { "FILENAME": "lqxw020323" },
    1556933584, "lqxw020323",
  ]

To ease debugging, blessed references without a C<TO_JSON> method are
rendered as an object with a single two-element arrayref value:

  { "__bless__": [
    "The::Class",
    { "the": "object" },
  ] }

=head1 METHODS

In addition to the L<Data::Dumper::Compact> methods, we provide:

=head2 encode

  JSON::Dumper::Compact->encode($data, \%opts?);
  $jdc->encode($data, \%opts?);

Operates identically to L<Data::Dumper::Compact/dump> but named to be less
confusing to code expecting a JSON object.

=head2 decode

  JSON::Dumper::Compact->decode($string, \%opts?);
  $jdc->decode($string, \%opts);

Runs the supplied string through an L<JSON::MaybeXS> C<decode> with options
set to be able to reliably reparse what we can currently format - notably
setting C<relaxed> to allow for trailing commas and using
C<filter_json_single_key_object> to re-inflate blessed objects.

Note that using this method on untrusted data is a security risk. While
C<encode>/C<dump> should be usable for JSON formatting, in general,
C<decode> fully rehydrates for debugging purposes and as such can e.g.
cause DESTROY methods to be called unexpectedly, which can allow a
malicious user to do things to your perl5 VM. Rather than using
debugging specific code on untrusted data, use L<JSON::MaybeXS> or
L<Mojo::JSON> directly (if the C<encode> output doesn't parse correctly
via other libraries, please report that as a bug)..

DO NOT USE THIS METHOD ON UNTRUSTED DATA IT WAS NOT DESIGNED TO BE SECURE.

=head1 COPYRIGHT

Copyright (c) 2019 the L<Data::Dumper::Compact/AUTHOR> and
L<Data::Dumper::Compact/CONTRIBUTORS> as listed in L<Data::Dumper::Compact>.

=head1 LICENSE

This library is free software and may be distributed under the same terms
as perl itself. See L<https://dev.perl.org/licenses/>.

=cut