YAML and constant objects

B

Brian Buckley

Hello all,

I have an immutable class Foo (once a foo object is created its state
is fixed). Foo objects have a bunch of attributes so their yaml
strings are fairly long.

There is a small set of standard, frequently used foo objects and I
have defined these as constants right in the class (newed and set
each attribute for Foo::FOO1, Foo::FOO2, ... etc.).

When I YAML one of these standard foos to the database and back, it
seems inefficient to create and send a big long yaml string describing
each attribute and then on retrieval to create a whole new Foo object
when all I really want is to look up an already-made constant.

Is there a good solution to making the yaml-ing of constants efficient?

Thanks!

--Brian Buckley

foo =3D Foo:FOO1
data =3D foo.to_yaml # the yaml string here is unnecessarily long
foo =3D YAML::load(data) # and now after retrieval we have an
additional foo object when we really only need the one original
constant




-
 
J

Joel VanderWerf

Brian said:
Hello all,

I have an immutable class Foo (once a foo object is created its state
is fixed). Foo objects have a bunch of attributes so their yaml
strings are fairly long.

There is a small set of standard, frequently used foo objects and I
have defined these as constants right in the class (newed and set
each attribute for Foo::FOO1, Foo::FOO2, ... etc.).

When I YAML one of these standard foos to the database and back, it
seems inefficient to create and send a big long yaml string describing
each attribute and then on retrieval to create a whole new Foo object
when all I really want is to look up an already-made constant.

Is there a good solution to making the yaml-ing of constants efficient?

Thanks!

--Brian Buckley

foo = Foo:FOO1
data = foo.to_yaml # the yaml string here is unnecessarily long
foo = YAML::load(data) # and now after retrieval we have an
additional foo object when we really only need the one original
constant

The only problem with the following (I think) is that you have to pass
the constant name in when you instantiate. Note that the object ID of
the object returned by YAML.load is the same as the original, so it's
actually the same object.

require 'yaml'

class Foo
attr_reader :name
def initialize name
@name = name
end

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

foo = FOO1 = Foo.new("FOO1")

p foo
data = foo.to_yaml
puts(data)
foo = YAML.load(data)
p foo

__END__

#<Foo:0xb7bff274 @name="FOO1">
--- !ruby/foo FOO1
#<Foo:0xb7bff274 @name="FOO1">
 
B

Brian Buckley

class Foo
attr_reader :name
def initialize name
@name =3D name
end

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

Joel, I don't yet fully understand your code Where can I find
explanations of is_complex_yaml?, add_ruby_type, read_type_class and
quick_emit? (My original class doesn't actually have a "name"
attribute but maybe once I understand this better I can adapt).

Brian Buckley
 
J

Joel VanderWerf

Brian said:
Joel, I don't yet fully understand your code Where can I find
explanations of is_complex_yaml?, add_ruby_type, read_type_class and
quick_emit? (My original class doesn't actually have a "name"
attribute but maybe once I understand this better I can adapt).

Brian Buckley

I hope I'm wrong, but I don't think those are really documented anywhere.

I got to this point by adapting code in rubytypes.rb in the YAML lib
files. You could replace "name" with anything else that is YAML-able and
persistently identifies your objects.

I *think* is_complex_yaml? controls whether the object is persisted to a
single line of text or not.

My guess is that add_ruby_type(/^foo/) makes YAML recognize things in
the file that look like "!ruby/foo ...".
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,197
Messages
2,571,038
Members
47,633
Latest member
BriannaLyk

Latest Threads

Top