Mohammad
Mohammad

Reputation: 3396

Force quotes in yaml

I have a ruby hash that is something like this:

myhash = { title: 'http://google.com'}

I'm trying to add this to a yaml file like this:

params['myhash'] = myhash
File.open('config.yaml', 'w') do |k|
  k.write params.to_yaml
end

The problem is that YAML is removing the quotes around the links even though they are needed (they contain ':').

According to several questions on Stackoverflow, YAML should only remove the quotes when they are not needed.

I found a Solution, but it's really ugly and I prefer not to use it if there was another solution.

I suppose that yaml should be including the quotes in this case. Is there any reason why it's not doing this?

Note: the links are dynamically created

Upvotes: 1

Views: 1739

Answers (2)

Jethro Yu
Jethro Yu

Reputation: 589

After couple hours i found it's easier in python.

usage: python quotes.py *.yml

  • This script use literal format if string has '\n'.
  • Use ruamel to replace yaml lib, yaml lib seems not handle some UTF-8 entry

    from ruamel import yaml
    import io
    import sys
    
    
    class quote_or_literal(unicode):
        pass
    
    
    def str_presenter(dumper, data):
        if data.count("\n"):  # check for multiline string
            return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
        else:
            return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
    
    
    yaml.add_representer(quote_or_literal, str_presenter)
    
    
    def quote_dict(d):
        new = {}
        for k, v in d.items():
            if isinstance(v, dict):
                v = quote_dict(v)
            else:
                v = quote_or_literal(v)
            new[k] = v
        return new
    
    
    def ensure_quotes(path):
        with io.open(path, 'r', encoding='utf-8') as stream:
            a = yaml.load(stream, Loader=yaml.Loader)
            a = quote_dict(a)
    
        with io.open(path, 'w', encoding='utf-8') as stream:
            yaml.dump(a, stream, allow_unicode=True,
                      width=1000, explicit_start=True)
    
    
    if __name__ == "__main__":
        for path in sys.argv[1:]:
            ensure_quotes(path)
    

Upvotes: 1

cschroed
cschroed

Reputation: 6834

Quotes aren't necessary for your example string. From the specs:

Normally, YAML insists the “:” mapping value indicator be separated from the value by white space. A benefit of this restriction is that the “:” character can be used inside plain scalars, as long as it is not followed by white space.

For example:

h = { value1: 'quotes: needed', value2: 'quotes:not needed' }
puts h.to_yaml

Results in:

---
:value1: 'quotes: needed'
:value2: quotes:not needed

Upvotes: 1

Related Questions