public Method

Module.define_method(...)

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></b:0x401b39e8>

Source Code

/*
*  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;
}
Comments

Have your say
Please use Textile formatting (click here for a cheat sheet). Use <code/> and <pre/> for code samples.
Click here to login with OpenID to to post comments.