Data-Dumper-Compact/lib/JSON/Dumper/Compact.pm
package JSON::Dumper::Compact;
use JSON::MaybeXS;
use Mu::Tiny;
use Class::Method::Modifiers;
our $VERSION = '0.006000';
$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]);
});
};
sub _json_decode { shift->json_obj->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 _format_ref {
my ($self, $payload) = @_;
my %subst = ('/' => '~1', '~' => '~0');
my @path = map { (my $x = $_->[1]) =~ s{[/~]}{$subst{$_}}eg; $x } @$payload;
return $self->format([ hash => [
[ '$ref' ],
{ '$ref' => [ string => join('/', '#', @path) ] },
] ]);
}
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