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