Outputting custom YAML types in 1.8.3

I just upgraded my main development box (Debian unstable) to the new
ruby 1.8.3 packages, and noticed a change in the behaviour of custom-
defined #to_yaml methods.

Simplified example code:

require 'yaml'
class Foo
  def to_yaml_type; "!example.com,2005/Foo"; end
  def to_yaml( opts={} )
    YAML::quick_emit( object_id, opts ) do |out|
      out.map( to_yaml_type ) do |map|
        map.add :foo, 'bar'
        map.add :one, 2
      end
    end
  end
end
puts( { 'a' => Foo.new }.to_yaml )

With previous versions this produced:

···

---
a: !example.com,2005/Foo
  :foo: bar
  :one: 2

The output that I now get is:
a:
  :foo: bar
  :one: 2

So there are a couple changes. First it's no longer outputting a line
of dashes at the beginning. Second, and more importantly, it's no
longer including the type information.

Things work fine if I just define #to_yaml_type and #to_yaml_properties
instead of #to_yaml, but I can't do that for some of my classes.

I can also get it to work if I call yaml_as for the class and use the
#taguri method generated by that as the argument when calling out.map(),
but this wouldn't be compatible with older versions.

Is this a bug, or is there something that I should be doing different?

--
Aaron Schrab aaron@schrab.com http://www.schrab.com/aaron/
When you're dealing with like crazy aggressors like Libya or Iran or
Microsoft, you are talking about people who could do anything.
   -- Bill Maher

Aaron Schrab wrote:

require 'yaml'
class Foo
  def to_yaml_type; "!example.com,2005/Foo"; end
  def to_yaml( opts={} )
    YAML::quick_emit( object_id, opts ) do |out|
      out.map( to_yaml_type ) do |map|
        map.add :foo, 'bar'
        map.add :one, 2
      end
    end
  end
end
puts( { 'a' => Foo.new }.to_yaml )
  

The out.map now takes YAML taguris. Try:

   YAML::quick_emit( YAML.tagurize( to_yaml_type[1..-1] ) )

Or I would recommend switching to taguris completely in your code.

  def to_yaml_type; "tag:example.com,2005:Foo"; end
  

The YAML syntax "!example.com,2005/Foo" is just a shortcut for a taguri.

So there are a couple changes. First it's no longer outputting a line
of dashes at the beginning. Second, and more importantly, it's no
longer including the type information.
  

The long string of dashes at the beginning isn't required in YAML 1.0, so I've decided to default to headless.

_why

I don't know if it is related but the 1.8.3 from Debian unstable broke
RubyGem ... It seems that the Yaml spec built with 1.8.3 is not accepted
by previous versions.

I have now
!ruby/object:Gem::Specification

while 1.8.2 is expecting
--- !ruby/object:Gem::Specification

Sylvain

The out.map now takes YAML taguris. Try:

  YAML::quick_emit( YAML.tagurize( to_yaml_type[1..-1] ) )

Presumably you mean to use that argument when calling map on the
emitter. That works with 1.8.3, but since the YAML class included in
previous versions of ruby doesn't respond to the tagurize method it
won't work there.

So to be compatible I guess I'll just have to do something like:

yaml_type = to_yaml_type
yaml_type = YAML.tagurize(yaml_type[1..-1]) if YAML.respond_to? :tagurize
out.map(yaml_type)

Or I would recommend switching to taguris completely in your code.
> def to_yaml_type; "tag:example.com,2005:Foo"; end

That also won't work properly with older versions.

The long string of dashes at the beginning isn't required in YAML 1.0,
so I've decided to default to headless.

Yeah, I don't really care about that. I really only noticed it when
comparing the ouput to older versions because of the other issue.

···

At 01:07 +0900 24 Sep 2005, why the lucky stiff <ruby-talk@whytheluckystiff.net> wrote:

--
Aaron Schrab aaron@schrab.com Aaron Schrab
As I look across the web, what I find is this vast wasteland that
makes television almost attractive. -- Clifford Stoll