我需要打开一个YAML文件,其中使用了别名:
defaults: &defaults
foo: bar
zip: button
node:
<<: *defaults
foo: other
这显然扩展为一个等效的YAML文档:
defaults:
foo: bar
zip: button
node:
foo: other
zip: button
YAML::load
读起来是这样的。
我需要在这个YAML文档中设置新的键,然后将它写回磁盘,尽可能地保留原始结构。
我看过YAML::Store,但这完全破坏了别名和锚。
是否有任何可用的东西可以沿着如下:
thing = Thing.load("config.yml")
thing[:node][:foo] = "yet another"
将文档重新保存为:
defaults: &defaults
foo: bar
zip: button
node:
<<: *defaults
foo: yet another
?
我之所以选择使用YAML,是因为它可以很好地处理别名,但是编写包含别名的YAML在现实中看起来有点乏味。
4条答案
按热度按时间exdqitrt1#
使用
<<
来指示别名Map应该合并到当前Map中不是Yaml核心规范的一部分,但它是part of the tag repository。Ruby - Psych -提供的Yaml库提供了
dump
和load
方法,它们允许Ruby对象的简单序列化和反序列化,并使用标记库中的各种隐式类型转换,包括<<
来合并散列。如果需要,它还提供了一些工具来进行更低级的Yaml处理。不幸的是,它没有不要轻易地允许选择性地禁用或启用标记库的特定部分--这是一件全有或全无的事情。特别是<<
的处理与哈希的处理非常相似。一种实现方法是提供你自己的Psych的
ToRuby
类的子类并覆盖这个方法,这样它就可以把<<
的Map键当作文字来处理。这涉及到覆盖Psych中的一个私有方法,所以你需要小心一点:然后,您可以像这样使用它:
使用示例中的Yaml,
data
将如下所示注意,
<<
是一个文本键。另外,data["defaults"]
键下的哈希值与data["node"]["<<"]
键下的哈希值 * 相同 *,即它们具有相同的object_id
。现在,您可以根据需要操作数据,当您将其写成Yaml时,锚点和别名仍然保持不变,尽管锚点名称已经更改:产生(Psych使用散列的
object_id
来确保唯一的锚名称(当前版本的Psych现在使用序列号而不是object_id
)):如果你想控制锚名称,你可以提供自己的
Psych::Visitors::Emitter
。下面是一个基于你的例子的简单例子,假设只有一个锚点:当与上面修改过的
data
哈希一起使用时:输出为:
(* 更新:* another question询问如何对多个锚执行此操作,我提出了possibly better way to keep anchor names when serializing。)
qvtsj1bj2#
YAML有别名,它们可以往返,但是您可以通过哈希合并禁用它。
<<
作为Map键似乎是YAML的非标准扩展(在1.8的syck和1.9的psych中都有)。印刷品
但是数据中的
<<
将别名哈希合并为一个不再是别名的新哈希。1rhkuytd3#
你试过Psych吗?又一个心理问题。
jei2mxaa4#
我用Ruby脚本和ERB模板生成了我的CircleCI配置文件。我的脚本解析并重新生成YAML,所以我想保留所有的锚点。配置中的锚点都与定义它们的键同名,例如:
所以我可以在生成的YAML字符串上使用正则表达式来解决这个问题。它写了一个
#restore_yaml_anchors
方法,将&1
和*1
转换回&docker_auth
和*docker_auth
。输出量:
它对我的CI配置工作得很好,但是您可能需要更新它以处理您自己的YAML中的一些其他情况。