YAML and ruby classes

M

Matteo Cavalleri

I need to create some objects of different (custom) classes, in
different pages of my site, so I made some code that takes an array of
hashes and create the objects. the hashes are like this one:

h = { :class => Class1, :param1 => 'foo', :param2 => 'bar', etc }

and basically I do

object = h[:class].new(h)

everything works fine as long as the hash is defined inside the source
code. however in some case I need to create the same object in two
different file. to avoid writing the same hashes twice I though about
putting them in a YAML file but this method doesn't work anymore because
the class name is converted to a string instead of a reference to the
class, using !ruby/object creates the object but all the code inside the
initialize method seems to be never executed (or the instance variables
ovverrided after the inzialize method) so my objects don't work,
ClassName.to_yaml returns an error, etc...

is there a way to do what I want to do? putting the ashes in a file and
loading them as a source AFAIK creates other problem due to the
sandboxing made by mod_ruby, that's why I tried with yaml.
 
M

Mark Volkmann

I need to create some objects of different (custom) classes, in
different pages of my site, so I made some code that takes an array of
hashes and create the objects. the hashes are like this one:

h = { :class => Class1, :param1 => 'foo', :param2 => 'bar', etc }

and basically I do

object = h[:class].new(h)

everything works fine as long as the hash is defined inside the source
code. however in some case I need to create the same object in two
different file. to avoid writing the same hashes twice I though about
putting them in a YAML file but this method doesn't work anymore
because
the class name is converted to a string instead of a reference to the
class, using !ruby/object creates the object but all the code
inside the
initialize method seems to be never executed (or the instance
variables
ovverrided after the inzialize method) so my objects don't work,
ClassName.to_yaml returns an error, etc...

is there a way to do what I want to do? putting the ashes in a file
and
loading them as a source AFAIK creates other problem due to the
sandboxing made by mod_ruby, that's why I tried with yaml.

It seems to me this is a fundamental problem with YAML. Even if you
were trying to put all the data in one file, I don't believe the YAML
spec. addresses writing object references instead of objects. This is
especially an issue when your objects have circular references.

This caused me to use XML instead of YAML for a recent Java project
because the Java XStream library handles serializing and
deserializing Java objects that have circular references.

If there is a YAML solution to this, I'd love to hear about it!
 
A

ara.t.howard

It seems to me this is a fundamental problem with YAML. Even if you were
trying to put all the data in one file, I don't believe the YAML spec.
addresses writing object references instead of objects. This is especially an
issue when your objects have circular references.
This caused me to use XML instead of YAML for a recent Java project because
the Java XStream library handles serializing and deserializing Java objects
that have circular references.

If there is a YAML solution to this, I'd love to hear about it!

harp:~ > ruby -r yaml -e' h = {}; h[:h] = h; y h '
&id001
:h: *id001


regards.

-a
 
M

Mark Volkmann

It seems to me this is a fundamental problem with YAML. Even if
you were trying to put all the data in one file, I don't believe
the YAML spec. addresses writing object references instead of
objects. This is especially an issue when your objects have
circular references.
This caused me to use XML instead of YAML for a recent Java
project because the Java XStream library handles serializing and
deserializing Java objects that have circular references.

If there is a YAML solution to this, I'd love to hear about it!

harp:~ > ruby -r yaml -e' h = {}; h[:h] = h; y h '
&id001
:h: *id001

My apologies! Apparently the problem is with the Java implementation
of YAML that I was using and not with YAML itself. Here's a more full
example that demonstrates YAML doing the right thing with multiple
references to the same object and with circular references.

---

require 'yaml'

class Person
attr_accessor :name, :spouse, :address

def to_s
"\n#{name} is married to #{spouse.name} and lives at\n#{address}"
end
end

class Address
attr_accessor :street, :city, :state, :zip

def to_s
"#{street}\n#{city}, #{state} #{zip}"
end
end

a = Address.new
a.street = "644 Glen Summit"
a.city = "St. Charles"
a.state = "MO"
a.zip = 63304

p1 = Person.new
p1.name = "Mark Volkmann"
p1.address = a

p2 = Person.new
p2.name = "Tami Volkmann"
p2.address = a

p1.spouse = p2
p2.spouse = p1

people = [p1, p2]
yaml_string = YAML::dump(people)
puts yaml_string

new_people = YAML::load(yaml_string)
puts new_people

---

The output is

---
- &id002 !ruby/object:person
address: &id001 !ruby/object:Address
city: St. Charles
state: MO
street: 644 Glen Summit
zip: 63304
name: Mark Volkmann
spouse: &id003 !ruby/object:person
address: *id001
name: Tami Volkmann
spouse: *id002
- *id003

Mark Volkmann is married to Tami Volkmann and lives at
644 Glen Summit
St. Charles, MO 63304

Tami Volkmann is married to Mark Volkmann and lives at
644 Glen Summit
St. Charles, MO 63304
 
K

Ken Bloom

I need to create some objects of different (custom) classes, in
different pages of my site, so I made some code that takes an array of
hashes and create the objects. the hashes are like this one:

h = { :class => Class1, :param1 => 'foo', :param2 => 'bar', etc }

and basically I do

object = h[:class].new(h)

everything works fine as long as the hash is defined inside the source
code. however in some case I need to create the same object in two
different file. to avoid writing the same hashes twice I though about
putting them in a YAML file but this method doesn't work anymore because
the class name is converted to a string instead of a reference to the
class, using !ruby/object creates the object but all the code inside the
initialize method seems to be never executed (or the instance variables
ovverrided after the inzialize method) so my objects don't work,
ClassName.to_yaml returns an error, etc...

is there a way to do what I want to do? putting the ashes in a file and
loading them as a source AFAIK creates other problem due to the
sandboxing made by mod_ruby, that's why I tried with yaml.

If you reference the class object directly, you can't dump it to yaml, so
try using a string instead, and running eval on the string to get the
class object.

h = { :class => 'Class1', :param1 => 'foo', :param2 => 'bar', etc }
object = eval(h[:class]).new(h)

This gives you the following YAML:
 
J

Joel VanderWerf

Matteo said:
I need to create some objects of different (custom) classes, in
different pages of my site, so I made some code that takes an array of
hashes and create the objects. the hashes are like this one:

h = { :class => Class1, :param1 => 'foo', :param2 => 'bar', etc }

and basically I do

object = h[:class].new(h)

everything works fine as long as the hash is defined inside the source
code. however in some case I need to create the same object in two
different file. to avoid writing the same hashes twice I though about
putting them in a YAML file but this method doesn't work anymore because
the class name is converted to a string instead of a reference to the
class, using !ruby/object creates the object but all the code inside the
initialize method seems to be never executed (or the instance variables
ovverrided after the inzialize method) so my objects don't work,
ClassName.to_yaml returns an error, etc...

is there a way to do what I want to do? putting the ashes in a file and
loading them as a source AFAIK creates other problem due to the
sandboxing made by mod_ruby, that's why I tried with yaml.

It is possible to extend YAML to serialize classes:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/177604

It seems to still work with ruby-1.8.6.

It lets you do this:

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

with output:

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

However, if you are hand-editing the YAML file, you may find that a
class name string is more convenient than this notation.

YYAMLMMV
 
M

Matteo Cavalleri

Joel VanderWerf said:
However, if you are hand-editing the YAML file, you may find that a
class name string is more convenient than this notation.

I think i'll go for the class name string :) but thanks for the link to
the extension. as I'm still learning ruby it was very interesting.
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top