NAME

JSON::PP::Monkey - JSON::PP with encoding fallbacks

VERSION

version 0.1.0

SYNOPSIS

use JSON::PP::Monkey;

my $json = JSON::PP::Monkey->new->utf8->pretty
             ->allow_blessed->add_fallback('blessed', sub { +{ __BLESSED_ => "$_[1]" } })
             ->allow_unknown->add_fallback('unknown', sub { +{ __UNKNOWN_ => "$_[1]" } })

$json->encode({ active => \1, io => \*STDOUT, foo => bless({}, 'foo')});
# {
#    "foo" : {
#       "__BLESSED_" : "foo=HASH(0x7fda11bc0fc8)"
#    },
#    "active" : true,
#    "io" : {
#       "__UNKNOWN_" : "GLOB(0x7fda11029518)"
#    }
# }

DESCRIPTION

This is an experiment with a JSON encoder that can apply fallback conversions to blessed objects and unknowns.

The primary reason it has been created was to allow dumping arbitrary Perl data into JSON.

CAVEATS

REVISED API

Unlike JSON::PP, JSON::XS, Cpanel::JSON::XS, "allow_blessed" must be enabled before blessed objects can be converted to JSON by invoking TO_JSON or stringifying bignums.

# { "x": <JSON encoding of $foo->TO_JSON> }
JSON::PP::Monkey->new->allow_blessed->convert_blessed->encode({x => $foo});

# dies - allow_blessed is not enabled
JSON::PP::Monkey->new->convert_blessed->encode({x => $foo});

# { "x": "999" }
JSON::PP::Monkey->new->allow_blessed->convert_bignum->encode({x => Math::BigInt->new('999')});

# dies - allow_blessed is not enabled
JSON::PP::Monkey->new->convert_bignum->encode({x => $foo});

Another difference is that the fallback conversion of objects into 'null' must be disabled explicitly (with "collapse_blessed") if it is unwanted. So

JSON::PP::Monkey->new->allow_blessed->collapse_blessed(0)->convert_blessed;

is the equivalent of

JSON::PP->new->convert_blessed;

in the sense they will convert objects with TO_JSON methods into JSON and bail on everything else.

The behavior of "allow_unknown" and "collapse_unknown" is analogous.

These API changes have been made to provide a more consistent behavior.

  • if objects will be encoded, allow_blessed must be enabled before any fallback (installed with "add_fallback", "convert_blessed", or "convert_bignum") can be applied.

  • if objects will be encoded but the fallback conversion into "null" is unwanted, it should be disabled with "collapse_blessed".

  • if unknowns will be encoded, allow_unknown must be enabled before any fallback can be applied

  • if unknowns will be encoded but the fallback conversion into "null" is unwanted, it should be disabled with "collapse_unknown".

FALLBACK ORDER

Notice that the order of fallbacks is important:

$json = JSON::PP->new->utf8->allow_blessed->convert_bignum->convert_blessed;

will apply stringification to bignums before trying to check for TO_JSON methods. While

$json = JSON::PP->new->utf8->allow_blessed->convert_blessed->convert_bignum;

will check for TO_JSON methods (and apply them) before considering the stringification of bignums.

METHODS

allow_blessed

$json = $json->allow_blessed;
$json = $json->allow_blessed($enable);

If enabled, allows to encode blessed references (or objects) via the current 'blessed' fallbacks or into 'null' (if "collapse_blessed" is enabled).

Defaults to disabled.

allow_unknown

$json = $json->allow_unknown;
$json = $json->allow_unknown($enable);

If enabled, allows to encode unknown references via the current 'unknown' fallbacks or into 'null' (if "collapse_unknown" is enabled).

Defaults to disabled.

collapse_blessed

$json = $json->collapse_blessed;
$json = $json->collapse_blessed($enable);

If "allow_blessed" is enabled, an object is encoded into 'null' if no 'blessed' fallback applied.

Defaults to enabled. Only has effect if "allow_blessed" is enabled.

collapse_unknown

$json = $json->collapse_unknown;
$json = $json->collapse_unknown($enable);

If "allow_unknown" is enabled, an unknown is encoded into 'null' if no 'unknown' fallback applied.

Defaults to enabled. Only has effect if "allow_unknown" is enabled.

convert_blessed

$json = $json->convert_blessed;

Add a "blessed" fallback which applies to objects which have a "TO_JSON" method. Equivalent to

$json = $json->add_fallback('blessed', sub {
    return unless $_[1]->can('TO_JSON');
    return $_[1]->TO_JSON;
});

Only has effect if "allow_blessed" is enabled.

convert_bignum

$json = $json->convert_bignum;

Add a "blessed" fallback which applies to objects which are Math::BigInt or Math::BigFloat. Equivalent to

$json = $json->add_fallback('blessed', sub {
    return unless $_[1]->isa('Math::BigInt') || $_[1]->isa('Math::BigFloat');
    return "$_[1]"
});

Only has effect if "allow_blessed" is enabled.

add_fallback

$json = $json->add_fallback('blessed', $cb);
$json = $json->add_fallback('unknown', $cb);

Add fallback conversions to be applied if:

a blessed ref is found and "allow_blessed" is enabled
an unknown is found and "allow_unknown" is enabled

$case should be one of 'blessed' or 'unknown'.

$cb is a subroutine which expects two arguments

sub {
    my ($json, $item, $case) = (shift, shift);
    ...
}

Fallback subroutines are evaluated in list context. Their return is interpreted as below.

  • a non-empty list means the first element converted to JSON will be the encoding result

  • an empty list means the fallback did not match, and the next one should be tried

remove_fallback

$json = $json->remove_fallback($case, $cb);

AUTHOR

Adriano Ferreira <ferreira@cpan.org>

CONTRIBUTOR

Adriano Ferreira <a.r.ferreira@gmail.com>

COPYRIGHT AND LICENSE

This software is copyright (c) 2017 by Adriano Ferreira.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.