2011-03-14 5 views
3

다음은 거래입니다. 클래스 Box의 특정 인스턴스를 몇 가지 방법으로 확장해야합니다. 내가 살고있는 모듈을 포함 할 필요가있는 메소드와 박스 인스턴스가 이 될 수 있기를 원한다면, 모듈은 동적으로을 포함합니다. 지금 내가 평가 후면에 후크를 사용하고 있습니다 : 그것은 매우 잘 작동되지만모듈의 메소드를 클래스의 특정 인스턴스에 동적으로 추가하십시오.

class Box 
    def after_initialize 
    if self.injected_module.present? 
     eval("class << self; include #{self.injected_module}; end") 
    end 
    end 
end 

내가 평가를 사용할 때 난 정말 더러운 느낌. 내가 그런 일을 찾고 있어요 :

module_to_inject = self.injected_module 
self.eigenclass.class_eval do 
    include module_to_inject 
end 

하지만 난 같은 클래스 monkeypatching없이 class_eval를 실행하는 eigenclass를 얻을 수있는 게 아니에요 :

class Box; def eigenclass; class << self; self; end end end 

것은 아름다운 있는가 나를 위해 (그리고 신뢰할 수있는) 방법이?

답변

8

당신이 Box의 특정 인스턴스에 모듈에서 메소드를 추가 할 필요가 동적입니다 Kernel#extend있어서 동사 "주입"은 이미 Enumerable#inject에서 루비 의미, 이것이 설명하기위한 최선의 동사를 가지고 있기 때문에이

box.extend MyModule 

또한, "연장".

+0

고마워요! 그것은 매력처럼 일했습니다! –

3

나는 당신의 추론을 따라갈 수 없습니다. self.class.class_eval은 다음과 같이 예제에서 잘 작동합니다.

class Box 
    def after_initialize 
    self.class.class_eval do 
     include(self.injected_module) 
    end 
    end 
end 

편집 : 설명을 명확히합니다.

과 같이

사용 Object#extend (것 eigenclass에서 그들을 정의 등) 클래스 메소드와 같은 모듈의 방법을 포함 :

module MyModule 
    def method 
     puts "called from #{self.inspect}" 
    end 
end 

class Box 
    def self.injected_module 
     MyModule 
    end 

    def require_module 
     self.class.class_eval do 
      extend self.injected_module 
     end 
    end 
end 

b = Box.new 
b.require_module 
Box.method 
# prints "called from Box" 
+0

이 솔루션의 문제점은 _eigenclass_가 아닌 클래스 자체에 메소드를 추가한다는 것입니다. 이 방법은이 코드를 실행 한 후 다른 상자 인스턴스를 만드는 경우 인스턴스는 새 메서드를 얻을 것이다. 내가 만드는 인스턴스에 싱글 톤 메서드로 메서드를 포함 시키려고합니다! –

+0

나는 그 추론을 따라갈 수 없다. 당신은 "eigenclass"라는 개념을 혼란스럽게 생각합니다. "eigenclass"는 클래스와 동의어이며, 클래스에서 직접 호출되는 메소드 인'Box.method '와 같습니다. 그러나 여기서는 Module을 클래스에 포함하여 인스턴스 메서드를 정의합니다. 정확히 원하는 것을 명확히 할 수 있습니까? –

+0

내 생각에 싱글 톤 인스턴스를 반환하고 클래스 메서드로 추가 된 모듈의 메서드가 필요하므로 인스턴스에서 메서드를 호출하는 대신 Box.method를 호출 할 수 있습니다 (예 : Box.instance.method). . include 대신 [Object # extend] (http://www.ruby-doc.org/core/classes/Object.html#M001002)를 사용해야합니다. –

관련 문제