How to add YAML serialization support to a class?

Hello. Can someone point me to some documentation describing how to add YAML
support to a class? I have a class that contains an RGL graph. I'd like to
be able to save it and restore it, but

YAML::dump(RGL::DirectedAdjacencyGraph.new)

throws an exception

TypeError: can't dump anonymous class Class
        from /usr//lib/ruby/1.8/yaml/rubytypes.rb:9:in `to_yaml'
        from /usr//lib/ruby/1.8/yaml/baseemitter.rb:181:in `map'
        from /usr//lib/ruby/1.8/yaml/baseemitter.rb:170:in `each'
        from /usr//lib/ruby/1.8/yaml/baseemitter.rb:170:in `map'
        from /usr//lib/ruby/1.8/yaml/rubytypes.rb:25:in `to_yaml'
        from /usr//lib/ruby/1.8/yaml/rubytypes.rb:24:in `call'
        from /usr//lib/ruby/1.8/yaml.rb:373:in `quick_emit'
        from /usr//lib/ruby/1.8/yaml/rubytypes.rb:24:in `to_yaml'
        from /usr//lib/ruby/1.8/yaml.rb:103:in `dump'

TIA.

Luca

Luca Pireddu wrote:

Hello. Can someone point me to some documentation describing how to add YAML
support to a class? I have a class that contains an RGL graph. I'd like to
be able to save it and restore it, but

YAML::dump(RGL::DirectedAdjacencyGraph.new)

throws an exception

TypeError: can't dump anonymous class Class

Looks like the problem is that somewhere in the graph of objects connected to your instance is a Class object:

$ irb -r yaml
irb(main):001:0> YAML.dump(Class)
TypeError: can't dump anonymous class Class
...

(I don't see what's anonymous about Class...)

Anyway, there's nothing shameful about wanting to yaml a class! It's easy to convince YAML to let you do it:

require 'yaml'

class Module
   def is_complex_yaml?
     false
   end
   def to_yaml( opts = {} )
     YAML::quick_emit( nil, opts ) { |out|
       out << "!ruby/module "
       self.name.to_yaml( :Emitter => out )
     }
   end
end
YAML.add_ruby_type(/^module/) do |type, val|
   subtype, subclass = YAML.read_type_class(type, Module)
   val.split(/::/).inject(Object) { |p, n| p.const_get(n)}
end

class Class
   def to_yaml( opts = {} )
     YAML::quick_emit( nil, opts ) { |out|
       out << "!ruby/class "
       self.name.to_yaml( :Emitter => out )
     }
   end
end
YAML.add_ruby_type(/^class/) do |type, val|
   subtype, subclass = YAML.read_type_class(type, Class)
   val.split(/::/).inject(Object) { |p, n| p.const_get(n)}
end

p YAML.dump(Class) # ==> "--- !ruby/class Class"

So, really, all that is getting written is a reference to the class. Any state in the class itself (class vars, class instance vars) is not stored.

Joel VanderWerf wrote:

Luca Pireddu wrote:

Hello. Can someone point me to some documentation describing how to add
YAML
support to a class? I have a class that contains an RGL graph. I'd like
to be able to save it and restore it, but

YAML::dump(RGL::DirectedAdjacencyGraph.new)

throws an exception

TypeError: can't dump anonymous class Class

Looks like the problem is that somewhere in the graph of objects
connected to your instance is a Class object:

$ irb -r yaml
irb(main):001:0> YAML.dump(Class)
TypeError: can't dump anonymous class Class
..

(I don't see what's anonymous about Class...)

Anyway, there's nothing shameful about wanting to yaml a class! It's
easy to convince YAML to let you do it:

require 'yaml'

class Module
   def is_complex_yaml?
     false
   end
   def to_yaml( opts = {} )
     YAML::quick_emit( nil, opts ) { |out|
       out << "!ruby/module "
       self.name.to_yaml( :Emitter => out )
     }
   end
end
YAML.add_ruby_type(/^module/) do |type, val|
   subtype, subclass = YAML.read_type_class(type, Module)
   val.split(/::/).inject(Object) { |p, n| p.const_get(n)}
end

class Class
   def to_yaml( opts = {} )
     YAML::quick_emit( nil, opts ) { |out|
       out << "!ruby/class "
       self.name.to_yaml( :Emitter => out )
     }
   end
end
YAML.add_ruby_type(/^class/) do |type, val|
   subtype, subclass = YAML.read_type_class(type, Class)
   val.split(/::/).inject(Object) { |p, n| p.const_get(n)}
end

p YAML.dump(Class) # ==> "--- !ruby/class Class"

So, really, all that is getting written is a reference to the class. Any
state in the class itself (class vars, class instance vars) is not stored.

Thanks for your reply Joel. I think I understand the basic idea. To emit,
define a method #to_yaml in your class. To enable YAML to load your class
register the type with YAML using one of the add_x_type methods, and
associate a block that knows how to recreate your data structure from the
YAML parse tree.

For anyone who may be interested, I've found helpful documentation at this
site:
http://yaml4r.sourceforge.net/doc/

Luca