For some Perl diagnostic tests, I'm recording assorted bits of information formatted as JSON using JSON::MaybeXS.
I get an error when I want to record the current Perl version, which I obtain from the special variable $^V.
As the minimal demonstration script shows, the error occurs unless I quote $^V as "$^V".
json_perl_version_test.pl
#!/usr/bin/env perl
use strict;
use warnings;
use v5.18;
use JSON::MaybeXS;
say "Running Perl version $^V";
my $item = 'Wut?';
my %hash1 = (
something => $item,
v_unquoted => $^V
);
eval { say say 'Hash1: ', encode_json \%hash1 };
say "Oops - JSON encode error: $@" if $@;
my %hash2 = (
something => $item,
v_quoted => "$^V"
);
say 'Hash2: ', encode_json \%hash2;
# Running Perl version v5.34.0
# Oops - JSON encode error: encountered object 'v5.34.0',
# but neither allow_blessed, convert_blessed nor allow_tags
# settings are enabled (or TO_JSON/FREEZE method missing) at
# /Users/bw/Documents/Dev/tests/json_perl_version_test.pl line 17.
# Hash2: {"something":"Wut?","v_quoted":"v5.34.0"}
Note that it wasn't necessary to quote $item.
The error message refers to some ways to handle other cases, but seemingly not including canonical Perl version dotted-decimal strings. I've looked through the main Perl JSON modules (recent versions of JSON::MaybeXS, JSON, and Cpanel::JSON::XS), but can't find anything referring to $^V or dotted-decimal strings. Also don't find a relevant question on SO :(.
Perhaps I'm missing something? Or am I stuck with needing to quote $^V?
Reasons?
Thanks,
CodePudding user response:
The $^V variable is really an object
The revision, version, and subversion of the Perl interpreter, represented as a version object.
That cannot be stored in JSON as an object. Quoting it stringifies it.
It is possible to make JSON::XS (and its Cpanel::) take a blessed reference but it likely involves far more work. See Object Serialization. The cleanest complete solution is with convert_blessed, when the encode method will look for a TO_JSON method (in the object to be added to JSON), which would return a JSON ready string.
Alas, there is no such a thing for version (nor for a few other classes I tried, like DateTime). Presumably one can add that method but thinking of that makes mere quotes look nice.
Another way is to get really explicit in making the version object stringify
my $json = JSON::XS->new->encode( { ver => $^V->stringify } )
This is yet more elaborate but at least now it's clear what's the matter, without magic quotes.
Or just quote it and add a comment.
CodePudding user response:
Blessed Perl objects can't be stored in JSON without extra steps (mentioned by the error).
print ref $^V; # version
A possible workaround:
my $j = Cpanel::JSON::XS->new->convert_blessed; # Allow stringification.
say 'Hash1: ', $j->encode(\%hash1);
