2009-06-11 2 views
5

나는 호기심 질문이 있습니다. Ruby 클래스가 있고 클래스 메소드, 클래스 변수 등을 동적으로 추가하면 실행되는 동안 변경된 클래스 정의를 저장할 수 있으므로 다음에 응용 프로그램을 시작할 때 다시 사용할 수 있습니다.동적 루비 클래스 저장

답변

1

개체를 마샬링하기 만하면됩니다 (다른 사람들이 말한 것처럼). 예제를 보자.

class Extras 
    attr_accessor :contents 
    def test 
    puts "This instance of Extras is OK. Contents is: " + @contents.to_s 
    end 

    def add_method(name) 
    self.class.send :define_method, name.to_sym do 
     puts "Called " + name.to_s 
    end 
    end 
end 

지금 인스턴스를 생성하는 프로그램을 작성할 수 있습니다

그것에 방법을 추가하고 디스크에 저장 :

require 'extras' 

fresh = Extras.new 
fresh.contents = 314 
fresh.test # outputs "This instance of Extras is OK. Contents is: 314" 
fresh.add_method(:foo) 
fresh.foo # outputs "Called foo" 

serial = Marshal.dump(fresh) 
file = File.new "dumpedExample", 'w' 
file.write serial 

그래서 우리는 정상적인 방법을 호출 할 수있는 '시험'이 클래스를 고려 동적 메서드 'foo'. 우리가 디스크에 저장 한 예의 예를로드하는 프로그램 작성하는 경우 어떻게되는지 살펴 봅시다 :

require 'extras' 

file = File.new 'dumpedExample', 'r' 
serial = file.read 

reheated = Marshal.load(serial) 
reheated.test # outputs "This instance of Extras is OK. Contents is 314" 
reheated.foo # throws a NoMethodError exception 

그래서 우리가 볼 수있는 그런 (멤버 변수의 값을 포함) 인스턴스는 동적 방법을 저장하는 동안 아니였다.

디자인 관점에서 보면, 추가 된 모든 코드를 모듈에 넣고 다음에 프로그램을 실행할 때 클래스에 다시로드하는 것이 좋습니다. 우리는 이것을 실제로 알고 싶어하지만 어떻게 사용하고 싶은지에 대한 좋은 예가 필요합니다.

메서드를 다시 만들려면 추가 정보가 필요하면 모듈에서이를 멤버 변수로 저장하게하십시오. 모듈에 included을 구현하고 클래스에 포함될 때 이러한 멤버 변수를 찾습니다.

-1

즉석에서 수업을 수정하고 싶으시겠습니까? 마샬 모듈을 사용하면 파일에 객체를 저장하고 메모리에서 동적으로 다시 읽을 수 있습니다.

4

이 작업을 수행 할 내장 방법은 없습니다. 마샬은 방법을 저장할 수 없습니다. 이러한 방법과 변수가 체계적으로 생성되면 클래스에 필요한 데이터를 저장하여 다시 만들 수 있습니다. 예를 들어 이러한 메서드를 정의하는 make_special_method(purpose, value) 메서드가있는 경우 이러한 메서드에 전달해야하는 인수 배열을 만들어 클래스 상태를 다시 구성해야합니다.

2

정확히 무슨 뜻인지에 따라이 문제를 해결할 수있는 몇 가지 방법이 있습니다.

가장 간단한 경우는이 예에서와 같이 이미 존재하는 클래스에 변수 나 메소드를 추가 한 하나입니다 : 여기

class String 
    def rot13 
    return self.tr('a-z', 'n-za-m') 
    end 
end 

우리는 String 클래스에 ROT13 방법을 추가했습니다. 이 코드를 실행하자마자 프로그램의 모든 문자열은 # rot13 수 있습니다. 따라서 rot13을 사용할 수있는 문자열이 필요한 코드가 있으면 위 코드가 문제의 코드 앞에 실행되는지 확인해야합니다. rot13 코드를 파일에 넣고 require()하면됩니다. 아주 쉽게!

그러나 어쩌면 당신은 클래스에 클래스 변수를 추가 한, 당신은 같이 그 존재하지만 그 값 단지를 유지하려면 : 이제 당신의 값을 저장하려면

class String 
    @@number_of_tr_calls_made = 0 
    # Fix up #tr so that it increments @@number_of_tr_calls_made 
end 

@ @number_of_tr_calls_made를 사용하면 마샬 라이브러리를 통해 다른 직렬화 가능 루비 값과 동일한 방식으로 변환 할 수 있습니다. 또한 쉽게!

그러나 당신이 당신의 질문을 표현한 방식에 뭔가가 날 수는이 같은 일을하고 있다는 의심 :

greeting = "Hello" 
class <<greeting 
    def rot13 
    return self.tr('a-z', 'n-za-m') 
    end 
end 
encrypted_greeting = greeting.rot13 

이것은 우리가 첫 번째 예제에서했던 것과 매우 다르다. 이 코드는 프로그램의 모든 String에 rot13 자체의 힘을 부여했습니다. 이 코드는 '인사'라는 이름으로 참조 된 객체에만 권한을 부여합니다. 내부적으로 Ruby는 String의 익명 Singleton 서브 클래스를 생성하고 rot13 메소드를 추가 한 다음 익명 서브 클래스로 인사 장의 클래스를 변경함으로써이를 수행합니다.

여기서 문제는 Singletons가 Marshal'd 일 수 없다는 것입니다. Marshal.load를 호출하면 기존 Singleton 개체의 복사본을 생성 할 수있는 이유를 알 수 있습니다. 이제 인사말에는 상속 계층 구조에 Singleton이 있으므로 저장 및로드하려면 hose가 필요합니다. 대신 하위 클래스를 만드십시오.

class HighlySecurableString < String 
    def rot13 
    return self.tr('a-z', 'n-za-m') 
    end 
end 
greeting = HighlySecurableString.new("hello") 
+0

나는 asker가 실행 중에 클래스에 추가 된 메소드를 참조한다고 생각한다. 나는. 메타 프로그래밍 된 방법. 나는 오해했을지도 모른다. – toholio