Yaml and ruby symbols

Since today is apparently the first day of the new YAML year, or at
least a major event on the YAML calendar, here’s something else I’ve
been wondering about.

I tend to prefer symbols to strings as hash keys (for immutability and
efficiency reasons), but I’m not crazy about how they look in YAML:

···

y({:foo=>1})


!ruby/sym foo: 1

whereas string keys look more natural:

y({“foo”=>1})


foo: 1

Yet it seems that YAML.load is quite capable of recognizing a nice,
natural format for symbols:

s=“—\n:foo: 1\n”
puts s


:foo: 1

YAML.load(s)
=> {:foo=>1}

And this notation is not ambiguous with strings that happen to begin
with a colon:

y({“:foo”=>1})


“:foo”: 1

Is it possible for Symbol#to_yaml to take an option that will dump
symbols in this simpler way? (You’d lose some portability, I guess, so
maybe the option should not be on by default.)

This is the implementation I tried, but apparently I don’t understand
how the opts argument of #to_yaml gets propagated (or why it doesn’t).

require ‘yaml’

class Symbol
def to_yaml( opts = {} )
YAML::quick_emit( nil, opts ) { |out|
out << (opts[:simple_symbols] ? “:” : "!ruby/sym ")
self.id2name.to_yaml( :Emitter => out )
}
end
end

foo_yaml = :foo.to_yaml({:simple_symbols => true})
puts foo_yaml

==>

— :foo

Good so far!

foo = YAML.load(foo_yaml)
p foo

==>

:foo

Still good.

h = {:foo=>1}

puts h.to_yaml

==>

!ruby/sym foo: 1

Expected.

puts h.to_yaml({:simple_symbols => true})

==>

!ruby/sym foo: 1

Expected:

:foo: 1

Joel VanderWerf wrote:

foo = YAML.load(foo_yaml)
p foo

==>

:foo

Still good.

the above works because loading of colon-prefixed strings as Symbols was
added to Syck about two months ago. so the only part of your
proposition that needs to be completed is the emission of symbols
implicitly.

i don’t see any reason we can’t move forward with it. you mention
portability…

no, python will not load symbols the same way. nor will php or java or
c. but this is true of many yaml constructs. the map, for instance,
will be loaded in php as an ordered hash. we can’t solve that problem.

i would recommend section 3.3 (‘Completeness’) of the yaml spec to
anyone who wants to know how portability between languages works with
yaml. basically, as long as the documents round-trip properly, the
native representation isn’t (and can’t be) perfect.

yeah, so the patch is checked into syck cvs. weaving into ruby cvs later.

_why

why the lucky stiff wrote:

Joel VanderWerf wrote:

foo = YAML.load(foo_yaml)
p foo

==>

:foo

Still good.

the above works because loading of colon-prefixed strings as Symbols was
added to Syck about two months ago. so the only part of your
proposition that needs to be completed is the emission of symbols
implicitly.

i don’t see any reason we can’t move forward with it. you mention
portability…

no, python will not load symbols the same way. nor will php or java or
c. but this is true of many yaml constructs. the map, for instance,
will be loaded in php as an ordered hash. we can’t solve that problem.

i would recommend section 3.3 (‘Completeness’) of the yaml spec to
anyone who wants to know how portability between languages works with
yaml. basically, as long as the documents round-trip properly, the
native representation isn’t (and can’t be) perfect.

yeah, so the patch is checked into syck cvs. weaving into ruby cvs later.

That’s great. Thanks!

How will we switch between emitting “!ruby/sym foo” and “:foo”? Will it
be an option to to_yaml?