Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Ruby's YAML module be used to embed comments?

Tags:

ruby

yaml

to-yaml

The to_yaml method produces nice YAML output, but I would like to include comment lines before some of the elements. Is there a way to do so?

For example, I would like to produce:

# hostname or IP address of client
client: host4.example.com
# hostname or IP address of server
server: 192.168.222.222

From something similar to:

{
  :client => 'host4.example.com',
  :server => '192.168.222.222',
}.to_yaml

... but am not sure if the YAML module even has a way to accomplish.

UPDATE: I ended up not using the solution which used regexes to insert the comments, since it required the separation of the data from the comments. The easiest and most understandable solution for me is:

require 'yaml'

source = <<SOURCE
# hostname or IP address of client
client: host4.example.com
# hostname or IP address of server
server: 192.168.222.222
SOURCE

conf = YAML::load(source)

puts source

The benefit to me is that nothing is repeated (for example, 'client:' is only specified once), the data and comments are together, the source can be outputted as YAML, and the data structure (available in conf) is available for use.

like image 389
sutch Avatar asked Jan 04 '13 00:01

sutch


3 Answers

You can do a string replace on all the insertions:

require 'yaml'

source = {
  :client => 'host4.example.com',
  :server => '192.168.222.222',
}.to_yaml

substitution_list = {
  /:client:/ => "# hostname or IP address of client\n:client:",
  /:server:/ => "# hostname or IP address of server\n:server:"
}

substitution_list.each do |pattern, replacement|
  source.gsub!(pattern, replacement)
end

puts source

output:

--- 
# hostname or IP address of client
:client: host4.example.com
# hostname or IP address of server
:server: 192.168.222.222
like image 120
mgamba Avatar answered Oct 22 '22 14:10

mgamba


Something like this:

my_hash = {a: 444}
y=YAML::Stream.new()
y.add(my_hash)
y.emit("# this is a comment")

Of course, you will need to walk the input hash yourself and either add() or emit() as needed. You could look at the source of the to_yaml method for a quick start.

like image 2
Zabba Avatar answered Oct 22 '22 16:10

Zabba


This isn't perfect (no mid-Array support, for example), but it works for my needs.

  def commentify_yaml(db)
    ret = []
    db.to_yaml(line_width: -1).each_line do |l|
      if l.match(/^\s*:c\d+:/)
        l = l.sub(/:c(\d+)?:/, '#').
            sub(/(^\s*# )["']/, '\1').
            sub(/["']\s*$/, '').
            gsub(/''(\S+?)''/, "'\\1'").
            gsub(/(\S)''/, "\\1'")
      end
      ret << l.chomp
    end
    ret * "\n"
  end

Example usage.

commentify_yaml(
  {
    c1: 'Comment line 1',
    c2: 'Comment line 2',
    'hash_1' => {
      c1: 'Foo',
      c2: 'Bar',
      'key_1' => "Hello!",
    },
    'baz' => qux,
    c3: 'Keep up-numbering the comments in the same hash',
    'array_1' => [
       1,
       2,
       3
     ]
  }
)

==>

# Comment line 1
# Comment line 2
hash_1:
  # Foo
  # Bar
  key_1: "Hello!"
baz: "Value of qux"
# Keep up-numbering the comments in the same hash
array_1:
- 1
- 2
- 3

(Note: Syck does not indent arrays they way it arguably should.)

like image 1
Myles Prather Avatar answered Oct 22 '22 14:10

Myles Prather