/*
* 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)");
}
noex = NOEX_PUBLIC;
if (ruby_cbase == mod) {
if (SCOPE_TEST(SCOPE_PRIVATE)) {
noex = NOEX_PRIVATE;
}
else if (SCOPE_TEST(SCOPE_PROTECTED)) {
noex = NOEX_PROTECTED;
}
}
rb_add_method(mod, id, node, noex);
return body;
}