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 VALUE rb_unmix(VALUE self, VALUE module) { VALUE klass; /* check that module is valid */ if (TYPE(module) != T_MODULE) rb_raise(rb_eArgError, "error: parameter must be a module"); for (klass = KLASS_OF(self); klass != rb_class_real(klass); klass = RCLASS_SUPER(klass)) { VALUE super = RCLASS_SUPER(klass); if (BUILTIN_TYPE(super) == T_ICLASS) { if (KLASS_OF(super) == module) { if (RCLASS_SUPER(module) && BUILTIN_TYPE(RCLASS_SUPER(module)) == T_ICLASS) remove_nested_module(super, module); RCLASS_SUPER(klass) = RCLASS_SUPER(RCLASS_SUPER(klass)); rb_clear_cache(); /* If the module is taken out, call the unmixed(obj) hook on * the module */ rb_funcall(module, rb_intern("unmixed"), 1, self); } } } return self; }
static void remove_nested_module(VALUE klass, VALUE include_class) { if (KLASS_OF(RCLASS_SUPER(klass)) != KLASS_OF(RCLASS_SUPER(include_class))) { return; } if (RCLASS_SUPER(RCLASS_SUPER(include_class)) && BUILTIN_TYPE(RCLASS_SUPER(include_class)) == T_ICLASS) { remove_nested_module(RCLASS_SUPER(klass), RCLASS_SUPER(include_class)); } RCLASS_SUPER(klass) = RCLASS_SUPER(RCLASS_SUPER(klass)); }
VALUE rb_to_module(VALUE self) { VALUE rclass, chain_start, jcur, klass; switch(BUILTIN_TYPE(self)) { case T_MODULE: return self; case T_CLASS: klass = self; break; case T_OBJECT: default: klass = rb_singleton_class(self); } chain_start = j_class_new(klass, rb_cObject); KLASS_OF(chain_start) = rb_cModule; RBASIC(chain_start)->flags = T_MODULE; jcur = chain_start; for(rclass = RCLASS_SUPER(klass); rclass != rb_cObject; rclass = RCLASS_SUPER(rclass)) { RCLASS_SUPER(jcur) = j_class_new(rclass, rb_cObject); jcur = RCLASS_SUPER(jcur); } RCLASS_SUPER(jcur) = (VALUE)NULL; return chain_start; }
/* 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; }