YAML is a serialized version of an object, either a hash or an array. Because of the way the serializer does it, according to the specification, we can't stick a line into the output any old place, it has to be syntactically correct. And, the easiest way to do that is to let the YAML parser and serializer handle it for you.
For instance:
require 'yaml'
foo = {'a' => 1}
puts foo.to_yaml
Which outputs:
---
a: 1
and is a simple hash in YAML format.
We can do a round-trip showing that's correct:
bar = foo.to_yaml
YAML.load(bar) # => {"a"=>1}
A more complex object shows how it can get tricky:
foo = {'a' => [1,2], 'b' => {'c' => [3, 4]}}
puts foo.to_yaml
which results in:
---
a:
- 1
- 2
b:
c:
- 3
- 4
There are other ways to designate an array, but that's the default for the serializer. If you added a line, depending on what you're adding it'd have to be before a:
or b:
, which would be a pain when writing code or appended to the file after - 4
.
Instead, we can load and parse the file, munge the resulting object however we want, then rewrite the YAML file, knowing the syntax will be right.
In the following code, imagine that bar
is the result of using YAML's load_file
, which reads and parses a YAML file, instead of my use of load
which only parses the serialized object:
require 'yaml'
bar = YAML.load("---\na: [1]\n") # => {"a"=>[1]}
I can modify bar
:
bar['b'] = {'c' => [2,3,4]}
Here's the modified object:
bar # => {"a"=>[1], "b"=>{"c"=>[2, 3, 4]}}
and serializing using to_yaml
will write the correct YAML:
bar.to_yaml # => "---\na:\n- 1\nb:\n c:\n - 2\n - 3\n - 4\n"
If that was:
File.write('foo.yaml', bar.to_yaml)
you'd have accomplished the change without any real hassle.
Instead of simply overwriting the file I'd recommend following safe file overwriting practices by writing to a new file, renaming the old, renaming the new to the name of the old, then deleting the renamed old file. This helps to make sure the file doesn't get clobbered if the code or machine dies causing you to lose all your data.