Joel VanderWerf
2/12/2007 3:44:00 AM
Larry Edelstein wrote:
> Hi all -
>
> I want to write a config file in YAML. In this file I will store a
> small graph of objects in an array:
>
> - !mydomain,mydate/Company
> name: TuesdayCo
> subthings:
> - !mydomain,mydate/Person
> name: Ruby Tuesday
> - !mydomain,mydate/Person
> name: Tuesday Weld
> - !mydomain,myDate
> name: FridayCo
> subthings:
> etc.
>
> Then I want to read in this file and get an array of Company objects,
> each of which has an array of Person objects. I'm defining these
> classes myself. I've tried using add_domain_type and hoped to get
> instances of my classes, but instead I got instances of
> YAML::DomainType.
>
> How should I do this?
Here's the only way I know to do this (I'm not sure if add_domain_type
is another way):
require 'yaml'
# This assumes that all your objects will serialize as hashes ("maps")
module Base
def to_yaml( opts = {} )
YAML::quick_emit( object_id, opts ) do |out|
out.map( taguri, to_yaml_style ) do |map|
to_yaml_properties.each do |m|
map.add( m, send( m ) )
end
end
end
end
module BaseModuleMethods
def yaml_new( klass, tag, val )
unless Hash === val
raise YAML::TypeError, "Invalid #{self}: " + val.inspect
## do more error checking here, if desired
end
name, type = YAML.read_type_class( tag, self )
st = type.new
val.each do |k,v|
st.send( "#{k}=", v )
end
st
end
end
def self.included mod
mod.extend BaseModuleMethods
end
end
class Company
include Base
attr_accessor :name, :subthings
def initialize name = nil
@name = name
end
yaml_as "tag:my.domain,2007:Company"
def to_yaml_properties
["name", "subthings"]
end
end
class Person
include Base
attr_accessor :name
def initialize name = nil
@name = name
end
yaml_as "tag:my.domain,2007:Person"
def to_yaml_properties
["name"]
end
end
co = Company.new "TuesdayCo"
co.subthings = [
Person.new("Ruby Tuesday"),
Person.new("Tuesday Weld")
]
co_yaml = co.to_yaml
puts co_yaml
# ==>
# --- !my.domain,2007/Company
# name: TuesdayCo
# subthings:
# - !my.domain,2007/Person
# name: Ruby Tuesday
# - !my.domain,2007/Person
# name: Tuesday Weld
co2 = YAML.load(co_yaml)
p co2
# ==>
#<Company:0xb7ce3cfc @subthings=[#<Person:0xb7ce44cc @name="Ruby
Tuesday">, #<Person:0xb7ce3ef0 @name="Tuesday Weld">], @name="TuesdayCo">
# Check that error-checking works by
# giving the parser an array instead of a hash:
s = <<END
--- !my.domain,2007/Company
- 1
- 2
END
begin
p YAML.load(s)
rescue YAML::TypeError => ex
puts ex.message # Invalid Company: [1, 2]
end
--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407