Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
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);
    }
}
Example #4
0
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;
}
Example #5
0
File: class.c Project: fi8on/ruby
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();
}
Example #6
0
/* 
 * 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;
}
Example #7
0
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();
}
Example #8
0
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();
}