Search code examples
rubyserializationmarshalling

How to exclude an instance variable from marshal dump


My object contains an instance variable that point to a File object amongst several other attributes. Because of this Marshal cannot serialize it. How can I write a bespoke dump method so to exclude only that instance variable?

class Area
  attr_accessor :area
  attr_reader :several_other_attributes
  ........

  def initialize(name)
    @area = name
    @several_other_attributes = ....

    @log = File.open( 'test.log', 'w')
  end
end

Solution

  • You can very easily write a marshal_dump and marshal_load method that marshals all but a specified number of instance variables. Here's a fairly generic example of something you could do:

    class MarshalTest
      attr_reader :foo, :bar, :baz, :t
      UNMARSHALED_VARIABLES = [:@foo, :@bar]
    
      def initialize(foo = nil, bar = nil, baz = nil, t = nil)
        @foo = foo
        @bar = bar
        @baz = baz
        @t = t
      end
    
      def marshal_dump
        instance_variables.reject{|m| UNMARSHALED_VARIABLES.include? m}.inject({}) do |vars, attr|
          vars[attr] = instance_variable_get(attr)
          vars
        end
      end
    
      def marshal_load(vars)
        vars.each do |attr, value|
          instance_variable_set(attr, value) unless UNMARSHALED_VARIABLES.include?(attr)
        end
      end
    end
    

    Example usage:

    1.9.3-p550 :026 > m = MarshalTest.new(1, 2, 3, 4)
     => #<MarshalTest:0x007ff73194cae8 @foo=1, @bar=2, @baz=3, @t=4>
    1.9.3-p550 :027 > m.foo
     => 1
    1.9.3-p550 :028 > m.bar
     => 2
    1.9.3-p550 :029 > m.baz
     => 3
    1.9.3-p550 :030 > m.t
     => 4
    1.9.3-p550 :031 > s = Marshal.dump(m)
     => "\x04\bU:\x10MarshalTest{\a:\t@bazi\b:\a@ti\t"
    1.9.3-p550 :032 > n = Marshal.load(s)
     => #<MarshalTest:0x007ff73112b828 @baz=3, @t=4>
    1.9.3-p550 :033 > n.foo
     => nil
    1.9.3-p550 :034 > n.bar
     => nil
    1.9.3-p550 :035 > n.baz
     => 3
    1.9.3-p550 :036 > n.t
     => 4
    

    As you can see, the instance variables foo and bar were ignored in the marshaling/unmarshaling.