static void add_module(VALUE self, VALUE module) { VALUE super = RCLASS_SUPER(rb_singleton_class(self)); #ifdef RUBY_19 VALUE klass = class_alloc(T_ICLASS, rb_cClass); #else NEWOBJ(klass, struct RClass); OBJSETUP(klass, rb_cClass, T_ICLASS); #endif if (BUILTIN_TYPE(module) == T_ICLASS) { module = KLASS_OF(module); } if (!RCLASS_IV_TBL(module)) { RCLASS_IV_TBL(module) = (void*)st_init_numtable(); } RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module); RCLASS_M_TBL(klass) = RCLASS_M_TBL(module); RCLASS_SUPER(klass) = super; if (TYPE(module) == T_ICLASS) { KLASS_OF(klass) = KLASS_OF(module); } else { KLASS_OF(klass) = module; } OBJ_INFECT(klass, module); OBJ_INFECT(klass, super); RCLASS_SUPER(rb_singleton_class(self)) = (VALUE)klass; }
/* :nodoc: */ VALUE rb_mod_init_copy(VALUE clone, VALUE orig) { rb_obj_init_copy(clone, orig); if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) { RBASIC(clone)->klass = rb_singleton_class_clone(orig); } RCLASS_SUPER(clone) = RCLASS_SUPER(orig); if (RCLASS_IV_TBL(orig)) { ID id; RCLASS_IV_TBL(clone) = st_copy(RCLASS_IV_TBL(orig)); CONST_ID(id, "__classpath__"); st_delete(RCLASS_IV_TBL(clone), (st_data_t*)&id, 0); CONST_ID(id, "__classid__"); st_delete(RCLASS_IV_TBL(clone), (st_data_t*)&id, 0); } if (RCLASS_M_TBL(orig)) { struct clone_method_data data; data.tbl = RCLASS_M_TBL(clone) = st_init_numtable(); data.klass = clone; st_foreach(RCLASS_M_TBL(orig), clone_method, (st_data_t)&data); } return clone; }
static VALUE create_class_restorer(VALUE klass) { /* On Ruby 1.8, there is a check in marshal_dump() to ensure that * the object being dumped has no modifications to its singleton * class (e.g. no singleton instance variables, and no singleton * methods defined). Since we need to dump the class's singleton * class in order to dump class methods, we need a way around this * restriction. The solution found here temporarily removes the * singleton instance variables and singleton methods while the * class is being dumped, and sets a special singleton instance * variable that restores the tables when dumping is complete. A * hack for sure, but it seems to work. */ struct RClass * singleton_class = RCLASS(CLASS_OF(klass)); struct Class_Restorer * class_restorer; if(!RCLASS_IV_TBL(singleton_class)) { rb_raise( rb_eTypeError, "can't dump singleton class on Ruby 1.8 without iv_tbl"); } class_restorer = ALLOC(struct Class_Restorer); class_restorer->klass = CLASS_OF(klass); class_restorer->m_tbl = *RCLASS_M_TBL(singleton_class); class_restorer->iv_tbl = *RCLASS_IV_TBL(singleton_class); #ifndef RUBY_VM class_restorer->thread_critical = rb_thread_critical; #endif return Data_Wrap_Struct( rb_cClass_Restorer, mark_class_restorer, ruby_xfree, class_restorer); }
static VALUE include_class_new(VALUE module, VALUE super) { VALUE klass = class_alloc(T_ICLASS, rb_cClass); if (BUILTIN_TYPE(module) == T_ICLASS) { module = RBASIC(module)->klass; } if (!RCLASS_IV_TBL(module)) { RCLASS_IV_TBL(module) = st_init_numtable(); } RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module); RCLASS_M_TBL(klass) = RCLASS_M_TBL(module); RCLASS_SUPER(klass) = super; if (TYPE(module) == T_ICLASS) { RBASIC(klass)->klass = RBASIC(module)->klass; } else { RBASIC(klass)->klass = module; } OBJ_INFECT(klass, module); OBJ_INFECT(klass, super); return (VALUE)klass; }
VALUE rb_singleton_class_clone(VALUE obj) { VALUE klass = RBASIC(obj)->klass; if (!FL_TEST(klass, FL_SINGLETON)) return klass; else { struct clone_method_data data; /* copy singleton(unnamed) class */ VALUE clone = class_alloc(RBASIC(klass)->flags, 0); if (BUILTIN_TYPE(obj) == T_CLASS) { RBASIC(clone)->klass = (VALUE)clone; } else { RBASIC(clone)->klass = rb_singleton_class_clone(klass); } RCLASS_SUPER(clone) = RCLASS_SUPER(klass); if (RCLASS_IV_TBL(klass)) { RCLASS_IV_TBL(clone) = st_copy(RCLASS_IV_TBL(klass)); } RCLASS_M_TBL(clone) = st_init_numtable(); data.tbl = RCLASS_M_TBL(clone); data.klass = (VALUE)clone; st_foreach(RCLASS_M_TBL(klass), clone_method, (st_data_t)&data); rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone); FL_SET(clone, FL_SINGLETON); return (VALUE)clone; } }
/* call-seq: * singleton_class_instance -> Object || nil * * Returns the object attached to the singleton class. * If the class does not have an object attached to it (possibly because * it isn't a singleton class), returns +nil+. */ static VALUE evilr_singleton_class_instance(VALUE klass) { VALUE obj; if(RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass), evilr__attached, &obj)) { return obj; } return Qnil; }
static VALUE find_class_path(VALUE klass) { struct fc_result arg; arg.name = 0; arg.path = 0; arg.klass = klass; arg.track = rb_cObject; arg.prev = 0; if (RCLASS_CONST_TBL(rb_cObject)) { st_foreach_safe(RCLASS_CONST_TBL(rb_cObject), fc_i, (st_data_t)&arg); } if (arg.path == 0) { st_foreach_safe(rb_class_tbl, fc_i, (st_data_t)&arg); } if (arg.path) { st_data_t tmp = tmp_classpath; if (!RCLASS_IV_TBL(klass)) { RCLASS_IV_TBL(klass) = st_init_numtable(); } st_insert(RCLASS_IV_TBL(klass), (st_data_t)classpath, arg.path); st_delete(RCLASS_IV_TBL(klass), &tmp, 0); return arg.path; } return Qnil; }
static VALUE classname(VALUE klass) { VALUE path = Qnil; st_data_t n; if (!klass) klass = rb_cObject; if (RCLASS_IV_TBL(klass)) { if (!st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classpath, &n)) { if (!st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classid, &n)) { return find_class_path(klass); } path = rb_str_dup(rb_id2str(SYM2ID((VALUE)n))); OBJ_FREEZE(path); st_insert(RCLASS_IV_TBL(klass), (st_data_t)classpath, (st_data_t)path); n = classid; st_delete(RCLASS_IV_TBL(klass), &n, 0); } else { path = (VALUE)n; } if (TYPE(path) != T_STRING) { rb_bug("class path is not set properly"); } return path; } return find_class_path(klass); }
VALUE rb_class_path(VALUE klass) { VALUE path = classname(klass); st_data_t n = (st_data_t)path; if (!NIL_P(path)) return path; if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass), (st_data_t)tmp_classpath, &n)) { return (VALUE)n; } else { const char *s = "Class"; if (TYPE(klass) == T_MODULE) { if (rb_obj_class(klass) == rb_cModule) { s = "Module"; } else { s = rb_class2name(RBASIC(klass)->klass); } } path = rb_sprintf("#<%s:%p>", s, (void*)klass); OBJ_FREEZE(path); rb_ivar_set(klass, tmp_classpath, path); return path; } }
VALUE rb_include_class_new(VALUE module, VALUE super) { VALUE klass = class_alloc(T_ICLASS, rb_cClass); if (BUILTIN_TYPE(module) == T_ICLASS) { module = RBASIC(module)->klass; } if (!RCLASS_IV_TBL(module)) { RCLASS_IV_TBL(module) = st_init_numtable(); } if (!RCLASS_CONST_TBL(module)) { RCLASS_CONST_TBL(module) = st_init_numtable(); } RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module); RCLASS_CONST_TBL(klass) = RCLASS_CONST_TBL(module); RCLASS_M_TBL_WRAPPER(OBJ_WB_UNPROTECT(klass)) = RCLASS_M_TBL_WRAPPER(OBJ_WB_UNPROTECT(RCLASS_ORIGIN(module))); RCLASS_SET_SUPER(klass, super); if (RB_TYPE_P(module, T_ICLASS)) { RBASIC_SET_CLASS(klass, RBASIC(module)->klass); } else { RBASIC_SET_CLASS(klass, module); } OBJ_INFECT(klass, module); OBJ_INFECT(klass, super); return (VALUE)klass; }
static VALUE fc_path(struct fc_result *fc, ID name) { VALUE path, tmp; path = rb_str_dup(rb_id2str(name)); while (fc) { st_data_t n; if (fc->track == rb_cObject) break; if (RCLASS_IV_TBL(fc->track) && st_lookup(RCLASS_IV_TBL(fc->track), (st_data_t)classpath, &n)) { tmp = rb_str_dup((VALUE)n); rb_str_cat2(tmp, "::"); rb_str_append(tmp, path); path = tmp; break; } tmp = rb_str_dup(rb_id2str(fc->name)); rb_str_cat2(tmp, "::"); rb_str_append(tmp, path); path = tmp; fc = fc->prev; } OBJ_FREEZE(path); return path; }
/* call-seq: * detach_singleton -> self * * If the receiver is a singleton class, it is transformed into a * regular class and it is detached from the instance. Note that * this means it becomes the class of the object to which it was previous * attached. If the receiver is not a singleton class, has no effect. * Returns the receiver. */ static VALUE evilr_detach_singleton(VALUE klass) { if (IS_SINGLETON_CLASS(klass)) { FL_UNSET(klass, FL_SINGLETON); if (RCLASS_IV_TBL(klass)) { st_delete(RCLASS_IV_TBL(klass), (st_data_t*)&evilr__attached, 0); } } return klass; }
/*! * Attach a object to a singleton class. * @pre \a klass is the singleton class of \a obj. */ void rb_singleton_class_attached(VALUE klass, VALUE obj) { if (FL_TEST(klass, FL_SINGLETON)) { if (!RCLASS_IV_TBL(klass)) { RCLASS_IV_TBL(klass) = st_init_numtable(); } st_insert(RCLASS_IV_TBL(klass), id_attached, obj); } }
void rb_singleton_class_attached(VALUE klass, VALUE obj) { if (FL_TEST(klass, FL_SINGLETON)) { ID attached; if (!RCLASS_IV_TBL(klass)) { RCLASS_IV_TBL(klass) = st_init_numtable(); } CONST_ID(attached, "__attached__"); st_insert(RCLASS_IV_TBL(klass), attached, obj); } }
VALUE rb_reset_tbls(VALUE self) { RCLASS_IV_TBL(self) = (struct st_table *) 0; RCLASS_M_TBL(self) = (struct st_table *) st_init_numtable(); return Qnil; }
/* a modified version of include_class_new from class.c */ static VALUE j_class_new(VALUE module, VALUE sup) { #ifdef RUBY_19 VALUE klass = class_alloc(T_ICLASS, rb_cClass); #else NEWOBJ(klass, struct RClass); OBJSETUP(klass, rb_cClass, T_ICLASS); #endif if (BUILTIN_TYPE(module) == T_ICLASS) { module = KLASS_OF(module); } if (!RCLASS_IV_TBL(module)) { RCLASS_IV_TBL(module) = (struct st_table *)st_init_numtable(); } /* assign iv_tbl, m_tbl and super */ RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module); RCLASS_SUPER(klass) = sup; if(TYPE(module) != T_OBJECT) { RCLASS_M_TBL(klass) = RCLASS_M_TBL(module); } else { RCLASS_M_TBL(klass) = RCLASS_M_TBL(CLASS_OF(module)); } /* */ if (TYPE(module) == T_ICLASS) { KLASS_OF(klass) = KLASS_OF(module); } else { KLASS_OF(klass) = module; } if(TYPE(module) != T_OBJECT) { OBJ_INFECT(klass, module); OBJ_INFECT(klass, sup); } return (VALUE)klass; }
static void set_class_restore_state(VALUE klass) { struct RClass * singleton_class = RCLASS(CLASS_OF(klass)); RCLASS_IV_TBL(singleton_class)->num_entries = 1; RCLASS_M_TBL(singleton_class)->num_entries = 0; #ifndef RUBY_VM rb_thread_critical = 1; #endif }
/* call-seq: * swap_instance_variables(other) -> self * * Swaps only the instance variables of the receiver and +other+. * You can only swap the instance variables between two objects that * use the internal type number T_OBJECT, or between Classes and Modules. * You cannot swap instance variables of immediate values, since they * do not have instance variables. Invalid swap attempts will raise * +TypeError+. */ static VALUE evilr_swap_instance_variables(VALUE self, VALUE other) { #ifndef RUBY19 struct st_table *tmp; #endif evilr__check_immediates(self, other); switch(BUILTIN_TYPE(self)) { case T_OBJECT: if (BUILTIN_TYPE(other) != T_OBJECT) { goto bad_types; } break; case T_MODULE: case T_CLASS: if (BUILTIN_TYPE(other) != T_MODULE && BUILTIN_TYPE(other) != T_CLASS) { goto bad_types; } break; default: bad_types: rb_raise(rb_eTypeError, "incompatible types used"); } #ifdef RUBY19 if (BUILTIN_TYPE(self) == T_MODULE || BUILTIN_TYPE(self) == T_CLASS) { struct st_table *tmp; tmp = RCLASS_IV_TBL(self); RCLASS(self)->ptr->iv_tbl = RCLASS_IV_TBL(other); RCLASS(other)->ptr->iv_tbl = tmp; } else { char tmp[OBJECT_SIZE]; memcpy(tmp, &(ROBJECT(self)->as), sizeof(ROBJECT(tmp)->as)); memcpy(&(ROBJECT(self)->as), &(ROBJECT(other)->as), sizeof(ROBJECT(self)->as)); memcpy(&(ROBJECT(other)->as), tmp, sizeof(ROBJECT(other)->as)); } #else /* RClass and RObject have iv_tbl at same position in the structure * so no funny business is needed */ tmp = ROBJECT_IVPTR(self); ROBJECT(self)->iv_tbl = ROBJECT_IVPTR(other); ROBJECT(other)->iv_tbl = tmp; #endif return self; }
VALUE Looksee_singleton_instance(VALUE self, VALUE klass) { if (!SPECIAL_CONST_P(klass) && BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON)) { VALUE object; if (!Looksee_method_table_lookup(RCLASS_IV_TBL(klass), rb_intern("__attached__"), (st_data_t *)&object)) rb_raise(rb_eRuntimeError, "[looksee bug] can't find singleton object"); return object; } else { return Qnil; } }
VALUE Looksee_singleton_instance(VALUE self, VALUE singleton_class) { if (BUILTIN_TYPE(singleton_class) == T_CLASS && FL_TEST(singleton_class, FL_SINGLETON)) { VALUE object; if (!Looksee_method_table_lookup(RCLASS_IV_TBL(singleton_class), rb_intern("__attached__"), (st_data_t *)&object)) rb_raise(rb_eRuntimeError, "[looksee bug] can't find singleton object"); return object; } else { rb_raise(rb_eTypeError, "expected singleton class, got %s", rb_obj_classname(singleton_class)); } }
static int fc_i(ID key, VALUE value, struct fc_result *res) { if (!rb_is_const_id(key)) return ST_CONTINUE; if (value == res->klass) { res->path = fc_path(res, key); return ST_STOP; } switch (TYPE(value)) { case T_MODULE: case T_CLASS: if (!RCLASS_IV_TBL(value)) return ST_CONTINUE; else { struct fc_result arg; struct fc_result *list; list = res; while (list) { if (list->track == value) return ST_CONTINUE; list = list->prev; } arg.name = key; arg.path = 0; arg.klass = res->klass; arg.track = value; arg.prev = res; st_foreach(RCLASS_IV_TBL(value), fc_i, (st_data_t)&arg); if (arg.path) { res->path = arg.path; return ST_STOP; } } break; default: break; } return ST_CONTINUE; }
VALUE rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach) { VALUE klass = RBASIC(obj)->klass; if (!FL_TEST(klass, FL_SINGLETON)) return klass; else { /* copy singleton(unnamed) class */ VALUE clone = class_alloc(RBASIC(klass)->flags, 0); if (BUILTIN_TYPE(obj) == T_CLASS) { RBASIC_SET_CLASS(clone, clone); } else { RBASIC_SET_CLASS(clone, rb_singleton_class_clone(klass)); } RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass)); RCLASS_EXT(clone)->allocator = RCLASS_EXT(klass)->allocator; if (RCLASS_IV_TBL(klass)) { RCLASS_IV_TBL(clone) = rb_st_copy(clone, RCLASS_IV_TBL(klass)); } if (RCLASS_CONST_TBL(klass)) { struct clone_const_arg arg; RCLASS_CONST_TBL(clone) = st_init_numtable(); arg.klass = clone; arg.tbl = RCLASS_CONST_TBL(clone); st_foreach(RCLASS_CONST_TBL(klass), clone_const_i, (st_data_t)&arg); } if (attach != Qundef) { rb_singleton_class_attached(clone, attach); } RCLASS_M_TBL_INIT(clone); st_foreach(RCLASS_M_TBL(klass), clone_method_i, (st_data_t)clone); rb_singleton_class_attached(RBASIC(clone)->klass, clone); FL_SET(clone, FL_SINGLETON); return clone; } }
/** * Allocates a struct RClass for a new class. * * \param flags initial value for basic.flags of the returned class. * \param klass the class of the returned class. * \return an uninitialized Class object. * \pre \p klass must refer \c Class class or an ancestor of Class. * \pre \code (flags | T_CLASS) != 0 \endcode * \post the returned class can safely be \c #initialize 'd. * * \note this function is not Class#allocate. */ static VALUE class_alloc(VALUE flags, VALUE klass) { rb_classext_t *ext = ALLOC(rb_classext_t); NEWOBJ(obj, struct RClass); OBJSETUP(obj, klass, flags); obj->ptr = ext; RCLASS_IV_TBL(obj) = 0; RCLASS_M_TBL(obj) = 0; RCLASS_SUPER(obj) = 0; RCLASS_IV_INDEX_TBL(obj) = 0; return (VALUE)obj; }
/* :nodoc: */ VALUE rb_mod_init_copy(VALUE clone, VALUE orig) { if (RB_TYPE_P(clone, T_CLASS)) { class_init_copy_check(clone, orig); } if (!OBJ_INIT_COPY(clone, orig)) return clone; if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) { RBASIC_SET_CLASS(clone, rb_singleton_class_clone(orig)); rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone); } RCLASS_SET_SUPER(clone, RCLASS_SUPER(orig)); RCLASS_EXT(clone)->allocator = RCLASS_EXT(orig)->allocator; if (RCLASS_IV_TBL(orig)) { st_data_t id; if (RCLASS_IV_TBL(clone)) { st_free_table(RCLASS_IV_TBL(clone)); } RCLASS_IV_TBL(clone) = rb_st_copy(clone, RCLASS_IV_TBL(orig)); CONST_ID(id, "__tmp_classpath__"); st_delete(RCLASS_IV_TBL(clone), &id, 0); CONST_ID(id, "__classpath__"); st_delete(RCLASS_IV_TBL(clone), &id, 0); CONST_ID(id, "__classid__"); st_delete(RCLASS_IV_TBL(clone), &id, 0); } if (RCLASS_CONST_TBL(orig)) { struct clone_const_arg arg; if (RCLASS_CONST_TBL(clone)) { rb_free_const_table(RCLASS_CONST_TBL(clone)); } RCLASS_CONST_TBL(clone) = st_init_numtable(); arg.klass = clone; arg.tbl = RCLASS_CONST_TBL(clone); st_foreach(RCLASS_CONST_TBL(orig), clone_const_i, (st_data_t)&arg); } if (RCLASS_M_TBL(orig)) { if (RCLASS_M_TBL_WRAPPER(clone)) { rb_free_m_tbl_wrapper(RCLASS_M_TBL_WRAPPER(clone)); } RCLASS_M_TBL_INIT(clone); st_foreach(RCLASS_M_TBL(orig), clone_method_i, (st_data_t)clone); } return clone; }
/** * Allocates a struct RClass for a new class. * * \param flags initial value for basic.flags of the returned class. * \param klass the class of the returned class. * \return an uninitialized Class object. * \pre \p klass must refer \c Class class or an ancestor of Class. * \pre \code (flags | T_CLASS) != 0 \endcode * \post the returned class can safely be \c #initialize 'd. * * \note this function is not Class#allocate. */ static VALUE class_alloc(VALUE flags, VALUE klass) { NEWOBJ_OF(obj, struct RClass, klass, (flags & T_MASK) | (RGENGC_WB_PROTECTED_CLASS ? FL_WB_PROTECTED : 0)); obj->ptr = ALLOC(rb_classext_t); RCLASS_IV_TBL(obj) = 0; RCLASS_CONST_TBL(obj) = 0; RCLASS_M_TBL(obj) = 0; RCLASS_SET_SUPER((VALUE)obj, 0); RCLASS_ORIGIN(obj) = (VALUE)obj; RCLASS_IV_INDEX_TBL(obj) = 0; RCLASS_REFINED_CLASS(obj) = Qnil; RCLASS_EXT(obj)->allocator = 0; return (VALUE)obj; }
static void restore_class(VALUE ruby_class_restorer) { struct Class_Restorer * class_restorer; struct RClass * klass; Data_Get_Struct( ruby_class_restorer, struct Class_Restorer, class_restorer); klass = RCLASS(class_restorer->klass); *RCLASS_M_TBL(klass) = class_restorer->m_tbl; *RCLASS_IV_TBL(klass) = class_restorer->iv_tbl; #ifndef RUBY_VM rb_thread_critical = class_restorer->thread_critical; #endif }
/* * call-seq: * obj.instance_variable_defined?(symbol) -> true or false * * Returns <code>true</code> if the given instance variable is * defined in <i>obj</i>. * * class Fred * def initialize(p1, p2) * @a, @b = p1, p2 * end * end * fred = Fred.new('cat', 99) * fred.instance_variable_defined?(:@a) #=> true * fred.instance_variable_defined?("@b") #=> true * fred.instance_variable_defined?("@c") #=> false */ mrb_value mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) { mrb_value arg; khiter_t k; kh_iv_t *h = RCLASS_IV_TBL(self); mrb_get_args(mrb, "o", &arg); mrb_sym mid = mrb_to_id(mrb, arg); if (h) { k = kh_get(iv, h, mid); if (k != kh_end(h)) { return mrb_true_value(); } } return mrb_false_value(); }
static VALUE class_alloc(VALUE flags, VALUE klass) { #ifdef RUBY_193 rb_deprecated_classext_t *ext = ALLOC(rb_deprecated_classext_t); #else rb_classext_t *ext = ALLOC(rb_classext_t); #endif NEWOBJ(obj, struct RClass); OBJSETUP(obj, klass, flags); obj->ptr = ext; RCLASS_IV_TBL(obj) = 0; RCLASS_M_TBL(obj) = 0; RCLASS_SUPER(obj) = 0; #ifndef RUBY_193 RCLASS_IV_INDEX_TBL(obj) = 0; #endif return (VALUE)obj; }
/* :nodoc: */ VALUE rb_mod_init_copy(VALUE clone, VALUE orig) { if (RB_TYPE_P(clone, T_CLASS)) { class_init_copy_check(clone, orig); } rb_obj_init_copy(clone, orig); if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) { RBASIC(clone)->klass = rb_singleton_class_clone(orig); rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone); } RCLASS_SUPER(clone) = RCLASS_SUPER(orig); if (RCLASS_IV_TBL(orig)) { st_data_t id; if (RCLASS_IV_TBL(clone)) { st_free_table(RCLASS_IV_TBL(clone)); } RCLASS_IV_TBL(clone) = st_copy(RCLASS_IV_TBL(orig)); CONST_ID(id, "__classpath__"); st_delete(RCLASS_IV_TBL(clone), &id, 0); CONST_ID(id, "__classid__"); st_delete(RCLASS_IV_TBL(clone), &id, 0); } if (RCLASS_CONST_TBL(orig)) { if (RCLASS_CONST_TBL(clone)) { rb_free_const_table(RCLASS_CONST_TBL(clone)); } RCLASS_CONST_TBL(clone) = st_init_numtable(); st_foreach(RCLASS_CONST_TBL(orig), clone_const_i, (st_data_t)RCLASS_CONST_TBL(clone)); } if (RCLASS_M_TBL(orig)) { struct clone_method_data data; if (RCLASS_M_TBL(clone)) { rb_free_m_table(RCLASS_M_TBL(clone)); } data.tbl = RCLASS_M_TBL(clone) = st_init_numtable(); data.klass = clone; st_foreach(RCLASS_M_TBL(orig), clone_method, (st_data_t)&data); } return clone; }
/* * call-seq: * obj.instance_variables -> array * * Returns an array of instance variable names for the receiver. Note * that simply defining an accessor does not create the corresponding * instance variable. * * class Fred * attr_accessor :a1 * def initialize * @iv = 3 * end * end * Fred.new.instance_variables #=> [:@iv] */ mrb_value mrb_obj_instance_variables(mrb_state *mrb, mrb_value self) { mrb_value ary; kh_iv_t *h = RCLASS_IV_TBL(self); int i; const char* p; ary = mrb_ary_new(mrb); if (h) { for (i=0;i<kh_end(h);i++) { if (kh_exist(h, i)) { p = mrb_sym2name(mrb, kh_key(h,i)); if (*p == '@') { if (mrb_type(kh_value(h, i)) != MRB_TT_UNDEF) mrb_ary_push(mrb, ary, mrb_str_new_cstr(mrb, p)); } } } } return ary; }