Commit f962890a authored by Blaž Hrastnik's avatar Blaž Hrastnik

Implement Module#prepend.

parent d0e67aad
......@@ -16,6 +16,7 @@ struct RClass {
struct iv_tbl *iv;
struct kh_mt *mt;
struct RClass *super;
struct RClass *origin;
};
#define mrb_class_ptr(v) ((struct RClass*)(mrb_ptr(v)))
......
......@@ -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 */
......
......@@ -474,6 +474,39 @@ end
# Not ISO specified
assert('Module#prepend') do
module M0
def m1; [:M0] end
end
module M1
def m1; [:M1, super, :M1] end
end
module M2
def m1; [:M2, super, :M2] end
end
M3 = Module.new do
def m1; [:M3, super, :M3] end
end
module M4
def m1; [:M4, super, :M4] end
end
class C0
include M0
prepend M1
def m1; [:C0, super, :C0] end
end
class C1 < C0
prepend M2, M3
include M4
def m1; [:C1, super, :C1] end
end
obj = C1.new
expected = [:M2,[:M3,[:C1,[:M4,[:M1,[:C0,[:M0],:C0],:M1],:M4],:C1],:M3],:M2]
assert_equal(expected, obj.m1)
end
assert('Module#to_s') do
module Test4to_sModules
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment