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,
2
Answers
Blessed Perl objects can’t be stored in JSON without extra steps (mentioned by the error).
A possible workaround:
The
$^V
variable is really an objectAn object cannot be stored in JSON just so. Quoting it stringifies it.
It is possible to make
JSON::XS
(and itsCpanel::
) take a blessed reference but it involves more work. See Object Serialization. The cleanest complete solution is with convert_blessed, when theencode
method will look for aTO_JSON
method (in the class of the object that is to be added to JSON), which would return a JSON-ready string.Alas, there is no such a thing for the
version
(nor for a few other classes I tried, likeDateTime
). One can add that method to the class† but just thinking of it makes quotes look nice.Another way is to get explicit in making the
version
object stringifyThis is yet more elaborate but at least now it’s clear what the matter is, without magic quotes.
Or just quote it and add a comment.
† By "monkey-patching" it, for example
add the sub, with a fully qualified name
Can also add a sub via string
eval
at runtime but that doesn’t seem needed.write the code reference to the class’s symbol table at runtime
well, or really with
strict
in effect we need to allow the symbolic refswhere I also added variables for class name and method, not necessary but better.
This is packaged for far nicer use in Sub::Install
There are expected defaults and a bit more in the module.
Or, of course by writing a wrapper class or some such but that’s something yet else.