如何以编程方式删除实例上的"单例信息"以使其成为封送?

cri*_*ess 5 ruby singleton metaprogramming marshalling

我创建了一个无法编组的对象,因为"在运行时执行了单例元类定义"(这是对代码的正确描述吗?).

这是通过以下代码执行的:

# define class X that my use singleton class metaprogramming features
# through call of method :break_marshalling!
class X
   def break_marshalling!
     meta_class = class << self
       self 
     end
     meta_class.send(:define_method, :method_y) do 
      return 
    end
  end
end

# prepare my instance of X now
instance_of_x = X.new

# marshalling fine here
Marshal.dump instance_of_x

# break marshalling with metprogramming features
instance_of_x.break_marshalling!

Marshal.dump instance_of_x
# fails with TypeError: singleton can't be dumped 
Run Code Online (Sandbox Code Playgroud)

我该怎么做才能使对象编组正确?是否有可能从class X对象中"移除"单例组件instance_of_x

我真的需要一个建议,因为我们的一些对象需要通过Marshal.dump序列化机制进行缓存.这段代码在ruby-1.9.3中执行,但我希望它在ruby-2.0或ruby-2.1中表现相似

his*_*rat 6

(通常)删除单例信息的单行方式instance_of_x:

instance_of_x = instance_of_x.dup
Run Code Online (Sandbox Code Playgroud)


mde*_*tis 4

您可以定义自定义marshal_dumpmarshal_load方法

class X
  def break_marshalling!
    meta_class = class << self
      self 
    end
    meta_class.send(:define_method, :method_y) do 
      return 
    end
  end

  # This should return an array of instance variables
  # needed to correctly restore any X instance. Assuming none is needed
  def marshal_dump
    []
  end

  # This should define instance variables
  # needed to correctly restore any X instance. Assuming none is needed
  def marshal_load(_)
    []
  end
end

# Works fine
restored_instance_of_x = 
  Marshal.load Marshal.dump(X.new.tap { |x| x.break_marshalling! })

# Does not work
restored_instance_of_x.method_y
Run Code Online (Sandbox Code Playgroud)

如果您愿意,可以通过以下方式管理动态方法定义method_missing

class X
  def method_missing(name, *args)
    if name == :method_y
      break_marshalling!
      public_send name, *args
    else
      super
    end
  end
end

# Works fine
Marshal.load(Marshal.dump(X.new)).method_y
Run Code Online (Sandbox Code Playgroud)