我正在尝试基于两个命名元组的合并在类(OtherThing
)中进行JSON.mapping
。
class Thing
MAPPING = {
id: {type: String, default: UUID.random.to_s},
email: {type: String, nilable: true},
}
JSON.mapping({{MAPPING}})
end
class OtherThing
MAPPING = Thing::MAPPING.merge({
address: String,
city: String,
zip: {type: String, nilable: true},
latitude: {type: Float64, nilable: true},
longitude: {type: Float64, nilable: true},
})
JSON.mapping({{MAPPING}})
end
这会产生错误,具体取决于我如何组织代码。
一个错误:
Error expanding macro
FOR expression must be an array, hash or tuple literal, not Call:
Thing::MAPPING.merge
{% for key, value in _properties_ %}
^~~~~~~~~~~~
另一个可能的错误:
undefined macro method 'NamedTupleLiteral#merge'
OtherThing
JSON.mapping
简而言之 — 不,您现在无法在宏中插值常量。
@asterite:
问题是映射宏期望 HashLiteral 作为 参数,但现在他们收到一个路径
在您的情况下,命名元组宏获得了调用节点。在讨论 Crystal repo 时,https://github.com/crystal-lang/crystal/issues/2388 找到了理论上可以解决此问题的解决方法,但 JSON.mapping 它是旧方法,将在下一个版本中删除,而是尝试 JSON::可序列化
感谢@Blacksmoke16的帮助指出这一点,您可以通过使用 splats 定义自己的宏来实现预期的结果。
下面的代码应该可以工作。功劳归@Blacksmoke16
macro define(*args)
JSON.mapping(
{% for t in args %}
{{t.double_splat}},
{% end %}
)
end
class Thing
MAPPING = {
id: {type: String, default: UUID.random.to_s},
email: {type: String, nilable: true},
}
define {{MAPPING}}
end
class OtherThing
MAPPING = {
address: String,
city: String,
zip: {type: String, nilable: true},
latitude: {type: Float64, nilable: true},
longitude: {type: Float64, nilable: true},
}
define {{MAPPING}}, {{Thing::MAPPING}}
end