Implement Module#prepend.

This commit is contained in:
Blaž Hrastnik
2015-07-09 23:46:54 +02:00
parent d0e67aada7
commit f962890a92
3 changed files with 99 additions and 2 deletions
+65 -2
View File
@@ -194,6 +194,7 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *
if (mrb_const_defined_at(mrb, mrb_obj_value(outer), name)) {
c = class_from_sym(mrb, outer, name);
c = c->origin;
if (super && mrb_class_real(c->super) != super) {
mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for Class %S (%S not %S)",
mrb_sym2str(mrb, name),
@@ -763,12 +764,13 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
else {
c->super = mrb->object_class;
}
c->origin = c;
c->mt = kh_init(mt, mrb);
return c;
}
MRB_API void
mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
MRB_API inline void
include_module_at(mrb_state *mrb, struct RClass *c, struct RClass *m, int search_super)
{
struct RClass *ins_pos;
@@ -782,6 +784,7 @@ mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
}
while (p) {
if (c != p && p->tt == MRB_TT_CLASS) {
if (!search_super) break;
superclass_seen = 1;
}
else if (p->mt == m->mt) {
@@ -810,6 +813,63 @@ mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
}
}
MRB_API void
mrb_include_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
{
include_module_at(mrb, c, m, FALSE);
}
MRB_API void
mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m)
{
struct RClass *origin;
int changed = 0;
origin = c->origin;
if (origin == c) {
origin = (struct RClass*)mrb_obj_alloc(mrb, MRB_TT_ICLASS, c);
//OBJ_WB_UNPROTECT(origin); /* TODO: conservative shading. Need more survey. */
origin->super = c->super;
c->super = origin;
c->origin = origin;
origin->mt = c->mt;
c->mt = kh_init(mt, mrb);
}
include_module_at(mrb, c, m, FALSE); // changed =
if (changed) {
//rb_vm_check_redefinition_by_prepend(klass);
}
}
static mrb_value
mrb_mod_prepend_features(mrb_state *mrb, mrb_value mod)
{
mrb_value klass;
mrb_check_type(mrb, mod, MRB_TT_MODULE);
mrb_get_args(mrb, "C", &klass);
mrb_prepend_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod));
return mod;
}
static mrb_value
mrb_mod_prepend(mrb_state *mrb, mrb_value klass)
{
mrb_value *argv;
mrb_int argc, i;
mrb_get_args(mrb, "*", &argv, &argc);
for (i=0; i<argc; i++) {
mrb_check_type(mrb, argv[i], MRB_TT_MODULE);
}
while (argc--) {
mrb_funcall(mrb, argv[argc], "prepend_features", 1, klass);
mrb_funcall(mrb, argv[argc], "prepended", 1, klass);
}
return klass;
}
static mrb_value
mrb_mod_append_features(mrb_state *mrb, mrb_value mod)
{
@@ -2090,6 +2150,9 @@ mrb_init_class(mrb_state *mrb)
mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */
mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */
mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */
mrb_define_method(mrb, mod, "prepend", mrb_mod_prepend, MRB_ARGS_ANY());
mrb_define_method(mrb, mod, "prepended", mrb_bob_init, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mod, "prepend_features", mrb_mod_prepend_features, MRB_ARGS_REQ(1));
mrb_define_method(mrb, mod, "include", mrb_mod_include, MRB_ARGS_ANY()); /* 15.2.2.4.27 */
mrb_define_method(mrb, mod, "include?", mrb_mod_include_p, MRB_ARGS_REQ(1)); /* 15.2.2.4.28 */
mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, MRB_ARGS_REQ(1)); /* 15.2.2.4.10 */