static VALUE rb_mixin(VALUE self, VALUE module) { VALUE nested_modules; int index; /* check that module is valid */ if (TYPE(module) != T_MODULE) rb_raise(rb_eArgError, "error: parameter must be a module"); rb_unmix(self, module); nested_modules = rb_mod_included_modules(module); for (index = RARRAY_LEN(nested_modules); index > 0; index--) { VALUE nested_module = RARRAY_PTR(nested_modules)[index - 1]; add_module(self, nested_module); } add_module(self, module); rb_clear_cache(); /* If the module is added, call the mixed_in(obj) hook on * the added module */ rb_funcall(module, rb_intern("mixed_in"), 1, self); return self; }
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; }
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 VALUE do_unmix(VALUE self, VALUE receiver, VALUE module) { VALUE klass = CLASS_OF(receiver); while (klass != rb_class_real(klass)) { VALUE super = RCLASS_SUPER(klass); if (BUILTIN_TYPE(super) == T_ICLASS && CLASS_OF(super) == module) { if (RCLASS_SUPER(module) && BUILTIN_TYPE(RCLASS_SUPER(module)) == T_ICLASS) { remove_nested_module(super, module); } RCLASS_SUPER(klass) = RCLASS_SUPER(super); rb_clear_cache(); } klass = super; } return receiver; }
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(); }
/* * call-seq: * remove_features(mod) => mod * * When this module is unincluded from another, Ruby Internal calls * remove_features in this module. The default behavior is to remove * the constants, methods, and module variables of this module from * _mod_. If this module has not been included by _mod_, an exception * will be raised. */ static VALUE module_remove_features(VALUE module, VALUE uninclude) { VALUE prev, mod; if(TYPE(uninclude) != T_CLASS && TYPE(uninclude) != T_MODULE) { Check_Type(uninclude, T_CLASS); } rb_frozen_class_p(uninclude); if(!OBJ_TAINTED(uninclude)) { rb_secure(4); } OBJ_INFECT(uninclude, module); if(RCLASS(uninclude)->m_tbl == RCLASS(module)->m_tbl) { rb_raise(rb_eArgError, "Cannot remove module from itself"); } prev = uninclude; mod = RCLASS_SUPER(uninclude); while(mod) { if(RCLASS(module)->m_tbl == RCLASS(mod)->m_tbl) { RCLASS_SUPER(prev) = RCLASS_SUPER(mod); rb_clear_cache(); return module; } if(BUILTIN_TYPE(mod) == T_CLASS) { break; } prev = mod; mod = RCLASS_SUPER(mod); } rb_raise(rb_eArgError, "Could not find included module"); return module; }
void rb_include_module(VALUE klass, VALUE module) { VALUE p, c; int changed = 0; rb_frozen_class_p(klass); if (!OBJ_TAINTED(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 = Qfalse; if (RCLASS(klass)->m_tbl == RCLASS(module)->m_tbl) rb_raise(rb_eArgError, "cyclic include detected"); /* ignore if the module included already in superclasses */ for (p = RCLASS(klass)->super; p; p = RCLASS(p)->super) { switch (BUILTIN_TYPE(p)) { case T_ICLASS: if (RCLASS(p)->m_tbl == RCLASS(module)->m_tbl) { if (!superclass_seen) { c = p; /* move insertion point */ } goto skip; } break; case T_CLASS: superclass_seen = Qtrue; break; } } c = RCLASS(c)->super = include_class_new(module, RCLASS(c)->super); changed = 1; skip: module = RCLASS(module)->super; } if (changed) rb_clear_cache(); }
void rb_include_module(VALUE klass, VALUE module) { int changed = 0; rb_frozen_class_p(klass); if (!RB_TYPE_P(module, T_MODULE)) { Check_Type(module, T_MODULE); } OBJ_INFECT(klass, module); changed = include_modules_at(klass, RCLASS_ORIGIN(klass), module); if (changed < 0) rb_raise(rb_eArgError, "cyclic include detected"); if (changed) rb_clear_cache(); }