경고 : 이것은 약간 길다. Ruby 소스 코드를 통한 약간의 둘러보기는 문서가 약간 얇기 때문에 필요합니다. 소시지를 만드는 방법에 신경 쓰지 않는다면 끝까지 건너 뛸 수 있습니다.
1.9.2 Module.nesting
는 다음과 같이 eval.c
에서 구현됩니다
static VALUE
rb_mod_nesting(void)
{
VALUE ary = rb_ary_new();
const NODE *cref = rb_vm_cref();
while (cref && cref->nd_next) {
VALUE klass = cref->nd_clss;
if (!(cref->flags & NODE_FL_CREF_PUSHED_BY_EVAL) &&
!NIL_P(klass)) {
rb_ary_push(ary, klass);
}
cref = cref->nd_next;
}
return ary;
}
내가 아니라 그 루비 내부를 모르지만 나는 while
이 같은 루프 읽어 연결된 cref
에서 추출 클래스와 비슷한 것이지만 eval
에서 나오지 않은 모든 노드를 나열하십시오. NODE_FL_CREF_PUSHED_BY_EVAL
비트는 여기에서 설정됩니다
/* block eval under the class/module context */
static VALUE
yield_under(VALUE under, VALUE self, VALUE values)
좀 더 grepping 읽기는 instance_eval
가 yield_under
을 겪고 결국 않음을 알 수있다. 독자의 연습 문제로는 instance_exec
, module_eval
및 module_exec
을 남겨 두겠습니다. 어쨌든 은 Module.nesting
목록에서 명시 적으로 제외됩니다. 그러나 이것은 다른 어떤 것보다 산만 함보다 더 중요합니다. 그것은 단지 여러분이 언급 한 진리를 보지 못하게된다는 것을 의미합니다.
이제 질문은 "NODE
과 rb_vm_cref()
은 무엇에 관한 것입니까?"입니다.
당신이 node.h
에서 보면 당신은 다양한 루비 키워드와 언어 구조에 대한 NODE 상수의 무리 볼 수 있습니다 :
NODE_BLOCK
NODE_BREAK
NODE_CLASS
NODE_MODULE
NODE_DSYM
을
- ...
그래서 NODE
은 명령어 트리의 노드입니다. 최대 잘 내
Module.nesting
이 라인은 주석에 파서에
추측을 이야기에 대한 자세한 것 같다. 하지만 어쨌든 우리는 계속 갈 것입니다.
rb_vm_cref
함수는 vm_get_cref0
에 대한 래퍼 인 vm_get_cref
에 대한 래퍼입니다. vm_get_cref0
은 무엇에 관한 것입니까?
static NODE *
vm_get_cref0(const rb_iseq_t *iseq, const VALUE *lfp, const VALUE *dfp)
{
while (1) {
if (lfp == dfp) {
return iseq->cref_stack;
}
else if (dfp[-1] != Qnil) {
return (NODE *)dfp[-1];
}
dfp = GET_PREV_DFP(dfp);
}
}
함수에 세 가지 인수가 직선이 제어 프레임 밖으로 나와 :
이
rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(th, th->cfp);
iseq
이 명령의 순서로 나타나고는 lfp
및 dfp
프레임 포인터는 이것에 대해 전부입니다 :
VALUE *lfp; // cfp[6], local frame pointer
VALUE *dfp; // cfp[7], dynamic frame pointer
cref_stack
의 정의는 관련이 :
/* klass/module nest information stack (cref) */
NODE *cref_stack;
따라서 어떤 종류의 호출 또는 중첩 스택이 rb_vm_cref
인 것으로 보입니다.
이제 당면 세부 사항으로 돌아갑니다. 이 작업을 수행 할 때 :
module A
p Module.nesting
end
당신은 아직 end
을 명중하지 않은으로합니다 (Module.nesting
결과 배열을 생산하기 위해 여과 있음) cref
링크 된 목록에 module A
을해야합니다. 당신이이 말을 할 때 : 이미 end
가 스택에서 module A
을 팝 히트했기 때문에
A.instance_eval { puts Module.nesting }
A.instance_exec { puts Module.nesting }
A.module_eval { puts Module.nesting }
A.module_exec { puts Module.nesting }
당신은 더 이상 cref
에서 module A
이 없습니다. 그러나, 당신이 할 경우이 다음 module A
가 폐쇄 (그리고 cref
을 튀어)되지 않았기 때문에
[A]
[A]
[A]
[A]
아직 :이 출력을 볼 수
module A
instance_eval { puts Module.nesting.inspect }
instance_exec { puts Module.nesting.inspect }
module_eval { puts Module.nesting.inspect }
module_exec { puts Module.nesting.inspect }
end
.
이 모듈의 목록이 호출의 시점에서 중첩 반환
는
Module.nesting
documentation이 말한다, 마무리합니다.
이 문장은 내부 검토를 통해 Module.nesting
이 실제로 호출되는 특정 문자 컨텍스트에 의존 함을 나타냅니다.
Ruby 내부에서 더 많은 경험을 가진 사람이 있으면 추가 할 항목이 있으므로 커뮤니티 위키로 SO 커뮤니티에 넘겨 줄 수 있습니다.
UPDATE :이 모든뿐만 아니라이 module_eval
에처럼 class_eval
에 적용하고 또한 그것뿐만 아니라이 1.9.2에처럼 1.9.3에 적용됩니다.
[ "호출 지점에 중첩 된 모듈 목록을 반환합니다]"(http://ruby-doc.org/core/classes/Module.html#M000441)하지만 말할 때 열린 '모듈'이 없습니다. 'A.module_eval' 당신은'A'의 맥락에서 행동하고 있습니다. 'Module.nesting'은 루비 실행 환경보다 파서와 더 많이 대화하는 것 같습니다. –
@mu가 너무 짧습니다. 귀하의 의견에 영감을 받아, 제 질문에 추가했습니다. – sawa