static int clone_method(ID mid, NODE *body, VALUE nklass) { NODE *fbody = body->nd_body; if (fbody) { VALUE nbody; switch (nd_type(fbody)) { case NODE_SCOPE: fbody = rb_copy_node_scope(fbody, ruby_cref); break; case NODE_BMETHOD: nbody = rb_block_dup(fbody->nd_cval, nklass, (VALUE)ruby_cref); fbody = NEW_BMETHOD(nbody); break; case NODE_DMETHOD: nbody = rb_method_dup(fbody->nd_cval, nklass, (VALUE)ruby_cref); fbody = NEW_DMETHOD(nbody); break; } } st_insert(RCLASS(nklass)->m_tbl, mid, (st_data_t)NEW_METHOD(fbody, body->nd_noex)); return ST_CONTINUE; }
static VALUE rb_mod_define_method(int argc, VALUE *argv, VALUE mod) { ID id; VALUE body; NODE *node; int noex = NOEX_PUBLIC; if (argc == 1) { id = rb_to_id(argv[0]); body = rb_block_lambda(); } else if (argc == 2) { id = rb_to_id(argv[0]); body = argv[1]; if (!rb_obj_is_method(body) && !rb_obj_is_proc(body)) { rb_raise(rb_eTypeError, "wrong argument type %s (expected Proc/Method)", rb_obj_classname(body)); } } else { rb_raise(rb_eArgError, "wrong number of arguments (%d for 1)", argc); } if (RDATA(body)->dmark == (RUBY_DATA_FUNC) bm_mark) { struct METHOD *method = (struct METHOD *)DATA_PTR(body); VALUE rklass = method->rklass; if (rklass != mod) { if (FL_TEST(rklass, FL_SINGLETON)) { rb_raise(rb_eTypeError, "can't bind singleton method to a different class"); } if (!RTEST(rb_class_inherited_p(mod, rklass))) { rb_raise(rb_eTypeError, "bind argument must be a subclass of %s", rb_class2name(rklass)); } } node = method->body; } else if (rb_obj_is_proc(body)) { rb_proc_t *proc; body = proc_dup(body); GetProcPtr(body, proc); if (BUILTIN_TYPE(proc->block.iseq) != T_NODE) { proc->block.iseq->defined_method_id = id; proc->block.iseq->klass = mod; proc->is_lambda = Qtrue; } node = NEW_BMETHOD(body); } else { /* type error */ rb_raise(rb_eTypeError, "wrong argument type (expected Proc/Method)"); } /* TODO: visibility */ rb_add_method(mod, id, node, noex); return body; }