/* * call-seq: * define_method(symbol, method) => new_method * define_method(symbol) { block } => proc * * Defines an instance method in the receiver. The _method_ * parameter can be a +Proc+ or +Method+ object. * If a block is specified, it is used as the method body. This block * is evaluated using <code>instance_eval</code>, a point that is * tricky to demonstrate because <code>define_method</code> is private. * (This is why we resort to the +send+ hack in this example.) * * class A * def fred * puts "In Fred" * end * def create_method(name, &block) * self.class.send(:define_method, name, &block) * end * define_method(:wilma) { puts "Charge it!" } * end * class B < A * define_method(:barney, instance_method(:fred)) * end * a = B.new * a.barney * a.wilma * a.create_method(:betty) { p self } * a.betty * * <em>produces:</em> * * In Fred * Charge it! * #<B:0x401b39e8> */ static VALUE rb_mod_define_method(argc, argv, mod) int argc; VALUE *argv; VALUE mod; { ID id; VALUE body; NODE *node; int noex; if (argc == 1) { id = rb_to_id(argv[0]); body = proc_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) { node = NEW_DMETHOD(method_unbind(body)); } else if (RDATA(body)->dmark == (RUBY_DATA_FUNC)blk_mark) { struct BLOCK *block; body = proc_clone(body); Data_Get_Struct(body, struct BLOCK, block); block->frame.last_func = id; block->frame.orig_func = id; block->frame.last_class = mod; node = NEW_BMETHOD(body); } else { /* type error */ rb_raise(rb_eTypeError, "wrong argument type (expected Proc/Method)"); } if (SCOPE_TEST(SCOPE_PRIVATE)) { noex = NOEX_PRIVATE; } else if (SCOPE_TEST(SCOPE_PROTECTED)) { noex = NOEX_PROTECTED; } else { noex = NOEX_PUBLIC; } rb_add_method(mod, id, node, noex); rb_define_method(rb_cBinding, "dup", proc_dup, 0); return body; }