[前][次][番号順一覧][スレッド一覧]

ruby-changes:24545

From: shugo <ko1@a...>
Date: Thu, 2 Aug 2012 20:34:35 +0900 (JST)
Subject: [ruby-changes:24545] shugo:r36596 (trunk): * eval.c (rb_mod_using): new method Module#using. [experimental]

shugo	2012-08-02 20:34:19 +0900 (Thu, 02 Aug 2012)

  New Revision: 36596

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=36596

  Log:
    * eval.c (rb_mod_using): new method Module#using. [experimental]
    
    * eval.c (rb_mod_refine): new method Module#refine. [experimental]
    
    * eval.c (f_using): new method Kernel#using. [experimental]

  Added files:
    trunk/test/ruby/test_refinement.rb
  Modified files:
    trunk/ChangeLog
    trunk/class.c
    trunk/eval.c
    trunk/gc.c
    trunk/include/ruby/intern.h
    trunk/include/ruby/ruby.h
    trunk/insns.def
    trunk/iseq.c
    trunk/method.h
    trunk/node.h
    trunk/object.c
    trunk/test/ruby/test_fiber.rb
    trunk/test/ruby/test_thread.rb
    trunk/vm.c
    trunk/vm_eval.c
    trunk/vm_insnhelper.c
    trunk/vm_insnhelper.h
    trunk/vm_method.c

Index: method.h
===================================================================
--- method.h	(revision 36595)
+++ method.h	(revision 36596)
@@ -91,7 +91,8 @@
 rb_method_entry_t *rb_add_method(VALUE klass, ID mid, rb_method_type_t type, void *option, rb_method_flag_t noex);
 rb_method_entry_t *rb_method_entry(VALUE klass, ID id, VALUE *define_class_ptr);
 
-rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, ID id, VALUE *define_class_ptr);
+rb_method_entry_t *rb_method_entry_get_with_omod(VALUE omod, VALUE klass, ID id, VALUE *define_class_ptr);
+rb_method_entry_t *rb_method_entry_get_without_cache(VALUE klass, VALUE omod, ID id, VALUE *define_class_ptr);
 rb_method_entry_t *rb_method_entry_set(VALUE klass, ID mid, const rb_method_entry_t *, rb_method_flag_t noex);
 
 int rb_method_entry_arity(const rb_method_entry_t *me);
Index: include/ruby/intern.h
===================================================================
--- include/ruby/intern.h	(revision 36595)
+++ include/ruby/intern.h	(revision 36596)
@@ -173,6 +173,7 @@
 VALUE rb_module_new(void);
 VALUE rb_define_module_id(ID);
 VALUE rb_define_module_id_under(VALUE, ID);
+VALUE rb_include_class_new(VALUE, VALUE);
 VALUE rb_mod_included_modules(VALUE);
 VALUE rb_mod_include_p(VALUE, VALUE);
 VALUE rb_mod_ancestors(VALUE);
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 36595)
+++ include/ruby/ruby.h	(revision 36596)
@@ -655,6 +655,7 @@
 #define RMODULE_CONST_TBL(m) RCLASS_CONST_TBL(m)
 #define RMODULE_M_TBL(m) RCLASS_M_TBL(m)
 #define RMODULE_SUPER(m) RCLASS_SUPER(m)
+#define RMODULE_IS_OVERLAYED FL_USER2
 
 struct RFloat {
     struct RBasic basic;
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 36595)
+++ ChangeLog	(revision 36596)
@@ -1,3 +1,11 @@
+Thu Aug  2 20:32:29 2012  Shugo Maeda  <shugo@r...>
+
+	* eval.c (rb_mod_using): new method Module#using. [experimental]
+
+	* eval.c (rb_mod_refine): new method Module#refine. [experimental]
+
+	* eval.c (f_using): new method Kernel#using. [experimental]
+
 Thu Aug  2 20:08:02 2012  Shugo Maeda  <shugo@r...>
 
 	* class.c, insns.def, method.h, proc.c, vm.c, vm_core.h, vm_eval.c,
Index: insns.def
===================================================================
--- insns.def	(revision 36595)
+++ insns.def	(revision 36596)
@@ -183,8 +183,8 @@
 ()
 (VALUE val)
 {
-    NODE *cref = vm_get_cref(GET_ISEQ(), GET_EP());
-    val = rb_cvar_get(vm_get_cvar_base(cref), id);
+    NODE *cref = rb_vm_get_cref(GET_ISEQ(), GET_EP());
+    val = rb_cvar_get(vm_get_cvar_base(cref, GET_CFP()), id);
 }
 
 /**
@@ -198,8 +198,8 @@
 (VALUE val)
 ()
 {
-    NODE *cref = vm_get_cref(GET_ISEQ(), GET_EP());
-    rb_cvar_set(vm_get_cvar_base(cref), id, val);
+    NODE *cref = rb_vm_get_cref(GET_ISEQ(), GET_EP());
+    rb_cvar_set(vm_get_cvar_base(cref, GET_CFP()), id, val);
 }
 
 /**
@@ -777,8 +777,8 @@
 	break;
       case DEFINED_CVAR:
 	{
-	NODE *cref = vm_get_cref(GET_ISEQ(), GET_EP());
-	klass = vm_get_cvar_base(cref);
+	NODE *cref = rb_vm_get_cref(GET_ISEQ(), GET_EP());
+	klass = vm_get_cvar_base(cref, GET_CFP());
 	if (rb_cvar_defined(klass, SYM2ID(obj))) {
 	    expr_type = "class variable";
 	}
@@ -970,6 +970,7 @@
 		  klass, 0, VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()),
 		  class_iseq->iseq_encoded, GET_SP(),
 		  class_iseq->local_size, 0);
+    rb_vm_using_modules(class_iseq->cref_stack, klass);
     RESTORE_REGS();
 
     INC_VM_STATE_VERSION();
@@ -1044,12 +1045,11 @@
     while (ip && !ip->klass) {
 	ip = ip->parent_iseq;
     }
-  again:
     me = rb_method_entry(klass, id, &klass);
     if (me && me->def->type == VM_METHOD_TYPE_ISEQ &&
 	me->def->body.iseq == ip) {
 	klass = RCLASS_SUPER(klass);
-	goto again;
+	me = rb_method_entry_get_with_omod(Qnil, klass, id, &klass);
     }
 
     CALL_METHOD(num, blockptr, flag, id, me, recv, klass);
Index: iseq.c
===================================================================
--- iseq.c	(revision 36595)
+++ iseq.c	(revision 36596)
@@ -199,17 +199,20 @@
     /* set class nest stack */
     if (type == ISEQ_TYPE_TOP) {
 	/* toplevel is private */
-	iseq->cref_stack = NEW_BLOCK(rb_cObject);
+	iseq->cref_stack = NEW_CREF(rb_cObject);
+	iseq->cref_stack->nd_omod = Qnil;
 	iseq->cref_stack->nd_visi = NOEX_PRIVATE;
 	if (th->top_wrapper) {
-	    NODE *cref = NEW_BLOCK(th->top_wrapper);
+	    NODE *cref = NEW_CREF(th->top_wrapper);
+	    cref->nd_omod = Qnil;
 	    cref->nd_visi = NOEX_PRIVATE;
 	    cref->nd_next = iseq->cref_stack;
 	    iseq->cref_stack = cref;
 	}
     }
     else if (type == ISEQ_TYPE_METHOD || type == ISEQ_TYPE_CLASS) {
-	iseq->cref_stack = NEW_BLOCK(0); /* place holder */
+	iseq->cref_stack = NEW_CREF(0); /* place holder */
+	iseq->cref_stack->nd_omod = Qnil;
     }
     else if (RTEST(parent)) {
 	rb_iseq_t *piseq;
@@ -1653,7 +1656,9 @@
 	iseq1->local_iseq = iseq1;
     }
     if (newcbase) {
-	iseq1->cref_stack = NEW_BLOCK(newcbase);
+	iseq1->cref_stack = NEW_CREF(newcbase);
+	iseq1->cref_stack->nd_omod = iseq0->cref_stack->nd_omod;
+	iseq1->cref_stack->nd_visi = iseq0->cref_stack->nd_visi;
 	if (iseq0->cref_stack->nd_next) {
 	    iseq1->cref_stack->nd_next = iseq0->cref_stack->nd_next;
 	}
Index: object.c
===================================================================
--- object.c	(revision 36595)
+++ object.c	(revision 36596)
@@ -2863,6 +2863,7 @@
     rb_define_private_method(rb_cModule, "included", rb_obj_dummy, 1);
     rb_define_private_method(rb_cModule, "extended", rb_obj_dummy, 1);
     rb_define_private_method(rb_cModule, "prepended", rb_obj_dummy, 1);
+    rb_define_private_method(rb_cModule, "used", rb_obj_dummy, 1);
     rb_define_private_method(rb_cModule, "method_added", rb_obj_dummy, 1);
     rb_define_private_method(rb_cModule, "method_removed", rb_obj_dummy, 1);
     rb_define_private_method(rb_cModule, "method_undefined", rb_obj_dummy, 1);
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 36595)
+++ vm_eval.c	(revision 36596)
@@ -391,7 +391,7 @@
                          rb_id2name(mid), type, (void *)recv, flags, klass);
         }
     }
-    return rb_method_entry(klass, mid, defined_class_ptr);
+    return rb_method_entry_get_with_omod(Qnil, klass, mid, defined_class_ptr);
 }
 
 static inline int
@@ -1310,6 +1310,7 @@
     }
     cref = vm_cref_push(th, under, NOEX_PUBLIC, blockptr);
     cref->flags |= NODE_FL_CREF_PUSHED_BY_EVAL;
+    rb_vm_using_modules(cref, under);
 
     if (values == Qundef) {
 	return vm_yield_with_cref(th, 1, &self, cref);
@@ -1331,6 +1332,7 @@
     else {
 	SafeStringValue(src);
     }
+    rb_vm_using_modules(cref, under);
 
     return eval_string_with_cref(self, src, Qnil, cref, file, line);
 }
Index: vm_method.c
===================================================================
--- vm_method.c	(revision 36595)
+++ vm_method.c	(revision 36596)
@@ -4,7 +4,7 @@
 
 #define CACHE_SIZE 0x800
 #define CACHE_MASK 0x7ff
-#define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
+#define EXPR1(c,o,m) ((((c)>>3)^((o)>>3)^(m))&CACHE_MASK)
 
 #define NOEX_NOREDEF 0
 #ifndef NOEX_NOREDEF
@@ -21,6 +21,7 @@
     VALUE filled_version;        /* filled state version */
     ID mid;			/* method's id */
     VALUE klass;		/* receiver's class */
+    VALUE omod;			/* overlay modules */
     rb_method_entry_t *me;
     VALUE defined_class;
 };
@@ -385,12 +386,20 @@
 }
 
 static rb_method_entry_t*
-search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
+search_method(VALUE klass, ID id, VALUE omod, VALUE *defined_class_ptr)
 {
     st_data_t body;
+    VALUE iclass, skipped_class = Qnil;
 
     for (body = 0; klass; klass = RCLASS_SUPER(klass)) {
-	st_table *m_tbl = RCLASS_M_TBL(klass);
+	st_table *m_tbl;
+
+	if (!NIL_P(omod) && klass != skipped_class &&
+	    !NIL_P(iclass = rb_hash_lookup(omod, klass))) {
+	    skipped_class = klass;
+	    klass = iclass;
+	}
+	m_tbl = RCLASS_M_TBL(klass);
 	if (!m_tbl) {
 	    m_tbl = RCLASS_M_TBL(RCLASS_ORIGIN(RBASIC(klass)->klass));
 	}
@@ -409,17 +418,18 @@
  * rb_method_entry() simply.
  */
 rb_method_entry_t *
-rb_method_entry_get_without_cache(VALUE klass, ID id,
+rb_method_entry_get_without_cache(VALUE klass, VALUE omod, ID id,
 				  VALUE *defined_class_ptr)
 {
     VALUE defined_class;
-    rb_method_entry_t *me = search_method(klass, id, &defined_class);
+    rb_method_entry_t *me = search_method(klass, id, omod, &defined_class);
 
     if (ruby_running) {
 	struct cache_entry *ent;
-	ent = cache + EXPR1(klass, id);
+	ent = cache + EXPR1(klass, omod, id);
 	ent->filled_version = GET_VM_STATE_VERSION();
 	ent->klass = klass;
+	ent->omod = omod;
 	ent->defined_class = defined_class;
 
 	if (UNDEFINED_METHOD_ENTRY_P(me)) {
@@ -439,21 +449,35 @@
 }
 
 rb_method_entry_t *
-rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
+rb_method_entry_get_with_omod(VALUE omod, VALUE klass, ID id,
+			      VALUE *defined_class_ptr)
 {
     struct cache_entry *ent;
 
-    ent = cache + EXPR1(klass, id);
+    ent = cache + EXPR1(klass, omod, id);
     if (ent->filled_version == GET_VM_STATE_VERSION() &&
-	ent->mid == id && ent->klass == klass) {
+	ent->mid == id && ent->klass == klass && ent->omod == omod) {
 	if (defined_class_ptr)
 	    *defined_class_ptr = ent->defined_class;
 	return ent->me;
     }
 
-    return rb_method_entry_get_without_cache(klass, id, defined_class_ptr);
+    return rb_method_entry_get_without_cache(klass, omod, id,
+					     defined_class_ptr);
 }
 
+rb_method_entry_t *
+rb_method_entry(VALUE klass, ID id, VALUE *defined_class_ptr)
+{
+    NODE *cref = rb_vm_cref();
+    VALUE omod = Qnil;
+
+    if (cref && !NIL_P(cref->nd_omod)) {
+	omod = cref->nd_omod;
+    }
+    return rb_method_entry_get_with_omod(omod, klass, id, defined_class_ptr);
+}
+
 static void
 remove_method(VALUE klass, ID mid)
 {
@@ -550,9 +574,9 @@
 	rb_secure(4);
     }
 
-    me = search_method(klass, name, &defined_class);
+    me = search_method(klass, name, Qnil, &defined_class);
     if (!me && RB_TYPE_P(klass, T_MODULE)) {
-	me = search_method(rb_cObject, name, &defined_class);
+	me = search_method(rb_cObject, name, Qnil, &defined_class);
     }
 
     if (UNDEFINED_METHOD_ENTRY_P(me)) {
@@ -640,6 +664,9 @@
 rb_undef(VALUE klass, ID id)
 {
     rb_method_entry_t *me;
+    NODE *cref = rb_vm_cref();
+    VALUE omod = Qnil;
+    void rb_overlay_module(NODE *cref, VALUE klass, VALUE module);
 
     if (NIL_P(klass)) {
 	rb_raise(rb_eTypeError, "no class to undef method");
@@ -655,7 +682,10 @@
 	rb_warn("undefining `%s' may cause serious problems", rb_id2name(id));
     }
 
-    me = search_method(klass, id, 0);
+    if (cref && !NIL_P(cref->nd_omod)) {
+	omod = cref->nd_omod;
+    }
+    me = search_method(klass, id, omod, 0);
 
     if (UNDEFINED_METHOD_ENTRY_P(me)) {
 	const char *s0 = " class";
@@ -676,6 +706,11 @@
 		      rb_id2name(id), s0, rb_class2name(c));
     }
 
+    if (!RTEST(rb_class_inherited_p(klass, me->klass))) {
+	VALUE mod = rb_module_new();
+	rb_overlay_module(cref, klass, mod);
+	klass = mod;
+    }
     rb_add_method(klass, id, VM_METHOD_TYPE_UNDEF, 0, NOEX_PUBLIC);
 
     CALL_METHOD_HOOK(klass, undefined, id);
@@ -980,11 +1015,11 @@
     }
 
   again:
-    orig_me = search_method(klass, def, 0);
+    orig_me = search_method(klass, def, Qnil, 0);
 
     if (UNDEFINED_METHOD_ENTRY_P(orig_me)) {
 	if ((!RB_TYPE_P(klass, T_MODULE)) ||
-	    (orig_me = search_method(rb_cObject, def, 0),
+	    (orig_me = search_method(rb_cObject, def, Qnil, 0),
 	     UNDEFINED_METHOD_ENTRY_P(orig_me))) {
 	    rb_print_undef(klass, def, 0);
 	}
@@ -1260,9 +1295,9 @@
 
 	id = rb_to_id(argv[i]);
 	for (;;) {
-	    me = search_method(m, id, 0);
+	    me = search_method(m, id, Qnil, 0);
 	    if (me == 0) {
-		me = search_method(rb_cObject, id, 0);
+		me = search_method(rb_cObject, id, Qnil, 0);
 	    }
 	    if (UNDEFINED_METHOD_ENTRY_P(me)) {
 		rb_print_undef(module, id, 0);
@@ -1376,6 +1411,20 @@
 }
 
 void
+rb_redefine_opt_method(VALUE klass, ID mid)
+{
+    st_data_t data;
+    rb_method_entry_t *me = 0;
+
+    if (!st_lookup(RCLASS_M_TBL(klass), mid, &data) ||
+	!(me = (rb_method_entry_t *)data) ||
+	(!me->def || me->def->type == VM_METHOD_TYPE_UNDEF)) {
+	return;
+    }
+    rb_vm_check_redefinition_opt_method(me, klass);
+}
+
+void
 Init_eval_method(void)
 {
 #undef rb_intern
Index: eval.c
===================================================================
--- eval.c	(revision 36595)
+++ eval.c	(revision 36596)
@@ -23,6 +23,8 @@
 
 NORETURN(void rb_raise_jump(VALUE));
 
+NODE *rb_vm_get_cref(const rb_iseq_t *, const VALUE *);
+
 VALUE rb_eLocalJumpError;
 VALUE rb_eSysStackError;
 
@@ -1025,6 +1027,180 @@
 }
 
 void
+rb_overlay_module(NODE *cref, VALUE klass, VALUE module)
+{
+    VALUE iclass, c, superclass = klass;
+
+    Check_Type(klass, T_CLASS);
+    Check_Type(module, T_MODULE);
+    if (NIL_P(cref->nd_omod)) {
+	cref->nd_omod = rb_hash_new();
+	rb_funcall(cref->nd_omod, rb_intern("compare_by_identity"), 0);
+    }
+    else {
+	if (cref->flags & NODE_FL_CREF_OMOD_SHARED) {
+	    cref->nd_omod = rb_hash_dup(cref->nd_omod);
+	    cref->flags &= ~NODE_FL_CREF_OMOD_SHARED;
+	}
+	if (!NIL_P(c = rb_hash_lookup(cref->nd_omod, klass))) {
+	    superclass = c;
+	    while (c && TYPE(c) == T_ICLASS) {
+		if (RBASIC(c)->klass == module) {
+		    /* already overlayed module */
+		    return;
+		}
+		c = RCLASS_SUPER(c);
+	    }
+	}
+    }
+    FL_SET(module, RMODULE_IS_OVERLAYED);
+    c = iclass = rb_include_class_new(module, superclass);
+    module = RCLASS_SUPER(module);
+    while (module) {
+	FL_SET(module, RMODULE_IS_OVERLAYED);
+	c = RCLASS_SUPER(c) = rb_include_class_new(module, RCLASS_SUPER(c));
+	module = RCLASS_SUPER(module);
+    }
+    rb_hash_aset(cref->nd_omod, klass, iclass);
+    rb_clear_cache_by_class(klass);
+}
+
+static int
+using_module_i(VALUE klass, VALUE module, VALUE arg)
+{
+    NODE *cref = (NODE *) arg;
+
+    rb_overlay_module(cref, klass, module);
+    return ST_CONTINUE;
+}
+
+void
+rb_using_module(NODE *cref, VALUE module)
+{
+    ID id_overlayed_modules;
+    VALUE overlayed_modules;
+
+    Check_Type(module, T_MODULE);
+    CONST_ID(id_overlayed_modules, "__overlayed_modules__");
+    overlayed_modules = rb_attr_get(module, id_overlayed_modules);
+    if (NIL_P(overlayed_modules)) return;
+    rb_hash_foreach(overlayed_modules, using_module_i, (VALUE) cref);
+}
+
+/*
+ *  call-seq:
+ *     using(module)    -> self
+ *
+ *  Import class refinements from <i>module</i> into the receiver.
+ */
+
+static VALUE
+rb_mod_using(VALUE self, VALUE module)
+{
+    NODE *cref = rb_vm_cref();
+    ID id_using_modules;
+    VALUE using_modules;
+
+    CONST_ID(id_using_modules, "__using_modules__");
+    using_modules = rb_attr_get(self, id_using_modules);
+    if (NIL_P(using_modules)) {
+	using_modules = rb_hash_new();
+	rb_funcall(using_modules, rb_intern("compare_by_identity"), 0);
+	rb_ivar_set(self, id_using_modules, using_modules);
+    }
+    rb_hash_aset(using_modules, module, Qtrue);
+    rb_using_module(cref, module);
+    rb_funcall(module, rb_intern("used"), 1, self);
+    return self;
+}
+
+void rb_redefine_opt_method(VALUE, ID);
+
+static VALUE
+refinement_module_method_added(VALUE mod, VALUE mid)
+{
+    ID id = SYM2ID(mid);
+    ID id_refined_class;
+    VALUE klass;
+
+    CONST_ID(id_refined_class, "__refined_class__");
+    klass = rb_ivar_get(mod, id_refined_class);
+    rb_redefine_opt_method(klass, id);
+    return Qnil;
+}
+
+static VALUE
+refinement_module_include(int argc, VALUE *argv, VALUE module)
+{
+    rb_thread_t *th = GET_THREAD();
+    rb_control_frame_t *cfp = th->cfp;
+    rb_control_frame_t *end_cfp = RUBY_VM_END_CONTROL_FRAME(th);
+    VALUE result = rb_mod_include(argc, argv, module);
+    NODE *cref;
+    ID id_refined_class;
+    VALUE klass, c;
+
+    CONST_ID(id_refined_class, "__refined_class__");
+    klass = rb_attr_get(module, id_refined_class);
+    while (RUBY_VM_VALID_CONTROL_FRAME_P(cfp, end_cfp)) {
+	if (RUBY_VM_NORMAL_ISEQ_P(cfp->iseq) &&
+	    (cref = rb_vm_get_cref(cfp->iseq, cfp->ep)) &&
+	    !NIL_P(cref->nd_omod) &&
+	    !NIL_P(c = rb_hash_lookup(cref->nd_omod, klass))) {
+	    while (argc--) {
+		VALUE mod = argv[argc];
+		if (rb_class_inherited_p(module, mod)) {
+		    RCLASS_SUPER(c) =
+			rb_include_class_new(mod, RCLASS_SUPER(c));
+		}
+	    }
+	    break;
+	}
+	cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+    }
+    return result;
+}
+
+/*
+ *  call-seq:
+ *     refine(klass) { block }   -> self
+ *
+ *  Refine <i>klass</i> in the receiver.
+ */
+
+static VALUE
+rb_mod_refine(VALUE module, VALUE klass)
+{
+    NODE *cref = rb_vm_cref();
+    VALUE mod;
+    ID id_overlayed_modules, id_refined_class;
+    VALUE overlayed_modules;
+
+    Check_Type(klass, T_CLASS);
+    CONST_ID(id_overlayed_modules, "__overlayed_modules__");
+    overlayed_modules = rb_attr_get(module, id_overlayed_modules);
+    if (NIL_P(overlayed_modules)) {
+	overlayed_modules = rb_hash_new();
+	rb_funcall(overlayed_modules, rb_intern("compare_by_identity"), 0);
+	rb_ivar_set(module, id_overlayed_modules, overlayed_modules);
+    }
+    mod = rb_hash_aref(overlayed_modules, klass);
+    if (NIL_P(mod)) {
+	mod = rb_module_new();
+	CONST_ID(id_refined_class, "__refined_class__");
+	rb_ivar_set(mod, id_refined_class, klass);
+	rb_define_singleton_method(mod, "method_added",
+				   refinement_module_method_added, 1);
+	rb_define_singleton_method(mod, "include",
+				   refinement_module_include, -1);
+	rb_overlay_module(cref, klass, mod);
+	rb_hash_aset(overlayed_modules, klass, mod);
+    }
+    rb_mod_module_eval(0, NULL, mod);
+    return mod;
+}
+
+void
 rb_obj_call_init(VALUE obj, int argc, VALUE *argv)
 {
     PASS_PASSED_BLOCK();
@@ -1134,6 +1310,23 @@
     return rb_mod_include(argc, argv, rb_cObject);
 }
 
+/*
+ *  call-seq:
+ *     using(module)    -> self
+ *
+ *  Import class refinements from <i>module</i> into the scope where
+ *  <code>using</code> is called.
+ */
+
+static VALUE
+f_using(VALUE self, VALUE module)
+{
+    NODE *cref = rb_vm_cref();
+
+    rb_using_module(cref, module);
+    return self;
+}
+
 static VALUE *
 errinfo_place(rb_thread_t *th)
 {
@@ -1298,6 +1491,8 @@
     rb_define_private_method(rb_cModule, "include", rb_mod_include, -1);
     rb_define_private_method(rb_cModule, "prepend_features", rb_mod_prepend_features, 1);
     rb_define_private_method(rb_cModule, "prepend", rb_mod_prepend, -1);
+    rb_define_private_method(rb_cModule, "using", rb_mod_using, 1);
+    rb_define_private_method(rb_cModule, "refine", rb_mod_refine, 1);
 
     rb_undef_method(rb_cClass, "module_function");
 
@@ -1309,6 +1504,8 @@
 
     rb_define_singleton_method(rb_vm_top_self(), "include", top_include, -1);
 
+    rb_define_global_function("using", f_using, 1);
+
     rb_define_method(rb_mKernel, "extend", rb_obj_extend, -1);
 
     rb_define_global_function("trace_var", rb_f_trace_var, -1);	/* in variable.c */
Index: gc.c
===================================================================
--- gc.c	(revision 36595)
+++ gc.c	(revision 36596)
@@ -1994,6 +1994,12 @@
 	    ptr = (VALUE)obj->as.node.u2.node;
 	    goto again;
 
+	  case NODE_CREF:
+	    gc_mark(objspace, obj->as.node.nd_omod, lev);
+	    gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
+	    ptr = (VALUE)obj->as.node.u3.node;
+	    goto again;
+
 	  default:		/* unlisted NODE */
 	    if (is_pointer_to_heap(objspace, obj->as.node.u1.node)) {
 		gc_mark(objspace, (VALUE)obj->as.node.u1.node, lev);
Index: class.c
===================================================================
--- class.c	(revision 36595)
+++ class.c	(revision 36596)
@@ -620,8 +620,8 @@
     return module;
 }
 
-static VALUE
-include_class_new(VALUE module, VALUE super)
+VALUE
+rb_include_class_new(VALUE module, VALUE super)
 {
     VALUE klass = class_alloc( (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]