Class Method
In: eval.c
Parent: Object

Proc objects are blocks of code that have been bound to a set of local variables. Once bound, the code may be called in different contexts and still access those variables.

   def gen_times(factor)
     return Proc.new {|n| n*factor }
   end

   times3 = gen_times(3)
   times5 = gen_times(5)

   times3.call(12)               #=> 36
   times5.call(5)                #=> 25
   times3.call(times5.call(4))   #=> 60

Methods

==   []   arity   call   clone   inspect   name   owner   receiver   to_proc   to_s   unbind  

Public Instance methods

Two method objects are equal if that are bound to the same object and contain the same body.

[Source]

/*
 * call-seq:
 *   meth == other_meth  => true or false
 *
 * Two method objects are equal if that are bound to the same
 * object and contain the same body.
 */


static VALUE
method_eq(method, other)
    VALUE method, other;
{
    struct METHOD *m1, *m2;

    if (TYPE(other) != T_DATA || RDATA(other)->dmark != (RUBY_DATA_FUNC)bm_mark)
        return Qfalse;
    if (CLASS_OF(method) != CLASS_OF(other))
        return Qfalse;

    Data_Get_Struct(method, struct METHOD, m1);
    Data_Get_Struct(other, struct METHOD, m2);

    if (m1->klass != m2->klass || m1->rklass != m2->rklass ||
        m1->recv != m2->recv || m1->body != m2->body)
        return Qfalse;

    return Qtrue;
}

Invokes the meth with the specified arguments, returning the method‘s return value.

   m = 12.method("+")
   m.call(3)    #=> 15
   m.call(20)   #=> 32

[Source]

/*
 *  call-seq:
 *     meth.call(args, ...)    => obj
 *     meth[args, ...]         => obj
 *  
 *  Invokes the <i>meth</i> with the specified arguments, returning the
 *  method's return value.
 *     
 *     m = 12.method("+")
 *     m.call(3)    #=> 15
 *     m.call(20)   #=> 32
 */

static VALUE
method_call(argc, argv, method)
    int argc;
    VALUE *argv;
    VALUE method;
{
    VALUE result = Qnil;        /* OK */
    struct METHOD *data;
    int safe;

    Data_Get_Struct(method, struct METHOD, data);
    if (data->recv == Qundef) {
        rb_raise(rb_eTypeError, "can't call unbound method; bind first");
    }
    if (OBJ_TAINTED(method)) {
        safe = NOEX_WITH(data->safe_level, 4)|NOEX_TAINTED;
    }
    else {
        safe = data->safe_level;
    }
    PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT);
    result = rb_call0(data->klass,data->recv,data->id,data->oid,argc,argv,data->body,safe);
    POP_ITER();
    return result;
}

Returns an indication of the number of arguments accepted by a method. Returns a nonnegative integer for methods that take a fixed number of arguments. For Ruby methods that take a variable number of arguments, returns -n-1, where n is the number of required arguments. For methods written in C, returns -1 if the call takes a variable number of arguments.

   class C
     def one;    end
     def two(a); end
     def three(*a);  end
     def four(a, b); end
     def five(a, b, *c);    end
     def six(a, b, *c, &d); end
   end
   c = C.new
   c.method(:one).arity     #=> 0
   c.method(:two).arity     #=> 1
   c.method(:three).arity   #=> -1
   c.method(:four).arity    #=> 2
   c.method(:five).arity    #=> -3
   c.method(:six).arity     #=> -3

   "cat".method(:size).arity      #=> 0
   "cat".method(:replace).arity   #=> 1
   "cat".method(:squeeze).arity   #=> -1
   "cat".method(:count).arity     #=> -1

[Source]

/*
 *  call-seq:
 *     meth.arity    => fixnum
 *  
 *  Returns an indication of the number of arguments accepted by a
 *  method. Returns a nonnegative integer for methods that take a fixed
 *  number of arguments. For Ruby methods that take a variable number of
 *  arguments, returns -n-1, where n is the number of required
 *  arguments. For methods written in C, returns -1 if the call takes a
 *  variable number of arguments.
 *     
 *     class C
 *       def one;    end
 *       def two(a); end
 *       def three(*a);  end
 *       def four(a, b); end
 *       def five(a, b, *c);    end
 *       def six(a, b, *c, &d); end
 *     end
 *     c = C.new
 *     c.method(:one).arity     #=> 0
 *     c.method(:two).arity     #=> 1
 *     c.method(:three).arity   #=> -1
 *     c.method(:four).arity    #=> 2
 *     c.method(:five).arity    #=> -3
 *     c.method(:six).arity     #=> -3
 *     
 *     "cat".method(:size).arity      #=> 0
 *     "cat".method(:replace).arity   #=> 1
 *     "cat".method(:squeeze).arity   #=> -1
 *     "cat".method(:count).arity     #=> -1
 */

static VALUE
method_arity(method)
    VALUE method;
{
    struct METHOD *data;
    NODE *body;
    int n;

    Data_Get_Struct(method, struct METHOD, data);

    body = data->body;
    switch (nd_type(body)) {
      case NODE_CFUNC:
        if (body->nd_argc < 0) return INT2FIX(-1);
        return INT2FIX(body->nd_argc);
      case NODE_ZSUPER:
        return INT2FIX(-1);
      case NODE_ATTRSET:
        return INT2FIX(1);
      case NODE_IVAR:
        return INT2FIX(0);
      case NODE_BMETHOD:
        return proc_arity(body->nd_cval);
      case NODE_DMETHOD:
        return method_arity(body->nd_cval);
      case NODE_SCOPE:
        body = body->nd_next;  /* skip NODE_SCOPE */
        if (nd_type(body) == NODE_BLOCK)
            body = body->nd_head;
        if (!body) return INT2FIX(0);
        n = body->nd_cnt;
        if (body->nd_opt || body->nd_rest)
            n = -n-1;
        return INT2FIX(n);
      default:
        rb_raise(rb_eArgError, "invalid node 0x%x", nd_type(body));
   }
}

Invokes the meth with the specified arguments, returning the method‘s return value.

   m = 12.method("+")
   m.call(3)    #=> 15
   m.call(20)   #=> 32

[Source]

/*
 *  call-seq:
 *     meth.call(args, ...)    => obj
 *     meth[args, ...]         => obj
 *  
 *  Invokes the <i>meth</i> with the specified arguments, returning the
 *  method's return value.
 *     
 *     m = 12.method("+")
 *     m.call(3)    #=> 15
 *     m.call(20)   #=> 32
 */

static VALUE
method_call(argc, argv, method)
    int argc;
    VALUE *argv;
    VALUE method;
{
    VALUE result = Qnil;        /* OK */
    struct METHOD *data;
    int safe;

    Data_Get_Struct(method, struct METHOD, data);
    if (data->recv == Qundef) {
        rb_raise(rb_eTypeError, "can't call unbound method; bind first");
    }
    if (OBJ_TAINTED(method)) {
        safe = NOEX_WITH(data->safe_level, 4)|NOEX_TAINTED;
    }
    else {
        safe = data->safe_level;
    }
    PUSH_ITER(rb_block_given_p()?ITER_PRE:ITER_NOT);
    result = rb_call0(data->klass,data->recv,data->id,data->oid,argc,argv,data->body,safe);
    POP_ITER();
    return result;
}

MISSING: documentation

[Source]

/*
 * MISSING: documentation
 */

static VALUE
method_clone(self)
    VALUE self;
{
    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);
    CLONESETUP(clone, self);
    *data = *orig;

    return clone;
}

Show the name of the underlying method.

  "cat".method(:count).inspect   #=> "#<Method: String#count>"

[Source]

/*
 *  call-seq:
 *   meth.to_s      =>  string
 *   meth.inspect   =>  string
 *
 *  Show the name of the underlying method.
 *
 *    "cat".method(:count).inspect   #=> "#<Method: String#count>"
 */

static VALUE
method_inspect(method)
    VALUE method;
{
    struct METHOD *data;
    VALUE str;
    const char *s;
    const char *sharp = "#";

    Data_Get_Struct(method, struct METHOD, data);
    str = rb_str_buf_new2("#<");
    s = rb_obj_classname(method);
    rb_str_buf_cat2(str, s);
    rb_str_buf_cat2(str, ": ");

    if (FL_TEST(data->klass, FL_SINGLETON)) {
        VALUE v = rb_iv_get(data->klass, "__attached__");

        if (data->recv == Qundef) {
            rb_str_buf_append(str, rb_inspect(data->klass));
        }
        else if (data->recv == v) {
            rb_str_buf_append(str, rb_inspect(v));
            sharp = ".";
        }
        else {
            rb_str_buf_append(str, rb_inspect(data->recv));
            rb_str_buf_cat2(str, "(");
            rb_str_buf_append(str, rb_inspect(v));
            rb_str_buf_cat2(str, ")");
            sharp = ".";
        }
    }
    else {
        rb_str_buf_cat2(str, rb_class2name(data->rklass));
        if (data->rklass != data->klass) {
            rb_str_buf_cat2(str, "(");
            rb_str_buf_cat2(str, rb_class2name(data->klass));
            rb_str_buf_cat2(str, ")");
        }
    }
    rb_str_buf_cat2(str, sharp);
    rb_str_buf_cat2(str, rb_id2name(data->oid));
    rb_str_buf_cat2(str, ">");

    return str;
}

Returns the name of the method.

[Source]

/*
 *  call-seq:
 *     meth.name    => string
 *
 *  Returns the name of the method.
 */

static VALUE
method_name(obj)
    VALUE obj;
{
    struct METHOD *data;

    Data_Get_Struct(obj, struct METHOD, data);
    return rb_str_new2(rb_id2name(data->oid));
}

Returns the class or module that defines the method.

[Source]

/*
 *  call-seq:
 *     meth.owner    => class_or_module
 *
 *  Returns the class or module that defines the method.
 */

static VALUE
method_owner(obj)
    VALUE obj;
{
    struct METHOD *data;

    Data_Get_Struct(obj, struct METHOD, data);
    return data->klass;
}

Returns the bound receiver of the method object.

[Source]

/*
 *  call-seq:
 *     meth.receiver    => object
 *
 *  Returns the bound receiver of the method object.
 */

static VALUE
method_receiver(obj)
    VALUE obj;
{
    struct METHOD *data;

    Data_Get_Struct(obj, struct METHOD, data);
    return data->recv;
}

Returns a Proc object corresponding to this method.

[Source]

/*
 *  call-seq:
 *     meth.to_proc    => prc
 *  
 *  Returns a <code>Proc</code> object corresponding to this method.
 */

static VALUE
method_proc(method)
    VALUE method;
{
    VALUE proc;
    struct METHOD *mdata;
    struct BLOCK *bdata;

    proc = rb_iterate((VALUE(*)_((VALUE)))mproc, 0, bmcall, method);
    Data_Get_Struct(method, struct METHOD, mdata);
    Data_Get_Struct(proc, struct BLOCK, bdata);
    bdata->body->nd_file = mdata->body->nd_file;
    nd_set_line(bdata->body, nd_line(mdata->body));
    bdata->body->nd_state = YIELD_FUNC_SVALUE;

    return proc;
}

Show the name of the underlying method.

  "cat".method(:count).inspect   #=> "#<Method: String#count>"

[Source]

/*
 *  call-seq:
 *   meth.to_s      =>  string
 *   meth.inspect   =>  string
 *
 *  Show the name of the underlying method.
 *
 *    "cat".method(:count).inspect   #=> "#<Method: String#count>"
 */

static VALUE
method_inspect(method)
    VALUE method;
{
    struct METHOD *data;
    VALUE str;
    const char *s;
    const char *sharp = "#";

    Data_Get_Struct(method, struct METHOD, data);
    str = rb_str_buf_new2("#<");
    s = rb_obj_classname(method);
    rb_str_buf_cat2(str, s);
    rb_str_buf_cat2(str, ": ");

    if (FL_TEST(data->klass, FL_SINGLETON)) {
        VALUE v = rb_iv_get(data->klass, "__attached__");

        if (data->recv == Qundef) {
            rb_str_buf_append(str, rb_inspect(data->klass));
        }
        else if (data->recv == v) {
            rb_str_buf_append(str, rb_inspect(v));
            sharp = ".";
        }
        else {
            rb_str_buf_append(str, rb_inspect(data->recv));
            rb_str_buf_cat2(str, "(");
            rb_str_buf_append(str, rb_inspect(v));
            rb_str_buf_cat2(str, ")");
            sharp = ".";
        }
    }
    else {
        rb_str_buf_cat2(str, rb_class2name(data->rklass));
        if (data->rklass != data->klass) {
            rb_str_buf_cat2(str, "(");
            rb_str_buf_cat2(str, rb_class2name(data->klass));
            rb_str_buf_cat2(str, ")");
        }
    }
    rb_str_buf_cat2(str, sharp);
    rb_str_buf_cat2(str, rb_id2name(data->oid));
    rb_str_buf_cat2(str, ">");

    return str;
}

Dissociates meth from it‘s current receiver. The resulting UnboundMethod can subsequently be bound to a new object of the same class (see UnboundMethod).

[Source]

/*
 *  call-seq:
 *     meth.unbind    => unbound_method
 *  
 *  Dissociates <i>meth</i> from it's current receiver. The resulting
 *  <code>UnboundMethod</code> can subsequently be bound to a new object
 *  of the same class (see <code>UnboundMethod</code>).
 */

static VALUE
method_unbind(obj)
    VALUE obj;
{
    VALUE method;
    struct METHOD *orig, *data;

    Data_Get_Struct(obj, struct METHOD, orig);
    method = Data_Make_Struct(rb_cUnboundMethod, struct METHOD, bm_mark, free, data);
    data->klass = orig->klass;
    data->recv = Qundef;
    data->id = orig->id;
    data->body = orig->body;
    data->rklass = orig->rklass;
    data->oid = orig->oid;
    OBJ_INFECT(method, obj);

    return method;
}

[Validate]