module.nesting 在instance_eval/exec 或 module_eval/exec 中
当我试图回答这个问题时,我想到了这个问题。以下是预期行为:
module A
p Module.nesting
end
# => [A]
但以下情况:
A.instance_eval{p Module.nesting}
A.instance_exec{p Module.nesting}
A.module_eval{p Module.nesting}
A.module_exec{p Module.nesting}
全部返回 []
。为什么这些不能像上面那样工作?
附加问题
Mu太短了,提出了一个有趣的观点。如果这是正确的,那么 Module.nesting
将是依赖于文字上下文的方法和变量之一,例如 Method#source_location
、__FILE__
。这种理解正确吗?如果是这样,有人可以提供这些依赖于文字上下文的方法/变量的清单吗?我觉得还是很有参考价值的。
I came up with this question when I was trying to answer this. The following is an expected behaviour:
module A
p Module.nesting
end
# => [A]
But the following:
A.instance_eval{p Module.nesting}
A.instance_exec{p Module.nesting}
A.module_eval{p Module.nesting}
A.module_exec{p Module.nesting}
all return []
. Why do these not work as the above?
Additional Question
Mu is too short suggested an interesting point. If that is correct, then Module.nesting
would be one of the methods and variables that are dependent on the literal context like Method#source_location
, __FILE__
. Is this understanding correct? If so, can someone provide the inventory of these methods/variables that are dependent on the literal context? I think it would be useful for reference.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
警告:这有点长而且漫无目的。由于文档有点单薄,因此似乎有必要浏览一下 Ruby 源代码。如果您不关心香肠的制作方法,请随意跳到最后。
1.9.2
Module.nesting
在eval.c
中实现如下:我不太了解 Ruby 内部结构,但我读了
while 像这样循环:从
cref
链表中提取与类似类的事物关联但不是来自eval
的所有节点。NODE_FL_CREF_PUSHED_BY_EVAL
位仅在此处设置:更多的 grep 和阅读表明
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_cref
又是vm_get_cref0
的包装器。vm_get_cref0
到底是什么?全部是这样的:函数的所有三个参数都直接来自此控制框架:
iseq
似乎是一个指令序列,lfp
和dfp
是帧指针:cref_stack
的定义是相关的:因此看起来您正在从
rb_vm_cref
中获取某种调用或嵌套堆栈。现在回到手头的具体细节。当您执行此操作时:
您将在
cref
链接列表中拥有module A
(经过过滤以生成Module.nesting
结果数组)因为您还没有到达end
。当您说这些时:您将不再有
cref
中的module A
因为您已经点击了end
弹出的module A
离开堆栈。但是,如果您这样做:您将看到以下输出:
因为
模块 A
尚未关闭(并从cref
弹出)。最后,
Module.nesting
文档 说的是:我认为这个陈述与内部审查相结合表明
Module.nesting
实际上依赖于调用它的特定文字上下文。如果任何在 Ruby 内部有更多经验的人有任何需要添加的内容,我可以将其作为社区 wiki 交给 SO 社区。
更新:所有这些都适用于
class_eval
以及module_eval
,它也适用于1.9.3以及它1.9.2.Warning: This is a little long and rambling. A bit of a tour through the Ruby source code seems necessary as the documentation is a bit thin. Feel free to skip to the end if you don't care about how sausage is made.
The 1.9.2
Module.nesting
is implemented ineval.c
like this:I don't know the Ruby internals that well but I read the
while
loop like this: extract from thecref
linked list all the nodes that are associated with a class-like thing but didn't come fromeval
. TheNODE_FL_CREF_PUSHED_BY_EVAL
bit is only set in here:A bit more grepping and reading reveals that
instance_eval
does end up going throughyield_under
. I'll leave checkinginstance_exec
,module_eval
, andmodule_exec
as exercises for the reader. In any case, it looks likeinstance_eval
is explicitly excluded from theModule.nesting
list; this is, however, more of a distraction than anything else, it just means that you won't see something the evals mentioned.So now the question is "what are
NODE
andrb_vm_cref()
all about?".If you look in
node.h
you'll see a bunch of NODE constants for the various Ruby keywords and language structures:NODE_BLOCK
NODE_BREAK
NODE_CLASS
NODE_MODULE
NODE_DSYM
so I'd guess that
NODE
is a node in the instruction tree. This lines up nicely with myconjecture in the comment. But we'll keep going anyway.
The
rb_vm_cref
function is just a wrapper forvm_get_cref
which is a wrapper forvm_get_cref0
. What isvm_get_cref0
all about? It is all about this:All three arguments to the function come straight out of this control frame:
The
iseq
appears to be an instruction sequence and thelfp
anddfp
are frame pointers:The definition of
cref_stack
is relevant:So it looks like you're getting some sort of call or nesting stack out of
rb_vm_cref
.Now back to the specifics at hand. When you do this:
You'll have
module A
in thecref
linked list (which is filtered to produce theModule.nesting
result array) as you haven't hit theend
yet. When you say these:You won't have
module A
incref
anymore because you've already hit theend
poppedmodule A
off the stack. However, if you do this:You'll see this output:
because the
module A
hasn't been closed (and popped offcref
) yet.To finish off, the
Module.nesting
documentation says this:I think this statement combined with the review of the internals indicates that
Module.nesting
does in fact depend on the specific literal context in which it is called.If anyone with more experience in the Ruby internals has anything to add I can hand this over to the SO community as a community wiki.
UPDATE: All of this applies to
class_eval
as well as it does tomodule_eval
and it also applies to 1.9.3 as well as it does to 1.9.2.