2014-11-26 2 views
1

실제로 문제는 루비 메타 프로그래밍의 내 오해에 대해됩니다 : 여기 내 질문을 삭제하려면 :실행 클래스 수준의 기능을 동적으로

module Mappable 
    def self.included(klass) 
    klass.class_eval do 
     class << self 
     attr_accessor :source 
     end 
    end 
    end 
end 

나의 이해 : 내가 좋아하는 내 모듈 중 하나의 작업 코드를 여기서 일어나는 일은 : 코드 "attr_accessor : source"를 평가하기 위해 Mappable 모듈을 포함하는 클래스가 무엇이든간에.

다음은 "< <"등급은 무엇입니까? "attr_accessor : source"를 "klass.class_eval"로 이미 평가 한 경우 감사합니다!

답변

1

여기에 무슨 일이 일어나는지 설명하는 데 도움이되는 몇 가지 코드가 있습니다. 나는 약간의 설명을 추가 할 것이다. 여기

module Mappable 
    def self.included(klass) 
    puts "klass = #{klass}" 
    puts "self before class_eval = #{self}" 
    klass.class_eval do 
     puts "self after class_eval and before class << self = #{self}" 
     class << self 
     puts "self after class << self = #{self}" 
     attr_accessor :source 
     end 
    end 
    end 
end 

class A 
    include Mappable 
    attr_accessor :source 
    @source = 'cat' 
    def initialize 
    @source = 'dog' 
    end 
end 

MappableAinclude D되는 결과 :

#-> klass = A 
#-> self before class_eval = Mappable 
#-> self after class_eval and before class << self = A 
#-> self after class << self = #<Class:A> 

klass.class_eval (A.class_eval)은 Mappable에서 A하는 문맥 (self의 값)을 변경하는 것을 알 수있다. class << self (class << A) 그러면 A의 싱글 톤 클래스로 컨텍스트가 변경됩니다.이 메서드는 attr_accessor 메서드를 실행하여 클래스 인스턴스 변수 @source에 대한 읽기/쓰기 접근자를 만듭니다.

A.methods(false) 
    #=> [:source, :source=] 
A.instance_variables 
    #=> [:@source] 

A.source 
    #=> "cat" 
A.source = 'pig' 
A.source 
    #=> "pig" 

이것은 우리가 @a 변수 클래스 인스턴스 생성 한 접근이 제대로 작동 것으로 보인다 보여줍니다. 이제 인스턴스 메소드와 인스턴스 변수를 살펴 보겠습니다.

A.instance_methods(false) 
    #=> [:source, :source=] 
a = A.new 
    #=> #<A:0x000001018fdc78 @source="dog"> 
a.instance_variables 
    #=> [:@source] 
a.source 
    #=> "dog" 
a.source = 'cow' 
    #=> "cow" 
a.source 
    #=> "cow" 

괜찮은 것 같습니다. Aa에는 각각 인스턴스 변수 @source이 있지만 두 변수는 관련이 없다는 것을 이해하는 것이 중요합니다. 마지막으로, 우리는 클래스 인스턴스 변수의 값에 영향을 미치지 않았다의 인스턴스 변수의 값을 변경에 다음 사항을 확인하자 :

A.source 
    #=> "pig" 

하기 위해, A의 싱글 톤 클래스에 컨텍스트를 변경하는 다른 방법이 있습니다 메소드 attr_accessor을 실행하십시오. 차라리 루비 1.9.2부터 우리와 함께하고있다 Object#singleton_class를 사용하는 발견 해요 :

def self.included(klass) 
    klass.singleton_class.class_eval do 
    attr_accessor :source 
    end 
end   
+0

와우, 이런, 감사합니다! 업데이트를 기대하지만이 자체는 훌륭한 설명입니다. –

관련 문제