如何通过扩展正在使用的 class 来扩展模块?

How to extend a module by extending a class that it is using?

一些背景: 我想在 Perl 5 中扩展 JSON::Tiny to allow for more relaxed parsing of lists. This is similar to the relaxed flag for JSON::XS。具体来说,我希望可以选择在列表末尾放置一个逗号。例如,{ "a" : 1, "b" : 2, }。注意 2 后的逗号,这是正常的 JSON 语法规范(或 JSON::Tiny)所不允许的。

通过检查 source code it seems this could be as simple as extending one of the modules, JSON::Tiny::GrammarJSON::Tiny 正在内部使用,然后覆盖它的两个规则:

grammar JSON::Relaxed::Grammar is JSON::Tiny::Grammar {
    rule pairlist   { <pair> * %% \,            } # override this rule
    rule arraylist  {  <value> * %% [ \, ]        } #overide this rule
}

请注意,对 JSON::Tiny::Grammar 的唯一修改是 为 pairlistarraylist 规则引入 %% 运算符而不是 % 运算符。

这样的扩展将允许代码 重用。 (复制 JSON::Tiny 中的所有代码的替代方案是最后的选择。)

问题:现在的问题是我应该如何在不修改或复制JSON::Tiny代码的情况下创建我的扩展(称为JSON::Relaxed)?这是我要编写的模块的草图:

unit module JSON::Relaxed;
use v6;

use JSON::Tiny; # <-- since it is a module, I cannot extend it like a class

# a) export all the stuff that JSON::Tiny exports to the caller
# b) Somehow make JSON::Tiny use JSON::Relaxed::Grammar instead of JSON::Tiny::Grammar

实现上面评论中的 a) 和 b) 的最佳方法是什么?

您可以像这样分别引入语法和动作:

use JSON::Tiny::Grammar;
use JSON::Tiny::Actions;

然后像问题中一样推导出自己的语法。

使用生成的语法和现有的操作 class,您将得到

JSON::Relaxed::Grammar.parse($input, :actions(JSON::Tiny::Actions)).ast

请注意,在 META6.json you can find the provides section 中可以准确地告诉您可以做什么 use

由于您想从 JSON::Tiny 中获取原始 to-json,因此您必须导出转发到原始文件的 to-json。这是执行此操作的代码:

sub to-json(|c) is export {
    use JSON::Tiny;
    to-json(|c);
}

这将使来自 JSON::Tiny 的符号仅在您的 to-json 函数的词法范围内可用,它将只接受其所有参数并使用它们调用原始 to-json 函数.