2012-05-04 21 views
3

我想要的,如果條件轉換:Ruby C API`定義了嗎? SomeConstant`相當於?

unless defined? SomeConstant 
    # do some stuff 
end 

進入本地C擴展的一部分。有人知道如何在C API中執行defined?謂詞檢查嗎?

編輯|我想我可以調用:

rb_funcall(rb_cObject, rb_intern("const_defined?"), 1, rb_intern("SomeConstant")) 

雖然這在語義上顯然略有不同。

+3

'Object.const_defined?'可能會像你想要的那樣好。實際的'defined?'關鍵字在'insns.def'中執行(查找'DEFINE_INSN'),並調用'vm_get_ev_const',它在'vm_insnhelper.c'中是靜態的,因此不可訪問。 –

+0

我認爲你是對的,謝謝!你想做出答案嗎? :) – d11wtq

+0

我放下了一些筆記,但它不是(當然)總是像Object.const_defined?一樣簡單。當然。 –

回答

3

如果跟蹤通過1.9.3源代碼,你會發現defined?insns.def實現:

DEFINE_INSN 
defined 
(rb_num_t op_type, VALUE obj, VALUE needstr) 
/* ... */ 
    switch (type) { 
    /* ... */ 
     case DEFINED_CONST: 
     klass = v; 
     if (vm_get_ev_const(th, GET_ISEQ(), klass, SYM2ID(obj), 1)) { 
      expr_type = "constant"; 
     } 
     break; 

所以,當你defined? SomeConstant,您通過大switch涓流,並最終調用vm_get_ev_const。該功能在vm_insnhelper.c定義:

static inline VALUE 
vm_get_ev_const(rb_thread_t *th, const rb_iseq_t *iseq, 
       VALUE orig_klass, ID id, int is_defined) 

這個功能恰好是靜態的,所以你不能得到它。看起來像vm_get_ev_const是根據rb_const_definedrb_const_defined_from定義的,並且這兩個都應該在C中可用,因此您可以嘗試這些;但是您必須爲這些人找到正確的klass

或者你可以去你的主意,只是使用Object.const_defined?。其中一個問題是,它不會像A::B這樣的事情做正確的事情,你必須說Object.const_defined? :A && A.const_defined? :B因爲Object.const_defined? :'A::B'只會拋出一個異常在你的臉上。這裏的一般解決方案需要迭代和類查找。但是,如果您正在查看的類都在頂級命名空間中,那麼一個簡單的Object.const_defined?應該可以做到。

+0

'rb_const_defined()'是使用的方法。 'if(rb_const_defined(rb_cObject,rb_intern(「MY_CONST」)))' – thomthom

+0

@thomthom在1.9.3或2.0.0的'ruby.h'中找不到'rb_const_defined'。 – mezis

+1

@mezis如果您按照「mu is too short」的回答('rb_const_defined')中的鏈接進行操作,那麼它會將您帶到它位於'variable.c'中的位置。 – thomthom