legendary_rob
legendary_rob

Reputation: 13012

Ruby Appending comment block to YAML file

I have a yml file that I am using to store a list of stories I have added between releases.

I am using a rake task to dynamically update the version number based off what stories I have added to this file.

It is introducing a new process, so I created the following comment block this will help anyone commenting here to add stories in the right format:

#  Version control file.
#  Versions should be incremented as follows
#
#   [X - major change] . [V - new feature] . [I - Bug fix / Small change]
#
#  Update the undefined block with a one line readable description of what your story was about. example:
#
#  undefined:
#    stories:
#    - "I - fixed spelling mistake"
#    - "V - added import functionality"
#    - "X - rebuilt the main dashboard"
#

The issue is after my rake task is done the job the file loses the comment block.

I pretty much load the YAML versions = YAML.load_file( 'doc/release.yml' ) and then once the logic is finished I File.open("doc/release.yml", 'w') { |f| YAML.dump(versions, f) }

Where versions is the new updated hash. However, this removes the comment block to the file.

Other solutions I have found just modify existing lines.

Is there a way to open the file and adding the above without messing up the YAML beneath. Any help will be much appreciated.

Upvotes: 3

Views: 2379

Answers (3)

Myles Prather
Myles Prather

Reputation: 178

I came up with this method of adding comments to my Hash before dumping out to yaml. I use this to initialize configuration files with embedded comments to document the configuration options. It's a limited solution. No in-Array comments, for example. But it'll work for simple cases.

cfg = {
  c: 'This is a comment',
  'foo' => 'bar',
  'level2' => {
    'level3' => {
      'foo' => 'bar',
      c1: 'This is a comment (line 1)',
      c2: 'This is a comment (line 2)',
      'foo2' => 'bar2',
    },
  },
}

YAML.dump(cfg).each_line do |l|
  if l.match(/:c(\d+)?:/)
    l.sub!(/:c(\d+)?:/, '#')
    l.sub!(/(^\s*# )["']/, '\1')
    l.sub!(/["']\s*$/, '')
  end
  puts l
end

Produces:

---
# This is a comment
foo: bar
level2:
  level3:
    foo: bar
    # This is a comment (line 1)
    # This is a comment (line 2)
    foo2: bar2

Upvotes: 1

Eric Duminil
Eric Duminil

Reputation: 54253

Here's a possible solution.

require 'yaml'

versions_yaml = File.read('release.yml')
versions = YAML.load(versions_yaml)
comments = versions_yaml.scan(/^#.*?$/)

File.open("release2.yml", 'w') { |f|
  f.puts comments
  YAML.dump(versions, f)
}

puts File.read("release2.yml")

With release.yml :

# I'm a comment on first line
---
- 1
- 2
- 3
# I'm a comment somewhere in the middle
- - 4
  - 5

it outputs :

# I'm a comment on first line
# I'm a comment somewhere in the middle
---
- 1
- 2
- 3
- - 4
  - 5

Upvotes: 1

peter
peter

Reputation: 42207

That the comments are lost with a dump is unfortunatly normal. You have two options:

  1. convert your versions hash to yaml { :a => 'b'}.to_yaml, add the comments and with File.write do the dump yourself, you could overwrite the normal .dump method in YAML this way
  2. assign the comments to some dummy value at the end of your yaml file so that they are read into versions and saved also.

Upvotes: 1

Related Questions