警告:這有點漫長。由於文檔有點簡單,瀏覽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