Forum: Ruby Marshaling classes

Posted by Damián M. González (igorjorobus)
on 2012-09-13 01:13
Guys, how are you?
 I'm stuck thinking about how can I save the state of a class. I want to
save the class variables of some classes. Do I have to require to
metaprogramming for this? I mean: save those variables in an object,
then dump it marshaling and then re-construct a class from that object
when is loaded. I'll try to explain the situation in an example:

class Dog
 @@quantity = 5
   def self.change_quantity=(n)
     @@quantity = n
   end
   def self.show_quantity
     @@quantity
   end
end

Dog.change_quantity = 99

File.open('anyfile.mrs', 'w+') do |f|
  Marshal.dump(Dog, f)
end

Dog.change_quantity = 50

Marshal.load(File.open('anyfile.mrs'))

Dog.show_quantity
#=> 50

#I want to show 99

 So as you can see I'm very confused. This is probably not the way to do
what I want, do you have any advice for me? The objetive is to save the
"state" of a class, save the values of all his class variables. Thanks.
Damián.
Posted by Ryan Davis (Guest)
on 2012-09-13 01:52
(Received via mailing list)
On Sep 12, 2012, at 16:13 , Damin M. Gonzlez <lists@ruby-forum.com> 
wrote:

> Guys, how are you?
> I'm stuck thinking about how can I save the state of a class. I want to
> save the class variables of some classes. Do I have to require to
> metaprogramming for this? I mean: save those variables in an object,
> then dump it marshaling and then re-construct a class from that object
> when is loaded. I'll try to explain the situation in an example:

Two ways I can think of off of the top of my head:

1) use `maglev-ruby -Mpersistent` to run your code and you're done.

> class Dog
> @@quantity = 5
>   def self.change_quantity=(n)
>     @@quantity = n
>   end
>   def self.show_quantity
>     @@quantity
>   end
> end


2) Rename your methods to reflect good ruby (def self.quantitiy and def 
self.quantity=) and then make them persist your values. Change the 
getter to a lazy accessor that will read in the value from disk (or 
whatever) and change the setter to persist the change back out.

def self.quantity
  @@quantity ||= Marshal.load(...) # or whatever
end
Posted by Brian Candler (candlerb)
on 2012-09-13 09:57
Unfortunately Marshal.dump doesn't dump even instance variables of a 
class, just the name of the class.

--8<----
class Dog
   @quantity = 5
   def self.change_quantity=(n)
     @quantity = n
   end
   def self.show_quantity
     @quantity
   end
end

Dog.change_quantity = 99

File.open('anyfile.mrs', 'w+') do |f|
  Marshal.dump(Dog, f)
end

Dog.change_quantity = 50

Dog2 = Marshal.load(File.open('anyfile.mrs'))

puts Dog.show_quantity   # 50
puts Dog2.show_quantity  # 50
puts Dog.object_id == Dog2.object_id   # true
--8<----

$ hexdump -C anyfile.mrs
00000000  04 08 63 08 44 6f 67                              |..c.Dog|
00000007

So I guess it's up to you to iterate over instance_variables:

--8<----
class IVDumper
  def initialize(klass)
    @klass = klass
    @ivs = {}
    klass.instance_variables.each do |k|
      @ivs[k] = klass.instance_variable_get(k)
    end
  end
  def restore
    @ivs.each do |k,v|
      @klass.instance_variable_set(k,v)
    end
    @klass
  end
end
def IVDumper(k)
  IVDumper.new(k)
end

Dog.change_quantity = 99

File.open('anyfile.mrs', 'w+') do |f|
  Marshal.dump(IVDumper(Dog), f)
end

Dog.change_quantity = 50

Marshal.load(File.open('anyfile.mrs')).restore

puts Dog.show_quantity   # 99
--8<----

You can probably make this more transparent, e.g using _dump/_load 
methods in IVDumper
Posted by Damián M. González (igorjorobus)
on 2012-09-13 15:20
Yes! Both advices help me a lot! Finally I've got to require to
metaprogramming for this case. Thank you both guys, for your knowledge.
Damián.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.