Vladimir Sizikov wrote: > I've written a small quick starting guide here: > http://blog.emptyway.com/2008/04/06/the-rubyspecs-quick-starting-guide/ Thanks, vgs% bin/mspec -t ruby spec/ruby/1.8/core/kernel ruby 1.8.6 (2008-04-06 patchlevel 5000) [i686-linux] ....................................................................................................................................................................................................................................................................................................................... Finished in 0.190939 seconds 101 files, 311 examples, 2658 expectations, 0 failures, 0 errors vgs% Please verify it Guy Decoux Index: intern.h =================================================================== --- intern.h (revision 15910) +++ intern.h (working copy) @@ -184,6 +184,8 @@ void rb_obj_call_init _((VALUE, int, VALUE*)); VALUE rb_class_new_instance _((int, VALUE*, VALUE)); VALUE rb_block_proc _((void)); +VALUE rb_block_dup _((VALUE, VALUE, VALUE)); +VALUE rb_method_dup _((VALUE, VALUE, VALUE)); VALUE rb_f_lambda _((void)); VALUE rb_proc_new _((VALUE (*)(ANYARGS/* VALUE yieldarg[, VALUE procarg] */), VALUE)); VALUE rb_protect _((VALUE (*)(VALUE), VALUE, int*)); Index: class.c =================================================================== --- class.c (revision 15910) +++ class.c (working copy) @@ -51,6 +51,7 @@ struct clone_method_data { st_table *tbl; VALUE klass; + VALUE cref; }; static int @@ -59,18 +60,75 @@ NODE *body; struct clone_method_data *data; { - NODE *fbody = body->nd_body; + NODE *node = body->nd_body; + if (node && data->cref) { + switch(nd_type(node)) { + case NODE_SCOPE: + if (node->nd_rval) { + NODE *tmp = NEW_NODE(nd_type(node->u2.node), data->cref, + node->u2.node->u2.node, node->u2.node->u3.node); + node = NEW_NODE(nd_type(node), node->u1.node, tmp, node->u3.node); + } + break; + + case NODE_BMETHOD: + { + VALUE body = rb_block_dup(node->nd_cval, data->klass, data->cref); + node = NEW_BMETHOD(body); + break; + } + + case NODE_DMETHOD: + { + VALUE body = rb_method_dup(node->nd_cval, data->klass, data->cref); + node = NEW_DMETHOD(body); + break; + } - if (fbody && nd_type(fbody) == NODE_SCOPE) { - VALUE cref = data->klass ? - (VALUE)NEW_NODE(NODE_CREF,data->klass,0,fbody->nd_rval) : - fbody->nd_rval; - fbody = NEW_NODE(NODE_SCOPE, fbody->nd_tbl, cref, fbody->nd_next); + } } - st_insert(data->tbl, mid, (st_data_t)NEW_METHOD(fbody, body->nd_noex)); + st_insert(data->tbl, mid, (st_data_t)NEW_METHOD(node, body->nd_noex)); return ST_CONTINUE; } +static VALUE +singleton_class_clone_int(obj, cref) + VALUE obj, cref; +{ + VALUE klass = RBASIC(obj)->klass; + + if (!FL_TEST(klass, FL_SINGLETON)) + return klass; + else { + struct clone_method_data data; + /* copy singleton(unnamed) class */ + NEWOBJ(clone, struct RClass); + OBJSETUP(clone, 0, RBASIC(klass)->flags); + + if (BUILTIN_TYPE(obj) == T_CLASS) { + RBASIC(clone)->klass = (VALUE)clone; + } + else { + RBASIC(clone)->klass = rb_singleton_class_clone(klass); + } + + clone->super = RCLASS(klass)->super; + clone->iv_tbl = 0; + clone->m_tbl = 0; + if (RCLASS(klass)->iv_tbl) { + clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl); + } + clone->m_tbl = st_init_numtable(); + data.tbl = clone->m_tbl; + data.klass = (VALUE)clone; + data.cref = cref; + st_foreach(RCLASS(klass)->m_tbl, clone_method, (st_data_t)&data); + rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone); + FL_SET(clone, FL_SINGLETON); + return (VALUE)clone; + } +} + /* :nodoc: */ VALUE rb_mod_init_copy(clone, orig) @@ -78,8 +136,7 @@ { rb_obj_init_copy(clone, orig); if (!FL_TEST(CLASS_OF(clone), FL_SINGLETON)) { - RBASIC(clone)->klass = RBASIC(orig)->klass; - RBASIC(clone)->klass = rb_singleton_class_clone(clone); + RBASIC(clone)->klass = singleton_class_clone_int(orig, clone); } RCLASS(clone)->super = RCLASS(orig)->super; if (RCLASS(orig)->iv_tbl) { @@ -94,9 +151,10 @@ if (RCLASS(orig)->m_tbl) { struct clone_method_data data; - data.tbl = RCLASS(clone)->m_tbl = st_init_numtable(); - data.klass = (VALUE)clone; - + RCLASS(clone)->m_tbl = st_init_numtable(); + data.tbl = RCLASS(clone)->m_tbl; + data.klass = clone; + data.cref = clone; st_foreach(RCLASS(orig)->m_tbl, clone_method, (st_data_t)&data); } @@ -121,48 +179,7 @@ rb_singleton_class_clone(obj) VALUE obj; { - VALUE klass = RBASIC(obj)->klass; - - if (!FL_TEST(klass, FL_SINGLETON)) - return klass; - else { - /* copy singleton(unnamed) class */ - NEWOBJ(clone, struct RClass); - OBJSETUP(clone, 0, RBASIC(klass)->flags); - - if (BUILTIN_TYPE(obj) == T_CLASS) { - RBASIC(clone)->klass = (VALUE)clone; - } - else { - RBASIC(clone)->klass = rb_singleton_class_clone(klass); - } - - clone->super = RCLASS(klass)->super; - clone->iv_tbl = 0; - clone->m_tbl = 0; - if (RCLASS(klass)->iv_tbl) { - clone->iv_tbl = st_copy(RCLASS(klass)->iv_tbl); - } - { - struct clone_method_data data; - - data.tbl = clone->m_tbl = st_init_numtable(); - switch (TYPE(obj)) { - case T_CLASS: - case T_MODULE: - data.klass = obj; - break; - default: - data.klass = 0; - break; - } - - st_foreach(RCLASS(klass)->m_tbl, clone_method, (st_data_t)&data); - } - rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone); - FL_SET(clone, FL_SINGLETON); - return (VALUE)clone; - } + return singleton_class_clone_int(obj, 0); } void Index: eval.c =================================================================== --- eval.c (revision 15910) +++ eval.c (working copy) @@ -8358,6 +8358,19 @@ return bind; } +VALUE +rb_block_dup(self, klass, cref) + VALUE self, klass, cref; +{ + struct BLOCK *block; + VALUE obj = proc_dup(self); + Data_Get_Struct(obj, struct BLOCK, block); + block->klass = klass; + block->cref = NEW_NODE(nd_type(block->cref), cref, block->cref->u2.node, + block->cref->u3.node); + return obj; +} + /* * call-seq: * binding -> a_binding @@ -9204,6 +9217,29 @@ return clone; } +VALUE +rb_method_dup(self, klass, cref) + VALUE self; + VALUE klass; + VALUE cref; +{ + VALUE clone; + struct METHOD *orig, *data; + + Data_Get_Struct(self, struct METHOD, orig); + clone = Data_Make_Struct(CLASS_OF(self),struct METHOD, bm_mark, free, data); + *data = *orig; + data->rklass = klass; + if (data->body->nd_rval) { + NODE *tmp = NEW_NODE(nd_type(data->body->u2.node), cref, + data->body->u2.node->u2.node, + data->body->u2.node->u3.node); + data->body = NEW_NODE(nd_type(data->body), data->body->u1.node, tmp, + data->body->u3.node); + } + return clone; +} + /* * call-seq: * meth.call(args, ...) => obj