[YAML] serializing Class and Module objects

Hey, _why, what do you think about allowing YAML to dump/load Class and
Module objects rather than gagging? I've posted code like the following
(different versions for 1.8.2 and 1.8.4) several times in response to
inquiries on ruby-talk, and found it useful myself.

···

=====================================================
Test code:

  enum_y = [Enumerable, Comparable, String, File].to_yaml
  puts enum_y
  p YAML.load(enum_y)

=====================================================
Test output:

---
- !ruby/module Enumerable
- !ruby/module Comparable
- !ruby/class String
- !ruby/class File
[Enumerable, Comparable, String, File]

=====================================================
require 'yaml'

if defined?(YAML.type_tag) # old version of 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

else

  class Module
    yaml_as "tag:ruby.yaml.org,2002:module"

    def Module.yaml_new( klass, tag, val )
      if String === val
        val.split(/::/).inject(Object) {|m, n| m.const_get(n)}
      else
        raise YAML::TypeError, "Invalid Module: " + val.inspect
      end
    end

    def to_yaml( opts = {} )
      YAML::quick_emit( nil, opts ) { |out|
        out.scalar( "tag:ruby.yaml.org,2002:module", self.name, :plain )
      }
    end
  end

  class Class
    yaml_as "tag:ruby.yaml.org,2002:class"

    def Class.yaml_new( klass, tag, val )
      if String === val
        val.split(/::/).inject(Object) {|m, n| m.const_get(n)}
      else
        raise YAML::TypeError, "Invalid Class: " + val.inspect
      end
    end

    def to_yaml( opts = {} )
      YAML::quick_emit( nil, opts ) { |out|
        out.scalar( "tag:ruby.yaml.org,2002:class", self.name, :plain )
      }
    end
  end

end

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Joel VanderWerf wrote:

Hey, _why, what do you think about allowing YAML to dump/load Class and
Module objects rather than gagging? I've posted code like the following
(different versions for 1.8.2 and 1.8.4) several times in response to
inquiries on ruby-talk, and found it useful myself.

I've been reluctant, because reloading these objects causes trouble if you haven't required the right libraries. But I think if YAML's error message was okay, it would work.

Oh and the best place for getting Syck requests through is now here: http://code.whytheluckystiff.net/syck/newticket

_why

why the lucky stiff wrote:

Joel VanderWerf wrote:

Hey, _why, what do you think about allowing YAML to dump/load Class and
Module objects rather than gagging? I've posted code like the following
(different versions for 1.8.2 and 1.8.4) several times in response to
inquiries on ruby-talk, and found it useful myself.

I've been reluctant, because reloading these objects causes trouble if
you haven't required the right libraries. But I think if YAML's error
message was okay, it would work.

I thought about rescuing and re-raising the exception as a different
exception class, but maybe it is better to leave it as it is:

NameError: uninitialized constant Foo

This is the same exception you would get if you loaded a script file.

The way Marshal does it (in the case of a dumped class that is loaded
without having the class definition required) is:

ArgumentError: undefined class/module Foo

Maybe that's how YAML should do it for consistency?

I'd be happy with either way.

Oh and the best place for getting Syck requests through is now here:
http://code.whytheluckystiff.net/syck/newticket

Thanks!

···

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

why the lucky stiff wrote:

Joel VanderWerf wrote:

Hey, _why, what do you think about allowing YAML to dump/load Class and
Module objects rather than gagging? I've posted code like the following
(different versions for 1.8.2 and 1.8.4) several times in response to
inquiries on ruby-talk, and found it useful myself.

I've been reluctant, because reloading these objects causes trouble if
you haven't required the right libraries. But I think if YAML's error
message was okay, it would work.

Oh and the best place for getting Syck requests through is now here:
http://code.whytheluckystiff.net/syck/newticket

Ok. I've submitted this patch and also the :SortKeys issue to the Syck Trak.

···

--
      vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407