【问题标题】:How to inject a line to a YAML file using Ruby如何使用 Ruby 向 YAML 文件中注入一行
【发布时间】:2016-11-17 17:53:45
【问题描述】:

我正在使用 to_yaml 将数组写入 Ruby 中的 YAML 文件。文件写入后,我需要在 YAML 指令行 (---) 或三个破折号下添加另一行或单词。

在我编写 YAML 文件后有没有办法做到这一点?还是一般来说有更好的方法来做到这一点?

我正在从一个 YAML 文件中读取以写入另一个文件:

items = YAML::load(File.open(yaml_file)

items.each do |key, value|
  item = items["#{key}"]
  f = File.open("/tmp/blah.yaml", 'w')
  f.puts item.to_yaml
  f.close
end

在它正确写入 YAML 文件后,我意识到我需要在 YAML 指令行下添加另一行。我需要在三个破折号下方添加单词类(---):

---
- blah::words
- blah::words

【问题讨论】:

  • 不确定我完全理解你想要做什么,但是#to_yaml 返回一个字符串,所以你应该能够在事后使用任何字符串方法。
  • 更新了我的帖子,希望能消除任何困惑。感谢您的回复!
  • 您似乎在一次读取 YAML 文件,但尝试逐行写入另一个 YAML 文件。逐行手动编写 YAML 非常容易出错(我认为没有正当理由这样做)。而是在内存中构建您的数据结构并一次性编写 YAML 文件。
  • @spickermann,我建议用这个创建一个答案,因为对于 OP 了解该做什么很重要。此外,stackoverflow.com/a/26044442/128421 也谈到了这一点。
  • @theTinMan :我同意并且我愿意。但老实说,我不明白他的问题和他的例子是如何结合在一起的,以及他真正想要实现的目标。我觉得他正试图手动生成无效的 YAML。如果他添加一个示例输入文件的外观以及他期望的输出,那就太好了。

标签: ruby yaml


【解决方案1】:

YAML 是对象的序列化版本,可以是散列,也可以是数组。由于序列化程序的执行方式,根据规范,我们不能在输出的任何旧位置添加一行,它必须在语法上正确。而且,最简单的方法是让 YAML 解析器和序列化程序为您处理它。

例如:

require 'yaml'

foo = {'a' => 1}
puts foo.to_yaml

哪些输出:

---
a: 1

并且是 YAML 格式的简单哈希。

我们可以做一个往返证明这是正确的:

bar = foo.to_yaml
YAML.load(bar) # => {"a"=>1}

一个更复杂的对象展示了它是如何变得棘手的:

foo = {'a' => [1,2], 'b' => {'c' => [3, 4]}}
puts foo.to_yaml

导致:

---
a:
- 1
- 2
b:
  c:
  - 3
  - 4

还有其他方法可以指定一个数组,但这是序列化程序的默认设置。如果您添加了一行,则取决于您添加的内容,它必须在 a:b: 之前,这在编写代码或在 - 4 之后附加到文件时会很痛苦。

相反,我们可以加载和解析文件,随意调整生成的对象,然后重写 YAML 文件,知道语法是正确的。

在下面的代码中,假设 bar 是使用 YAML 的 load_file 读取并解析 YAML 文件的结果,而不是我使用的仅解析序列化对象的 load

require 'yaml'

bar = YAML.load("---\na: [1]\n") # => {"a"=>[1]}

我可以修改bar:

bar['b'] = {'c' => [2,3,4]}

这是修改后的对象:

bar # => {"a"=>[1], "b"=>{"c"=>[2, 3, 4]}}

并使用to_yaml 进行序列化将写入正确的 YAML:

bar.to_yaml # => "---\na:\n- 1\nb:\n  c:\n  - 2\n  - 3\n  - 4\n"

如果是这样的话:

File.write('foo.yaml', bar.to_yaml)

您会毫不费力地完成更改。

我建议不要简单地覆盖文件,而是通过写入新文件、重命名旧文件、将新文件重命名为旧文件,然后删除重命名的旧文件,遵循安全文件覆盖做法。这有助于确保在代码或机器死机导致您丢失所有数据时文件不会被破坏。

【讨论】:

    【解决方案2】:

    如果你想在文件末尾添加一些东西,那么就写在:

    f.puts item.to_yaml
    

    f.close
    

    但是,您应该考虑将key(因为它是唯一的)作为您编写的 YAML 文件的文件名的一部分。正如你的/tmp/blah.yaml 是为第一个键写入的,并且为each 循环中处理的每个下一个键覆盖,这可能不是你想要的。

    【讨论】:

      猜你喜欢
      • 2017-04-03
      • 2011-01-17
      • 2015-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-22
      • 1970-01-01
      相关资源
      最近更新 更多