ruby / psych

A libyaml wrapper for Ruby
MIT License
564 stars 201 forks source link

Add an option for stringifying the symbol key without colon #396

Open jessehu opened 5 years ago

jessehu commented 5 years ago

Currently if the key in the Hash is a symbol (e.g. h = {a: 1}), to_yaml will generate :a: 1.

irb(main):003:0> require 'yaml'
irb(main):003:0> puts({a: 1, b: 'ruby'}.to_yaml)
---
:a: 1
:b: ruby

Usually the key in the yaml file doesn't start with ':'. So this feature request is for adding a new to_yaml option for stringifying the symbol key without colon. As a result, to_yaml will generate 'a: 1' for '{a: 1}'.

The code change required will be in this function: https://github.com/ruby/psych/blob/e01839af57df559b26f74e906062be6c692c89c8/lib/psych/visitors/yaml_tree.rb#L401 Change it to:

          def visit_Symbol o
            if o.empty?
              @emitter.scalar "", nil, '!ruby/symbol', false, false, Nodes::Scalar::ANY
            else
              str = @options[:stringify_symbol_key] ? "#{o}" : ":#{o}"
              @emitter.scalar str, nil, nil, true, false, Nodes::Scalar::ANY
            end
          end

There are a few discussion/requirement for this feature on google.com, e.g. https://stackoverflow.com/questions/53093316/ruby-to-yaml-colon-in-keys

tuscen commented 2 years ago

I'd really like to have this feature. I'm trying to write a DSL for Gitlab CI and because of this behaviour I have to resort to a bunch of nasty hacks to convert all symbols in all hashes, collections and other objects into strings.

Buju77 commented 2 years ago

I would like to also have this option. It is very uncommon to have symbols in YAML files. Most of them are normal strings and not symbols.

blowfishpro commented 1 year ago

I also just ran into this. I built a workaround but I would love to not have to:

class SymbolToStringYamlTreeVisitor < Psych::Visitors::YAMLTree
  def visit_Symbol(sym)
    visit_String(sym.to_s)
  end
end

# actually use it, mostly the same as Psych.dump
def dump_yaml_without_symbols(obj, io = nil, **options)
  visitor = SymbolToStringYamlTreeVisitor.create(**options)
  visitor << obj
  visitor.tree.yaml(io, **options)
end
toote commented 11 months ago

@blowfishpro

def dump_yaml_without_symbols(obj, io = nil, **options)
  visitor = SymbolToStringYamlTreeVisitor.create(**options)
  visitor << values
  visitor.tree.yaml(io, **options)
end

there is a bug in your code, it should be visitor << obj instead of visitor << values

blowfishpro commented 11 months ago

there is a bug in your code, it should be visitor << obj instead of visitor << values

Whoops yeah, fixed. I changed some variable names when I posted it and missed that one. Thanks!