1

I'm using to_yaml to write an array to a YAML file in Ruby. After the file is written I need to add another line or word under the YAML directive line (---) or the three dashes.

Is there a way to do this after I write the YAML file? Or is there just a better way in general to do this?

I'm reading in from one YAML file to write to another:

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

After it writes the YAML file correctly I realized that I need to add another line under the YAML directive line. I need to add the word classes below the three dashes (---):

---
- blah::words
- blah::words
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Tony D
  • 49
  • 1
  • 7
  • Not sure I understand exactly what you want to do, but `#to_yaml` returns a String, so you should be able to use any String method after the fact. – moveson Nov 17 '16 at 18:09
  • Updated my post to hopefully clear any confusion. Thanks for responding! – Tony D Nov 17 '16 at 18:30
  • 4
    It seems like you are reading the YAML file on one go, but try to write into another YAML file line by line. Writing YAML manually line by line is very error prone (and I see no valid reason to do it that way). Instead build your data structure in memory and write the YAML file in one go. – spickermann Nov 17 '16 at 18:39
  • @spickermann, I recommend creating an answer with this as it's important for the OP to understand what to do. Also, http://stackoverflow.com/a/26044442/128421 talks about this. – the Tin Man Nov 17 '16 at 21:35
  • @theTinMan : I agree and I would like to. But honestly I don't understand how his question and his example fit together and what he really wants to achieve. It feels to me like he is trying to generate invalid YAML manually. It would be great if he added an example how the input file looks like and what output he expects. – spickermann Nov 17 '16 at 21:39

2 Answers2

0

If you want to add something at the end of the file, then just write this between:

f.puts item.to_yaml

and

f.close

However you should consider making key (as it is unique) part of the filename of the YAML file that you write. As is your /tmp/blah.yaml is written for the first key, and the overwritten for every next key processed in the each loop, which is probably not what you want.

Anthon
  • 69,918
  • 32
  • 186
  • 246
0

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.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303