我正在使用ruby marshaling在两个客户端之间发送数据。每个客户端都有一组类定义,它们将用于帮助加载封送数据。这些定义存储在外部ruby文件中,可以随时加载(但通常在启动时)
一个简单的用例是
但是,有时一个客户端发送的数据包含未在其他客户端定义中定义的对象,在这种情况下,另一个客户端应相应地更新其定义。
它可能是一个新的实例变量,应该添加到类xyz
的定义中,或者它可能是一个完全新的类。
Marshal#Load
遇到未定义的变量时,它会抛出异常(例如:undefined class / method abc
)。
我是否有办法接受此异常并相应地更新定义,以便客户端可以愉快地读取数据并将其写出来?
所有类都将包含Marshal已经知道如何编码/解码的数据,例如字符串,数组,哈希,数字等。没有任何数据需要自定义dump
/ {{1}方法。
答案 0 :(得分:1)
我的解决方案是自动创建类(和常量层次结构,即Foo::Bar::Baz
)并使类自动响应以属性访问尝试。
class AutoObject
def method_missing(*args,&b)
if args.size == 1
name = args[0]
if instance_variable_defined? "@#{name}"
self.class.send :attr_accessor, name
send(*args)
else
super
end
elsif args.size == 2 && args[0].to_s[/=$/]
name = args[0].to_s[0...-1]
if instance_variable_defined? "@#{name}"
self.class.send :attr_accessor, name
send(*args)
else
super
end
end
end
end
def Marshal.auto_load(data)
Marshal.load(data)
rescue ArgumentError => e
classname = e.message[%r(^undefined class/module (.+)$), 1]
raise e unless classname
classname.split("::").inject(Object) do |outer, inner|
if !outer.const_defined? inner
outer.const_set inner, Class.new(AutoObject)
else
outer.const_get inner
end
end
retry
end
这可以很容易地扩展到记录所有创建的类,甚至可以确定它们可能具有的实例变量。然后,这可以帮助您更新文件,也许以编程方式。