void rb_prepend_module(VALUE klass, VALUE module) { void rb_vm_check_redefinition_by_prepend(VALUE klass); VALUE origin; int changed = 0; rb_frozen_class_p(klass); Check_Type(module, T_MODULE); OBJ_INFECT(klass, module); origin = RCLASS_ORIGIN(klass); if (origin == klass) { origin = class_alloc(T_ICLASS, klass); RCLASS_SET_SUPER(origin, RCLASS_SUPER(klass)); RCLASS_SET_SUPER(klass, origin); RCLASS_ORIGIN(klass) = origin; RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass); RCLASS_M_TBL(klass) = st_init_numtable(); st_foreach(RCLASS_M_TBL(origin), move_refined_method, (st_data_t) RCLASS_M_TBL(klass)); } changed = include_modules_at(klass, klass, module); if (changed < 0) rb_raise(rb_eArgError, "cyclic prepend detected"); if (changed) { rb_clear_cache(); rb_vm_check_redefinition_by_prepend(klass); } }
static void remove_method(VALUE klass, ID mid) { st_data_t key, data; rb_method_entry_t *me = 0; if (klass == rb_cObject) { rb_secure(4); } if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) { rb_raise(rb_eSecurityError, "Insecure: can't remove method"); } rb_check_frozen(klass); if (mid == object_id || mid == id__send__ || mid == idInitialize) { rb_warn("removing `%s' may cause serious problems", rb_id2name(mid)); } if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) || !(me = (rb_method_entry_t *)data) || (!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) { rb_name_error(mid, "method `%s' not defined in %s", rb_id2name(mid), rb_class2name(klass)); } key = (st_data_t)mid; st_delete(RCLASS_M_TBL(klass), &key, &data); rb_vm_check_redefinition_opt_method(me, klass); rb_clear_cache_for_undef(klass, mid); rb_unlink_method_entry(me); CALL_METHOD_HOOK(klass, removed, mid); }
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(OBJ_WB_UNPROTECT(klass)) = RCLASS_M_TBL(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 class_instance_method_list(int argc, VALUE *argv, VALUE mod, int obj, int (*func) (st_data_t, st_data_t, st_data_t)) { VALUE ary; int recur, prepended = 0; st_table *list; if (argc == 0) { recur = TRUE; } else { VALUE r; rb_scan_args(argc, argv, "01", &r); recur = RTEST(r); } if (!recur && RCLASS_ORIGIN(mod) != mod) { mod = RCLASS_ORIGIN(mod); prepended = 1; } list = st_init_numtable(); for (; mod; mod = RCLASS_SUPER(mod)) { if (RCLASS_M_TBL(mod)) st_foreach(RCLASS_M_TBL(mod), method_entry_i, (st_data_t)list); if (BUILTIN_TYPE(mod) == T_ICLASS && !prepended) continue; if (obj && FL_TEST(mod, FL_SINGLETON)) continue; if (!recur) break; } ary = rb_ary_new(); st_foreach(list, func, ary); st_free_table(list); return ary; }
VALUE rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj) { VALUE recur, ary, klass; st_table *list; if (argc == 0) { recur = Qtrue; } else { rb_scan_args(argc, argv, "01", &recur); } klass = CLASS_OF(obj); list = st_init_numtable(); if (klass && FL_TEST(klass, FL_SINGLETON)) { st_foreach(RCLASS_M_TBL(klass), method_entry, (st_data_t)list); klass = RCLASS_SUPER(klass); } if (RTEST(recur)) { while (klass && (FL_TEST(klass, FL_SINGLETON) || TYPE(klass) == T_ICLASS)) { st_foreach(RCLASS_M_TBL(klass), method_entry, (st_data_t)list); klass = RCLASS_SUPER(klass); } } ary = rb_ary_new(); st_foreach(list, ins_methods_i, ary); st_free_table(list); return ary; }
static int include_modules_at(const VALUE klass, VALUE c, VALUE module) { VALUE p, iclass; int method_changed = 0, constant_changed = 0; const st_table *const klass_m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(klass)); while (module) { int superclass_seen = FALSE; if (RCLASS_ORIGIN(module) != module) goto skip; if (klass_m_tbl && klass_m_tbl == RCLASS_M_TBL(module)) return -1; /* ignore if the module included already in superclasses */ for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) { switch (BUILTIN_TYPE(p)) { case T_ICLASS: if (RCLASS_M_TBL_WRAPPER(p) == RCLASS_M_TBL_WRAPPER(module)) { if (!superclass_seen) { c = p; /* move insertion point */ } goto skip; } break; case T_CLASS: superclass_seen = TRUE; break; } } iclass = rb_include_class_new(module, RCLASS_SUPER(c)); c = RCLASS_SET_SUPER(c, iclass); if (BUILTIN_TYPE(module) == T_ICLASS) { rb_module_add_to_subclasses_list(RBASIC(module)->klass, iclass); } else { rb_module_add_to_subclasses_list(module, iclass); } if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) { VALUE refined_class = rb_refinement_module_get_refined_class(klass); st_foreach(RMODULE_M_TBL(module), add_refined_method_entry_i, (st_data_t) refined_class); FL_SET(c, RMODULE_INCLUDED_INTO_REFINEMENT); } if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries) method_changed = 1; if (RMODULE_CONST_TBL(module) && RMODULE_CONST_TBL(module)->num_entries) constant_changed = 1; skip: module = RCLASS_SUPER(module); } if (method_changed) rb_clear_method_cache_by_class(klass); if (constant_changed) rb_clear_constant_cache(); return method_changed; }
VALUE rb_obj_singleton_methods(int argc, VALUE *argv, VALUE obj) { VALUE recur, ary, klass, origin; st_table *list, *mtbl; if (argc == 0) { recur = Qtrue; } else { rb_scan_args(argc, argv, "01", &recur); } klass = CLASS_OF(obj); origin = RCLASS_ORIGIN(klass); list = st_init_numtable(); if (klass && FL_TEST(klass, FL_SINGLETON)) { if ((mtbl = RCLASS_M_TBL(origin)) != 0) st_foreach(mtbl, method_entry_i, (st_data_t)list); klass = RCLASS_SUPER(klass); } if (RTEST(recur)) { while (klass && (FL_TEST(klass, FL_SINGLETON) || RB_TYPE_P(klass, T_ICLASS))) { if (klass != origin && (mtbl = RCLASS_M_TBL(klass)) != 0) st_foreach(mtbl, method_entry_i, (st_data_t)list); klass = RCLASS_SUPER(klass); } } ary = rb_ary_new(); st_foreach(list, ins_methods_i, ary); st_free_table(list); return ary; }
/* :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 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; }
static void remove_method(VALUE klass, ID mid) { st_data_t key, data; rb_method_entry_t *me = 0; VALUE self = klass; klass = RCLASS_ORIGIN(klass); rb_frozen_class_p(klass); if (mid == object_id || mid == id__send__ || mid == idInitialize) { rb_warn("removing `%s' may cause serious problems", rb_id2name(mid)); } if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) || !(me = (rb_method_entry_t *)data) || (!me->def || me->def->type == VM_METHOD_TYPE_UNDEF) || UNDEFINED_REFINED_METHOD_P(me->def)) { rb_name_error(mid, "method `%"PRIsVALUE"' not defined in %"PRIsVALUE, rb_id2str(mid), rb_class_path(klass)); } key = (st_data_t)mid; st_delete(RCLASS_M_TBL(klass), &key, &data); rb_vm_check_redefinition_opt_method(me, klass); rb_clear_method_cache_by_class(klass); rb_unlink_method_entry(me); if (me->def->type == VM_METHOD_TYPE_REFINED) { rb_add_refined_method_entry(klass, mid); } CALL_METHOD_HOOK(self, removed, mid); }
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; } }
void rb_prepend_module(VALUE klass, VALUE module) { void rb_vm_check_redefinition_by_prepend(VALUE klass); VALUE origin; int changed = 0; rb_frozen_class_p(klass); Check_Type(module, T_MODULE); OBJ_INFECT(klass, module); origin = RCLASS_ORIGIN(klass); if (origin == klass) { origin = class_alloc(T_ICLASS, klass); OBJ_WB_UNPROTECT(origin); /* TODO: conservertive shading. Need more survery. */ RCLASS_SET_SUPER(origin, RCLASS_SUPER(klass)); RCLASS_SET_SUPER(klass, origin); RCLASS_ORIGIN(klass) = origin; RCLASS_M_TBL_WRAPPER(origin) = RCLASS_M_TBL_WRAPPER(klass); RCLASS_M_TBL_INIT(klass); st_foreach(RCLASS_M_TBL(origin), move_refined_method, (st_data_t) RCLASS_M_TBL(klass)); } changed = include_modules_at(klass, klass, module); if (changed < 0) rb_raise(rb_eArgError, "cyclic prepend detected"); if (changed) { rb_vm_check_redefinition_by_prepend(klass); } }
void rb_alias(VALUE klass, ID name, ID def) { NODE *orig_fbody, *node, *method; VALUE singleton = 0; st_data_t data; rb_frozen_class_p(klass); if (klass == rb_cObject) { rb_secure(4); } orig_fbody = search_method(klass, def, 0); if (!orig_fbody || !orig_fbody->nd_body) { if (TYPE(klass) == T_MODULE) { orig_fbody = search_method(rb_cObject, def, 0); } } if (!orig_fbody || !orig_fbody->nd_body) { rb_print_undef(klass, def, 0); } if (FL_TEST(klass, FL_SINGLETON)) { singleton = rb_iv_get(klass, "__attached__"); } orig_fbody->nd_cnt++; if (st_lookup(RCLASS_M_TBL(klass), name, &data)) { node = (NODE *)data; if (node) { if (RTEST(ruby_verbose) && node->nd_cnt == 0 && node->nd_body) { rb_warning("discarding old %s", rb_id2name(name)); } if (nd_type(node->nd_body->nd_body) == NODE_CFUNC) { rb_vm_check_redefinition_opt_method(node); } } } st_insert(RCLASS_M_TBL(klass), name, (st_data_t) NEW_FBODY( method = NEW_METHOD(orig_fbody->nd_body->nd_body, orig_fbody->nd_body->nd_clss, NOEX_WITH_SAFE(orig_fbody->nd_body->nd_noex)), def)); method->nd_file = (void *)def; rb_clear_cache_by_id(name); if (!ruby_running) return; if (singleton) { rb_funcall(singleton, singleton_added, 1, ID2SYM(name)); } else { rb_funcall(klass, added, 1, ID2SYM(name)); } }
/* call-seq: * swap_method_tables(other) -> self * * Swap the method table of the receiver with the method table of the given * class or module. If +other+ is not a class or module, raise a +TypeError+. */ static VALUE evilr_swap_method_tables(VALUE self, VALUE other) { struct st_table *tmp; evilr__check_immediate(other); if(BUILTIN_TYPE(other) != T_MODULE && BUILTIN_TYPE(other) != T_CLASS) { rb_raise(rb_eTypeError, "non-class or module used"); } tmp = RCLASS_M_TBL(self); RCLASS(self)->m_tbl = RCLASS_M_TBL(other); RCLASS(other)->m_tbl = tmp; rb_clear_cache_by_class(self); rb_clear_cache_by_class(other); return self; }
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; }
static VALUE internal_instance_methods(VALUE klass, long visibility) { add_method_if_matching_arg_t arg; arg.names = rb_ary_new(); arg.visibility = visibility; st_foreach(RCLASS_M_TBL(klass), add_method_if_matching, (st_data_t)&arg); return arg.names; }
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 class_instance_method_list(int argc, VALUE *argv, VALUE mod, int (*func) (ID, long, VALUE)) { VALUE ary; int recur; st_table *list; if (argc == 0) { recur = TRUE; } else { VALUE r; rb_scan_args(argc, argv, "01", &r); recur = RTEST(r); } list = st_init_numtable(); for (; mod; mod = RCLASS_SUPER(mod)) { st_foreach(RCLASS_M_TBL(mod), method_entry, (st_data_t)list); if (BUILTIN_TYPE(mod) == T_ICLASS) continue; if (FL_TEST(mod, FL_SINGLETON)) continue; if (!recur) break; } ary = rb_ary_new(); st_foreach(list, func, ary); st_free_table(list); return ary; }
/* :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; }
/* 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 VALUE internal_instance_methods(VALUE klass, VISIBILITY_TYPE visibility) { add_method_if_matching_arg_t arg; arg.names = rb_ary_new(); arg.visibility = visibility; Looksee_method_table_foreach(RCLASS_M_TBL(klass), add_method_if_matching, (st_data_t)&arg); return arg.names; }
void rb_include_module(VALUE klass, VALUE module) { VALUE p, c; int changed = 0; rb_frozen_class_p(klass); if (!OBJ_UNTRUSTED(klass)) { rb_secure(4); } if (TYPE(module) != T_MODULE) { Check_Type(module, T_MODULE); } OBJ_INFECT(klass, module); c = klass; while (module) { int superclass_seen = FALSE; if (RCLASS_M_TBL(klass) == RCLASS_M_TBL(module)) rb_raise(rb_eArgError, "cyclic include detected"); /* ignore if the module included already in superclasses */ for (p = RCLASS_SUPER(klass); p; p = RCLASS_SUPER(p)) { switch (BUILTIN_TYPE(p)) { case T_ICLASS: if (RCLASS_M_TBL(p) == RCLASS_M_TBL(module)) { if (!superclass_seen) { c = p; /* move insertion point */ } goto skip; } break; case T_CLASS: superclass_seen = TRUE; break; } } c = RCLASS_SUPER(c) = include_class_new(module, RCLASS_SUPER(c)); if (RMODULE_M_TBL(module) && RMODULE_M_TBL(module)->num_entries) changed = 1; skip: module = RCLASS_SUPER(module); } if (changed) rb_clear_cache(); }
/* :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; }
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 }
VALUE rb_module_new(void) { VALUE mdl = class_alloc(T_MODULE, rb_cModule); RCLASS_M_TBL(mdl) = st_init_numtable(); return (VALUE)mdl; }
static void remove_method(VALUE klass, ID mid) { st_data_t data; NODE *body = 0; if (klass == rb_cObject) { rb_secure(4); } if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) { rb_raise(rb_eSecurityError, "Insecure: can't remove method"); } if (OBJ_FROZEN(klass)) rb_error_frozen("class/module"); if (mid == object_id || mid == __send__ || mid == idInitialize) { rb_warn("removing `%s' may cause serious problem", rb_id2name(mid)); } if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) { body = (NODE *)data; if (!body || !body->nd_body) body = 0; else { st_delete(RCLASS_M_TBL(klass), &mid, &data); } } if (!body) { rb_name_error(mid, "method `%s' not defined in %s", rb_id2name(mid), rb_class2name(klass)); } if (nd_type(body->nd_body->nd_body) == NODE_CFUNC) { rb_vm_check_redefinition_opt_method(body); } rb_clear_cache_for_undef(klass, mid); if (FL_TEST(klass, FL_SINGLETON)) { rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1, ID2SYM(mid)); } else { rb_funcall(klass, removed, 1, ID2SYM(mid)); } }
/*! * A utility function that wraps class_alloc. * * allocates a class and initializes safely. * \param super a class from which the new class derives. * \return a class object. * \pre \a super must be a class. * \post the metaclass of the new class is Class. */ VALUE rb_class_boot(VALUE super) { VALUE klass = class_alloc(T_CLASS, rb_cClass); RCLASS_SUPER(klass) = super; RCLASS_M_TBL(klass) = st_init_numtable(); OBJ_INFECT(klass, super); return (VALUE)klass; }
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(clone) = st_init_numtable(); 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; } }
static inline rb_method_entry_t * lookup_method_table(VALUE klass, ID id) { st_data_t body; st_table *m_tbl = RCLASS_M_TBL(klass); if (st_lookup(m_tbl, id, &body)) { return (rb_method_entry_t *) body; } else { return 0; } }