2012-07-30 65 views
1

我正在使用ruby封送器在兩個客戶端之間發送數據。每個客戶端都有一組類定義,它們將用來幫助加載編組數據。該定義存儲在外部ruby文件,他們可以加載任何時候他們想要的(但通常,當他們啓動)封送和未定義的屬性/類

一個簡單的例子是

  • 客戶端A元帥轉儲數據並將其發送到客戶端B
  • 客戶端B編組加載的數據,然後將其寫入到一個文件

然而,有時一個客戶端發送包含未在其他客戶端的定義所定義的對象的數據,在這種情況另一個客戶應該是你相應地更新其定義。

它可能是一個新的實例變量,應該添加到類xyz的定義中,或者它可能完全是一個新類。

Marshal#Load當前剛剛拋出一個異常,當它運行到一個未定義的變量(例如:undefined類/方法abc)。

有沒有辦法讓我採取這種例外並相應地更新定義,以便客戶端可以愉快地讀取數據並寫出來?

所有類都將包含Marshal已經知道如何編碼/解碼的數據,例如字符串,數組,哈希,數字等。不會有任何數據需要自定義方法dump/load方法。

回答

1

我的解決方案是自動創建類(和恆定的層次結構,即Foo::Bar::Baz),並使類autorespond屬性訪問嘗試。

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 

這可以很容易地擴展到記錄所有創建的類,甚至可以確定它們可能具有的實例變量。這可以幫助你更新文件,也許編程。