1

我正在使用 ruby​​ 编组在两个客户端之间发送数据。每个客户端都有一组类定义,它们将用于帮助加载封送数据。定义存储在外部 ruby​​ 文件中,他们可以随时加载(但通常在启动时)

一个简单的用例是

  • 客户端 A 编组转储数据并将其发送给客户端 B
  • 客户端 B 编组加载数据,然后将其写入文件

但是,有时一个客户端发送的数据包含其他客户端定义中未定义的对象,在这种情况下,另一个客户端应相应地更新其定义。

它可能是一个新的实例变量,应该添加到类的定义中,xyz或者它可能完全是一个新的类。

Marshal#Load当前只是在遇到未定义的变量时抛出异常(例如:未定义的类/方法abc)。

有没有办法让我接受这个异常并相应地更新定义,以便客户端可以愉快地读取数据并将其写出?

所有类都将包含 Marshal 已经知道如何编码/解码的数据,例如字符串、数组、哈希、数字等。不会有任何需要自定义dump/load方法的数据。

4

1 回答 1

2

My solution would be to automatically create the class (and constant hierarchy, i.e. Foo::Bar::Baz) and make the class autorespond to attribute access attempts.

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

This could easily be extended to log all classes created, and even to determine what instance variables they might have. Which could then aid you in updating the files, perhaps programatically.

于 2012-12-27T10:20:21.270 回答