2016-12-01 1 views
6

루비에서는 상수 조회가 중첩의 영향을 받고 메소드가 중첩을 유지합니다. 예를 들어Ruby에서 메소드의 중첩을 찾으려면 어떻게해야합니까?

, I는 이러한 모듈이있는 경우 : [Foo, B]의 중첩을 갖는

module Foo 
    module ::A 
    Module.nesting #=> [A, Foo] 
    def Foo.a 
     X 
    end 
    end 
end 

Foo.a #=> 1 

및 그 방법 Foo.b : I가 [A, Foo] 중첩되어있는 방법 Foo.a을 정의 할 수

module A 
    X = 1 
end 

module B 
    X = 2 
end 

module Foo 
end 

을 :

module B 
    module ::Foo 
    Module.nesting #=> [Foo, B] 
    def Foo.b 
     X 
    end 
    end 
end 

Foo.b #=> 2 
Foo::X = 3 

Foo.a #=> 1 <- still resolves to A::X 
Foo.b #=> 3 <- now resolves to Foo::X 

하지만 어떻게 주어진 방법의 중첩을 결정합니까 : 나는 Foo::X를 정의 할 경우3210의 차이는 분명하게?

+0

솔직히 말하면, 나는 왜'Foo.a'와'Foo.b'가 정의되어 있고 main에서 사용 가능한지조차 확신하지 못합니다. –

+0

@EricDuminil':: Foo' 때문에 최상위 상수를 나타냅니다. – Stefan

+0

최상위 모듈이 다른 모듈에 중첩 될 수 있다는 사실을 인식하지 못했습니다. – akuhn

답변

4

이 작동합니다 :

Foo.method(:a).to_proc.binding.eval('Module.nesting') 
#=> [A, Foo] 

Foo.method(:b).to_proc.binding.eval('Module.nesting') 
#=> [Foo, B] 

루비 2.2.1와 2.3.1로 테스트. Ruby 2.1.5에서는 작동하지 않습니다.

+1

예, 도움이됩니다, 감사합니다! – Stefan

+0

당신이 말했습니다. _ "내 전화로는 테스트 할 수 없습니다."_ - 이것이 행운의 추측입니까, 아니면 작동 할 것임을 알았습니까? – Stefan

+2

공식적인 루비 문서로 도움을받은 교육 수준이 높은 추측이라고 가정 해 보겠습니다. –

2

잘못된 방식으로 생각하고 있습니다. "메서드 중첩"과 같은 것은 없습니다. 상수는 어딘가에 중첩됩니다. 중첩은 모듈과 클래스의 이름에 연결된 경로 분석을가집니다. 메서드는 모듈/클래스 내에 포함됩니다 ("normal" 또는 싱글 톤이됩니다).


의미가있는 메소드가있는 곳. self과 비슷한 개념이 있는데,이 정의는 메서드가 정의 될 위치를 결정하며 기본 정의라고합니다. 거기에 대한 키워드는 없지만, 그것으로 거의 비슷이다 : 상수가 배치

kind_of?(Module) ? name : self.class.name 

은 /를 위해 순수하게 구문입니다 검색. 당신이 X를 참조 할 때 당신이 그것을 배치하는 경우, 그것은 방법 여부를 조금도 신경 쓰지 않습니다

DEEP_MIND = Object.new 

module Foo 
    X = 42 
end 

module Foo 
    module Bar 
    def DEEP_MIND.talk 
     p X 
    end 
    end 
end 

DEEP_MIND.talk # => 42 

module Foo::Bar 
    def DEEP_MIND.talk 
    p X 
    end 
end 

DEEP_MIND.talk # => uninitialized constant 

모든 것이 관심에 대해 무엇 코드의 라인에 "현재 중첩" 어디를 그것을 참조하려고했습니다. 당신이 실제로"방법의 몸 내부의 현재 중첩"를 찾기 위해 원하는 경우


지금, 당신은 당신이 실제로있다 척 할 수있는 방법이 필요합니다.

슬프게도 나는 @Eric's answer에 나타난 것 이외의 다른 방법이 있다고 생각하지 않습니다. 블록을 instance_eval/instance_exec과 함께 사용하면 블록이 정의 된 위치가 중첩됩니다.

+0

_ "메소드의 중첩"과 같은 것은 없습니다. _ _ -하지만 메소드를 평가하려면 루비가 중첩을 알아야합니다. 필자의 예에서,'Foo.b'는 먼저'B :: X'와'Foo :: X'를 해결합니다. 그것은 단순히 정적으로':: B :: X '로 해석되지 않으며, 생성 시점에서의 중첩, 즉'[Foo, B]'를 존중합니다. – Stefan

+0

@Stefan * "그러나 방법을 평가하기 위해 Ruby는 중첩을 알아야합니다. * - 실제로는 아닙니다. 그것은 단지 호출 된 객체를 알아야합니다. 상수는 메서드에 의해 해결되지 않습니다. 코드의 현재 컨텍스트로 해결됩니다. 메소드가 현재 컨텍스트/클로저를 얻기위한 편리한 방법 인'# binding'을 가지고있다. 당신이 어디에 있든, 방법이든 아니든간에, 현재의 네 스팅은'Module.nesting'을 통해 접근 할 수 있습니다. 현재 바인딩을 사용합니다. 'binding.eval ('Module.nesting')'은 다른 컨텍스트를 가진 것처럼 다른 바인딩을 사용합니다. – ndn

+0

@Stefan, ok, 메소드가 바인딩을 알고 있고 바인딩 (메소드가 어디에 있든 관계없이)이 현재 중첩을 알고 있다고 말할 수 있습니다. 이러한 의미에서 메서드는 정의 된 위치의 현재 중첩을 알고 있습니다. 그러나 이것은 우발적 인 것입니다. 메서드가 상수와 비슷하게 중첩되어있는 것은 아닙니다. – ndn

관련 문제