2012-07-30 1 views
1

두 클라이언트간에 데이터를 보내려면 루비 마샬링을 사용하고 있습니다. 각 클라이언트에는 마샬링 된 데이터를로드하는 데 사용하는 클래스 정의 집합이 있습니다. 정의는 그들이 원하는 언제든지로드 할 수있는 외부 루비 파일에 저장됩니다 (하지만 보통은 시작할 때)마샬링 및 정의되지 않은 특성/클래스

간단한 사용 사례는 마샬링 데이터를 덤프 및로 전송

  • 클라이언트 것 클라이언트 B는
  • 클라이언트 B 원수는 데이터를로드 한 후이 경우, 파일 그러나

, 때로는 하나의 클라이언트가 다른 클라이언트의 정의에 정의되지 않은 객체를 포함하는 데이터를 전송하고 그것을 기록합니다 다른 고객은 그에 따라 정의를 pdate하십시오.

xyz 클래스의 정의에 추가해야하는 새 인스턴스 변수이거나 완전히 새로운 클래스 일 수 있습니다.

Marshal#Load은 현재 정의되지 않은 변수 (예 : 정의되지 않은 클래스/메소드 abc)로 실행될 때 예외를 throw합니다.

클라이언트가 데이터를 행복하게 읽고 쓸 수 있도록이 예외를 적용하고 정의를 업데이트하는 방법이 있습니까?

모든 클래스는 원수가 이미 정의 dump/load 방법을 필요로하는 데이터가되지 않습니다 등 문자열, 배열, 해시, 숫자로,/디코딩을 인코딩하는 방법을 알고 그 데이터가 포함됩니다.

답변

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 

이렇게하면 쉽게 생성 할 수있는 모든 클래스를 기록하고 심지어 인스턴스 변수를 결정할 수도 있습니다. 그러면 아마도 파일을 프로그램 적으로 업데이트하는 데 도움이 될 것입니다.

관련 문제