警告:这有点漫长。由于文档有点简单,浏览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;
}
我不知道Ruby的内部是很好,但我读了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
作为读者的练习。在任何情况下,看起来instance_eval
明确排除在Module.nesting
列表中;然而,这比其他任何事都更让人分心,它只是意味着你不会看到提及的事物。
所以现在的问题是“什么是NODE
和rb_vm_cref()
?”。
如果您在node.h
看,你会看到不同的Ruby关键词和语言结构一堆NODE常量:
NODE_BLOCK
NODE_BREAK
NODE_CLASS
NODE_MODULE
NODE_DSYM
- ...
所以我猜想NODE
是指令树中的一个节点。我
Module.nesting
了很好的这行似乎更多有关评论谈话的解析器
猜想。但我们会继续前进。
rb_vm_cref
函数只是vm_get_cref
的包装,它是vm_get_cref0
的包装。什么是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
你必须module A
在cref
链表(被过滤以产生Module.nesting
结果数组)你有没有打end
呢。当你说的这些:
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
了,因为你已经打了end
弹出module 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
你会看到这样的输出:
[A]
[A]
[A]
[A]
因为module A
尚未关闭(和弹出cref
)呢。
要玩完的Module.nesting
documentation这样说:
返回嵌套在呼叫点的模块列表。
我认为这句话结合内部审查表明,Module.nesting
确实取决于它被调用的特定文字上下文。
如果任何在Ruby内部有更多经验的人都可以添加任何东西,我可以把它作为社区维基交给SO社区。
UPDATE:所有这一切都适用于class_eval
以及它对module_eval
,它也适用于1.9.3以及它对1.9.2。
[“返回嵌套在调用点的模块列表”](http://ruby-doc.org/core/classes/Module.html#M000441),但是当您说时没有打开的“模块” 'A.module_eval'你只是在'A'的背景下行事。 'Module.nesting'似乎更多地是与Ruby运行时环境交谈的解析器。 – 2011-06-14 01:59:18
@mu太短由你的评论启发,我加入到我的问题。 – sawa 2011-06-14 02:17:12