Forum: Ruby yaml object de-serialisation

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
unknown (Guest)
on 2006-02-09 13:48
(Received via mailing list)
i've a class "Preferences"
which includes other classes for example "Theme"

i save an instance of "Preferences" by writing self.to_yaml into a file.

obviously, i want to retrive this instance back by :
o=YAML::load(File.open("#{PREFS_FILE}"))

PREFS_FILE being the preceedingly saved one.

what's the best way to "re-populate" my classes ?

for the time being i'm doing :

        o.themes_list.each { |theme|
          t=Theme.new(theme.label)
          t.nb_cols_list=theme.nb_cols_list
          @themes_list << t
        }
[...]
        @theme_label=o.theme_label
        @nb_cols=o.nb_cols


does exist a more direct way to do the samething ?
David V. (Guest)
on 2006-02-09 15:20
(Received via mailing list)
DÅ?a Å tvrtok 09 Február 2006 12:48 Une bévue napísal:
> what's the best way to "re-populate" my classes ?
>         @nb_cols=o.nb_cols
>
>
> does exist a more direct way to do the samething ?

I thought YAML does deep serialization? It should load this
automatically.

What do you mean by Preferences including Themes? If you mean instances
of
Theme are instance variables of Preferences, or are stored in an Array
in
Preferences, you shouldn't need to repopulate anything.

I didn't quite understand the intent of your code, but it looks like
you're
doing copies of themes from o.themes_list to another Array
@themes_list...
Why can't you keep them in the original object "o" and access them from
there?

David V.
unknown (Guest)
on 2006-02-09 15:38
(Received via mailing list)
David V. <removed_email_address@domain.invalid> wrote:

First, thanks for your reply ))

> What do you mean by Preferences including Themes? If you mean instances of
> Theme are instance variables of Preferences, or are stored in an Array in
> Preferences, you shouldn't need to repopulate anything.
>
yes i have another class Theme and Preferences class includes an array
of instances of Theme.

> I didn't quite understand the intent of your code, but it looks like you're
> doing copies of themes from o.themes_list to another Array @themes_list...
> Why can't you keep them in the original object "o" and access them from
> there?

ok, i see xhat you mean.

three cases :

- first launch of this app whithout any prefs saved:

i create a default prefs by :

prefs=Preferences.new blahblahblah

prefs.save  #ie to a yaml file

- not first launch of this app with an instance of Preferences saved :

prefs=YAML::load(File.open("#{PREFS_FILE}"))

that's all


now the third case i've an old way to save prefs into a yaml file,
basically a hash instead of an instance of Preferences

in that case i only have to add another method to the Preferences class,
saying :

prefs=Preferences.new
prefs.updateFromOlderFileStructure

prefs.save

again, that's all.

am i right ?
David V. (Guest)
on 2006-02-09 17:01
(Received via mailing list)
DÅ?a Å tvrtok 09 Február 2006 14:38 Une bévue napísal:
> prefs.save
>
> again, that's all.
>
> am i right ?

Ah, this third case wasn't quite obvious from your example. But yes,
you're
stuck to adapting the old preference structure to the new more or less
by
hand. This doesn't seem like a particularly error prone piece of code,
so I'd
stick with whatever seems to work for now, direct or indirect. As long
as it
works...

You could possibly golf down your script by having the new Theme object
take
as constructor parameters the whole old corresponding object, but I
don't
quite like this sort of coupling of compatibility code in the main
logic.

David V.
Joel VanderWerf (Guest)
on 2006-02-09 22:44
(Received via mailing list)
Une bévue wrote:
> what's the best way to "re-populate" my classes ?
>         @nb_cols=o.nb_cols
>
>
> does exist a more direct way to do the samething ?

This may be helpful, or at least interesting:

http://raa.ruby-lang.org/project/preferences/
http://redshift.sourceforge.net/preferences/doc/index.html

It's a way of automating the configuration of objects from a
hierarchical hash stored in a YAML file. It works with existing
accessors, so it's very easy to use with a GUI toolkit. See
examples/foursplit-prefs.rb for a version of the FXRuby foursplit.rb
example, but using Preferences.
unknown (Guest)
on 2006-02-24 19:46
(Received via mailing list)
David V. <removed_email_address@domain.invalid> wrote:

> You could possibly golf down your script by having the new Theme object take
> as constructor parameters the whole old corresponding object, but I don't
> quite like this sort of coupling of compatibility code in the main logic.

that's a "small" prob to me, i've used java where i might have multiple
constructors...

now to workaround i have build an initialize which returns all of its
attributes to nil or the like ([] in case of arrays)

a defaults method which populate de prefs with default values

an updateFromHash(o) which updates prefs from older structure.

suppose now, in the live of this app, i'll add some new attributes to
the class Preferences, what is the behaviour of yaml in that case ?

i suppose the new attributes (if an instance of Preferences is loaded
from older attributes list) will be nill ?
David V. (Guest)
on 2006-02-24 19:46
(Received via mailing list)
DÅ?a Å tvrtok 09 Február 2006 15:33 Une bévue napísal:
> David V. <removed_email_address@domain.invalid> wrote:
> > You could possibly golf down your script by having the new Theme object
> > take as constructor parameters the whole old corresponding object, but I
> > don't quite like this sort of coupling of compatibility code in the main
> > logic.
>
> that's a "small" prob to me, i've used java where i might have multiple
> constructors...
>

Constructors are just cleverly disguised initializers. Have #initialize
only
do the completely common code, and then explicitly call other
initializer
methods you define if you want this pattern. I personally consider
method
overloading a slight misfeature of the C++ language family, and have
grown
quite accustomed to using the more flexible "options hash" pattern
instead.
For example, if you have some class with instance variables bar, baz,
and
quux:

	class Foo
		DEFAULTS = {
			:bar => 1,
			:baz => 2,
			:quux => 3
		}

		attr :bar
		attr :baz
		attr :quux

		def initialize(params)
			attribs = DEFAULTS.dup.update(params)
			@bar = attribs[:bar]
			@baz = attribs[:baz]
			@quux = attribs[:quux]
		end
	end

	foo = Foo.new(:bar = "Hello", :quux => "World")

	p foo # Outputs #<Foo:0xb7c8004c @bar="Hello", @quux="World", @baz=2>

I find this covers 90% of what you commonly use overloaded constructors
for,
and is a bit more readable too.

> now to workaround i have build an initialize which returns all of its
> attributes to nil or the like ([] in case of arrays)
>
> a defaults method which populate de prefs with default values
>
> an updateFromHash(o) which updates prefs from older structure.

If the above pattern doesn't cover what you need, you can always create
more
factory methods to crunch for example the old structure into one the
constructor will like better.

>
> suppose now, in the live of this app, i'll add some new attributes to
> the class Preferences, what is the behaviour of yaml in that case ?
>
> i suppose the new attributes (if an instance of Preferences is loaded
> from older attributes list) will be nill ?

Yes, the YAML loader doesn't know anything about what instance
attributes the
object is supposed to have. AFAIK, it uses Object::allocate to create a
blank
instance of the class, then populates the instance variables via
Object#instance_variable_set, or something equivalent.
Mark V. (Guest)
on 2006-02-24 19:46
(Received via mailing list)
On 2/9/06, David V. <removed_email_address@domain.invalid> wrote:

>                 }
>                 end
>         end
>
>         foo = Foo.new(:bar = "Hello", :quux => "World")
>
>         p foo # Outputs #<Foo:0xb7c8004c @bar="Hello", @quux="World", @baz=2>
>
> I find this covers 90% of what you commonly use overloaded constructors for,
> and is a bit more readable too.

I'd never seen this before. Cool!

I think you can use
attribs = DEFAULTS.merge(param)
instead of
attribs = DEFAULTS.dup.update(params)
unknown (Guest)
on 2006-02-24 19:46
(Received via mailing list)
David V. <removed_email_address@domain.invalid> wrote:

> If the above pattern doesn't cover what you need, you can always create more
> factory methods to crunch for example the old structure into one the
> constructor will like better.

yes, that's another solution. I'll think about your above solution
(options hash) because i don't like the way i've done that actually
mostly because, i, my case, the #initialize is more orl es a fake
initialise : it returns somehow an empty object.
> Object#instance_variable_set, or something equivalent.
OK, thanks for all.
David V. (Guest)
on 2006-02-24 19:46
(Received via mailing list)
DÅ?a Å tvrtok 09 Február 2006 22:12 Mark V. napísal:
> I'd never seen this before. Cool!
>

I saw this on some page about ruby idioms somewhere. Might have been the
RubyGarden one. Or the RAA library interface design guidelines. I think
those
are very roughly a ripoff from Perl's, and I don't necessarily like
them, and
I didn't like this idiom at first. But then I saw this other snippet
where
the default parameters were used and suddenly it made Perfect Sense
(tm).


This is used all over the place in Rails, and the options hash is useful
outside constructors too. I find it generally both more readable and
comfortable to use than having multiple methods accept different
combinations
of parameters, especially since you get the perks of keyword arguments
(arbitrary argument order) along. You might want to check for typos by
being
strict about what keys / combinations of keys you accept in the options
hash,
and convert the keys to symbols or vice versa depending on what you
except.

> I think you can use
> attribs = DEFAULTS.merge(param)
> instead of
> attribs = DEFAULTS.dup.update(params)
>

*bangs head against wall*

I should really, really start reading ri output better. I knew about
Hash#update, but I didn't actually go on and notice it's a synonym for
Hash#merge! when I checked ri. D'oh!

David V.
This topic is locked and can not be replied to.