为什么需要为 JSON 编码引用 Perl 版本字符串?
Why is it necessary to quote Perl version string for JSON encoding?
对于一些 Perl 诊断测试,我使用 JSON::MaybeXS.
记录格式为 JSON 的各种信息位
当我想记录当前的 Perl 版本时出错,这是我从特殊变量 $^V 获得的。
如最小演示脚本所示,除非我将 $^V 引用为“$^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"}
请注意,没有必要引用 $item。
错误消息提到了一些处理其他情况的方法,但似乎不包括规范的 Perl 版本点分十进制字符串。我查看了主要的 Perl JSON 模块(JSON::MaybeXS、JSON 和 Cpanel::JSON::XS 的最新版本),但找不到任何引用 $^V 或点分十进制字符串。也没有在 SO 上找到相关问题 :(.
也许我遗漏了什么?还是我坚持需要引用 $^V?
原因?
谢谢,
如果没有额外的步骤(错误中提到),Blessed Perl 对象无法存储在 JSON 中。
print ref $^V; # version
可能的解决方法:
my $j = Cpanel::JSON::XS->new->convert_blessed; # Allow stringification.
say 'Hash1: ', $j->encode(\%hash1);
$^V
variable确实是一个对象
The revision, version, and subversion of the Perl interpreter, represented as a version object.
对象无法存储在 JSON 中。引用它会把它字符串化。
可以使 JSON::XS
(及其 Cpanel::
)成为一个有福的引用,但它需要更多的工作。见Object Serialization. The cleanest complete solution is with convert_blessed,当encode
方法会寻找一个TO_JSON
方法(在要添加到JSON的对象的class中),这会 return 一个 JSON-ready 字符串。
唉,version
没有这样的东西(我试过的其他一些 classes 也没有,比如 DateTime
)。可以将该方法添加到 class†,但仅考虑它会使引号看起来不错。
另一种方法是明确地使 version
对象字符串化
my $json = JSON::XS->new->encode( { ver => $^V->stringify } )
这更加详尽,但至少现在很清楚问题是什么,没有魔法引号。
或者只是引用它并添加评论。
†通过“monkey-patching”吧,比如
添加具有完全限定名称的子
perl -Mstrict -wE'use JSON::XS; say $^V;
sub version::TO_JSON { return $_[0]->stringify };
my $json = JSON::XS->new->convert_blessed->encode( { ver => $^V } );
say $json'
也可以在运行时通过字符串 eval
添加子项,但这似乎不需要。
在运行时将代码引用写入 class 的符号 table
perl -wE'use JSON::XS; say $^V;
*{"version"."::"."TO_JSON"} = sub { return $_[0]->stringify };
$json = JSON::XS->new->convert_blessed->encode( { ver => $^V } );
say $json'
好吧,或者实际上 strict
我们需要允许符号引用
perl -Mstrict -wE'use JSON::XS; say $^V;
NO_STRICT_REFS: {
no strict "refs";
my ($class, $method) = qw(version TO_JSON);
*{$class."::".$method} = sub { return $_[0]->stringify }
};
my $json = JSON::XS->new->convert_blessed->encode( { ver => $^V } );
say $json'
我还为 class 名称和方法添加了变量,这不是必需的,但更好。
这是为了在 Sub::Install
中更好地使用而打包
use Sub::Install;
Sub::Install::install_sub({
code => sub { ... }, into => $package, as => $subname
});
模块中有预期的默认值和更多内容。
或者,当然是通过编写包装器 class 或类似的东西,但那是另外一回事。
对于一些 Perl 诊断测试,我使用 JSON::MaybeXS.
记录格式为 JSON 的各种信息位当我想记录当前的 Perl 版本时出错,这是我从特殊变量 $^V 获得的。
如最小演示脚本所示,除非我将 $^V 引用为“$^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"}
请注意,没有必要引用 $item。
错误消息提到了一些处理其他情况的方法,但似乎不包括规范的 Perl 版本点分十进制字符串。我查看了主要的 Perl JSON 模块(JSON::MaybeXS、JSON 和 Cpanel::JSON::XS 的最新版本),但找不到任何引用 $^V 或点分十进制字符串。也没有在 SO 上找到相关问题 :(.
也许我遗漏了什么?还是我坚持需要引用 $^V?
原因?
谢谢,
如果没有额外的步骤(错误中提到),Blessed Perl 对象无法存储在 JSON 中。
print ref $^V; # version
可能的解决方法:
my $j = Cpanel::JSON::XS->new->convert_blessed; # Allow stringification.
say 'Hash1: ', $j->encode(\%hash1);
$^V
variable确实是一个对象
The revision, version, and subversion of the Perl interpreter, represented as a version object.
对象无法存储在 JSON 中。引用它会把它字符串化。
可以使 JSON::XS
(及其 Cpanel::
)成为一个有福的引用,但它需要更多的工作。见Object Serialization. The cleanest complete solution is with convert_blessed,当encode
方法会寻找一个TO_JSON
方法(在要添加到JSON的对象的class中),这会 return 一个 JSON-ready 字符串。
唉,version
没有这样的东西(我试过的其他一些 classes 也没有,比如 DateTime
)。可以将该方法添加到 class†,但仅考虑它会使引号看起来不错。
另一种方法是明确地使 version
对象字符串化
my $json = JSON::XS->new->encode( { ver => $^V->stringify } )
这更加详尽,但至少现在很清楚问题是什么,没有魔法引号。
或者只是引用它并添加评论。
†通过“monkey-patching”吧,比如
添加具有完全限定名称的子
perl -Mstrict -wE'use JSON::XS; say $^V; sub version::TO_JSON { return $_[0]->stringify }; my $json = JSON::XS->new->convert_blessed->encode( { ver => $^V } ); say $json'
也可以在运行时通过字符串
eval
添加子项,但这似乎不需要。在运行时将代码引用写入 class 的符号 table
perl -wE'use JSON::XS; say $^V; *{"version"."::"."TO_JSON"} = sub { return $_[0]->stringify }; $json = JSON::XS->new->convert_blessed->encode( { ver => $^V } ); say $json'
好吧,或者实际上
strict
我们需要允许符号引用perl -Mstrict -wE'use JSON::XS; say $^V; NO_STRICT_REFS: { no strict "refs"; my ($class, $method) = qw(version TO_JSON); *{$class."::".$method} = sub { return $_[0]->stringify } }; my $json = JSON::XS->new->convert_blessed->encode( { ver => $^V } ); say $json'
我还为 class 名称和方法添加了变量,这不是必需的,但更好。
这是为了在 Sub::Install
中更好地使用而打包use Sub::Install; Sub::Install::install_sub({ code => sub { ... }, into => $package, as => $subname });
模块中有预期的默认值和更多内容。
或者,当然是通过编写包装器 class 或类似的东西,但那是另外一回事。