Method objects are created by
Object#method
, and are associated with a particular object
(not just with a class). They may be used to invoke the method within the
object, and as a block associated with an iterator. They may also be
unbound from one object (creating an UnboundMethod
) and bound
to another.
class Thing def square(n) n*n end end thing = Thing.new meth = thing.method(:square) meth.call(9) #=> 81 [ 1, 2, 3 ].collect(&meth) #=> [1, 4, 9] [ 1, 2, 3 ].each(&method(:puts)) #=> prints 1, 2, 3 require 'date' %w[2017-03-01 2017-03-02].collect(&Date.method(:parse)) #=> [#<Date: 2017-03-01 ((2457814j,0s,0n),+0s,2299161j)>, #<Date: 2017-03-02 ((2457815j,0s,0n),+0s,2299161j)>]
Returns a proc that is the composition of this method and the given g. The returned proc takes a variable number of arguments, calls g with them then calls this method with the result.
def f(x) x * x end f = self.method(:f) g = proc {|x| x + x } p (f << g).call(2) #=> 16
static VALUE rb_method_compose_to_left(VALUE self, VALUE g) { VALUE proc = method_to_proc(self); return proc_compose_to_left(proc, g); }
Two method objects are equal if they are bound to the same object and refer to the same method definition and their owners are the same class or module.
static VALUE method_eq(VALUE method, VALUE other) { struct METHOD *m1, *m2; VALUE klass1, klass2; if (!rb_obj_is_method(other)) return Qfalse; if (CLASS_OF(method) != CLASS_OF(other)) return Qfalse; Check_TypedStruct(method, &method_data_type); m1 = (struct METHOD *)DATA_PTR(method); m2 = (struct METHOD *)DATA_PTR(other); klass1 = method_entry_defined_class(m1->me); klass2 = method_entry_defined_class(m2->me); if (!rb_method_entry_eq(m1->me, m2->me) || klass1 != klass2 || m1->klass != m2->klass || m1->recv != m2->recv) { return Qfalse; } return Qtrue; }
Invokes the method with obj
as the parameter like call. This allows a method object to
be the target of a when
clause in a case statement.
require 'prime' case 1373 when Prime.method(:prime?) # ... end
VALUE rb_method_call(int argc, const VALUE *argv, VALUE method) { VALUE procval = rb_block_given_p() ? rb_block_proc() : Qnil; return rb_method_call_with_block(argc, argv, method, procval); }
Returns a proc that is the composition of this method and the given g. The returned proc takes a variable number of arguments, calls this method with them then calls g with the result.
def f(x) x * x end f = self.method(:f) g = proc {|x| x + x } p (f >> g).call(2) #=> 8
static VALUE rb_method_compose_to_right(VALUE self, VALUE g) { VALUE proc = method_to_proc(self); return proc_compose_to_right(proc, g); }
Invokes the meth with the specified arguments, returning the method's return value, like call.
m = 12.method("+") m[3] #=> 15 m[20] #=> 32
VALUE rb_method_call(int argc, const VALUE *argv, VALUE method) { VALUE procval = rb_block_given_p() ? rb_block_proc() : Qnil; return rb_method_call_with_block(argc, argv, method, procval); }
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. Keyword arguments will be considered as a single additional argument, that argument being mandatory if any keyword argument is mandatory. 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 def seven(a, b, x:0); end def eight(x:, y:); end def nine(x:, y:, **z); end def ten(*a, x:, y:); 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 c.method(:seven).arity #=> -3 c.method(:eight).arity #=> 1 c.method(:nine).arity #=> 1 c.method(:ten).arity #=> -2 "cat".method(:size).arity #=> 0 "cat".method(:replace).arity #=> 1 "cat".method(:squeeze).arity #=> -1 "cat".method(:count).arity #=> -1
static VALUE method_arity_m(VALUE method) { int n = method_arity(method); return INT2FIX(n); }
Invokes the meth with the specified arguments, returning the method's return value.
m = 12.method("+") m.call(3) #=> 15 m.call(20) #=> 32
VALUE rb_method_call(int argc, const VALUE *argv, VALUE method) { VALUE procval = rb_block_given_p() ? rb_block_proc() : Qnil; return rb_method_call_with_block(argc, argv, method, procval); }
Returns a clone of this method.
class A def foo return "bar" end end m = A.new.method(:foo) m.call # => "bar" n = m.clone.call # => "bar"
static VALUE method_clone(VALUE self) { VALUE clone; struct METHOD *orig, *data; TypedData_Get_Struct(self, struct METHOD, &method_data_type, orig); clone = TypedData_Make_Struct(CLASS_OF(self), struct METHOD, &method_data_type, data); CLONESETUP(clone, self); RB_OBJ_WRITE(clone, &data->recv, orig->recv); RB_OBJ_WRITE(clone, &data->klass, orig->klass); RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me)); return clone; }
Returns a curried proc based on the method. When the proc is called with a number of arguments that is lower than the method's arity, then another curried proc is returned. Only when enough arguments have been supplied to satisfy the method signature, will the method actually be called.
The optional arity argument should be supplied when currying methods with variable arguments to determine how many arguments are needed before the method is called.
def foo(a,b,c) [a, b, c] end proc = self.method(:foo).curry proc2 = proc.call(1, 2) #=> #<Proc> proc2.call(3) #=> [1,2,3] def vararg(*args) args end proc = self.method(:vararg).curry(4) proc2 = proc.call(:x) #=> #<Proc> proc3 = proc2.call(:y, :z) #=> #<Proc> proc3.call(:a) #=> [:x, :y, :z, :a]
static VALUE rb_method_curry(int argc, const VALUE *argv, VALUE self) { VALUE proc = method_to_proc(self); return proc_curry(argc, argv, proc); }
Two method objects are equal if they are bound to the same object and refer to the same method definition and their owners are the same class or module.
static VALUE method_eq(VALUE method, VALUE other) { struct METHOD *m1, *m2; VALUE klass1, klass2; if (!rb_obj_is_method(other)) return Qfalse; if (CLASS_OF(method) != CLASS_OF(other)) return Qfalse; Check_TypedStruct(method, &method_data_type); m1 = (struct METHOD *)DATA_PTR(method); m2 = (struct METHOD *)DATA_PTR(other); klass1 = method_entry_defined_class(m1->me); klass2 = method_entry_defined_class(m2->me); if (!rb_method_entry_eq(m1->me, m2->me) || klass1 != klass2 || m1->klass != m2->klass || m1->recv != m2->recv) { return Qfalse; } return Qtrue; }
Returns a hash value corresponding to the method object.
See also Object#hash.
static VALUE method_hash(VALUE method) { struct METHOD *m; st_index_t hash; TypedData_Get_Struct(method, struct METHOD, &method_data_type, m); hash = rb_hash_start((st_index_t)m->recv); hash = rb_hash_method_entry(hash, m->me); hash = rb_hash_end(hash); return ST2FIX(hash); }
Returns a human-readable description of the underlying method.
"cat".method(:count).inspect #=> "#<Method: String#count>" (1..3).method(:map).inspect #=> "#<Method: Range(Enumerable)#map>"
In the latter case, the method description includes the “owner” of the
original method (Enumerable
module, which is included into
Range
).
static VALUE method_inspect(VALUE method) { struct METHOD *data; VALUE str; const char *sharp = "#"; VALUE mklass; VALUE defined_class; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); str = rb_sprintf("#<% "PRIsVALUE": ", rb_obj_class(method)); OBJ_INFECT_RAW(str, method); mklass = data->iclass; if (!mklass) mklass = data->klass; if (data->me->def->type == VM_METHOD_TYPE_ALIAS) { defined_class = data->me->def->body.alias.original_me->owner; } else { defined_class = method_entry_defined_class(data->me); } if (RB_TYPE_P(defined_class, T_ICLASS)) { defined_class = RBASIC_CLASS(defined_class); } if (FL_TEST(mklass, FL_SINGLETON)) { VALUE v = rb_ivar_get(mklass, attached); if (data->recv == Qundef) { rb_str_buf_append(str, rb_inspect(mklass)); } 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 { mklass = data->klass; if (FL_TEST(mklass, FL_SINGLETON)) { do { mklass = RCLASS_SUPER(mklass); } while (RB_TYPE_P(mklass, T_ICLASS)); } rb_str_buf_append(str, rb_inspect(mklass)); if (defined_class != mklass) { rb_str_catf(str, "(% "PRIsVALUE")", defined_class); } } rb_str_buf_cat2(str, sharp); rb_str_append(str, rb_id2str(data->me->called_id)); if (data->me->called_id != data->me->def->original_id) { rb_str_catf(str, "(%"PRIsVALUE")", rb_id2str(data->me->def->original_id)); } if (data->me->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) { rb_str_buf_cat2(str, " (not-implemented)"); } rb_str_buf_cat2(str, ">"); return str; }
Returns the name of the method.
static VALUE method_name(VALUE obj) { struct METHOD *data; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data); return ID2SYM(data->me->called_id); }
Returns the original name of the method.
class C def foo; end alias bar foo end C.instance_method(:bar).original_name # => :foo
static VALUE method_original_name(VALUE obj) { struct METHOD *data; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data); return ID2SYM(data->me->def->original_id); }
Returns the class or module that defines the method. See also receiver.
(1..3).method(:map).owner #=> Enumerable
static VALUE method_owner(VALUE obj) { struct METHOD *data; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data); return data->me->owner; }
Returns the parameter information of this method.
def foo(bar); end method(:foo).parameters #=> [[:req, :bar]] def foo(bar, baz, bat, &blk); end method(:foo).parameters #=> [[:req, :bar], [:req, :baz], [:req, :bat], [:block, :blk]] def foo(bar, *args); end method(:foo).parameters #=> [[:req, :bar], [:rest, :args]] def foo(bar, baz, *args, &blk); end method(:foo).parameters #=> [[:req, :bar], [:req, :baz], [:rest, :args], [:block, :blk]]
static VALUE rb_method_parameters(VALUE method) { const rb_iseq_t *iseq = rb_method_iseq(method); if (!iseq) { return rb_unnamed_parameters(method_arity(method)); } return rb_iseq_parameters(iseq, 0); }
Returns the bound receiver of the method object.
(1..3).method(:map).receiver # => 1..3
static VALUE method_receiver(VALUE obj) { struct METHOD *data; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data); return data->recv; }
Returns the Ruby source filename and line number containing this method or nil if this method was not defined in Ruby (i.e. native).
VALUE rb_method_location(VALUE method) { return method_def_location(rb_method_def(method)); }
Returns a Method of superclass which would be called when super is used or nil if there is no method on superclass.
static VALUE method_super_method(VALUE method) { const struct METHOD *data; VALUE super_class, iclass; ID mid; const rb_method_entry_t *me; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); iclass = data->iclass; if (!iclass) return Qnil; if (data->me->def->type == VM_METHOD_TYPE_ALIAS && data->me->defined_class) { super_class = RCLASS_SUPER(rb_find_defined_class_by_owner(data->me->defined_class, data->me->def->body.alias.original_me->owner)); mid = data->me->def->body.alias.original_me->def->original_id; } else { super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass)); mid = data->me->def->original_id; } if (!super_class) return Qnil; me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(super_class, mid, &iclass); if (!me) return Qnil; return mnew_internal(me, me->owner, iclass, data->recv, mid, rb_obj_class(method), FALSE, FALSE); }
Returns a Proc
object corresponding to this method.
static VALUE method_to_proc(VALUE method) { VALUE procval; rb_proc_t *proc; /* * class Method * def to_proc * lambda{|*args| * self.call(*args) * } * end * end */ procval = rb_iterate(mlambda, 0, bmcall, method); GetProcPtr(procval, proc); proc->is_from_method = 1; return procval; }
Returns a human-readable description of the underlying method.
"cat".method(:count).inspect #=> "#<Method: String#count>" (1..3).method(:map).inspect #=> "#<Method: Range(Enumerable)#map>"
In the latter case, the method description includes the “owner” of the
original method (Enumerable
module, which is included into
Range
).
static VALUE method_inspect(VALUE method) { struct METHOD *data; VALUE str; const char *sharp = "#"; VALUE mklass; VALUE defined_class; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data); str = rb_sprintf("#<% "PRIsVALUE": ", rb_obj_class(method)); OBJ_INFECT_RAW(str, method); mklass = data->iclass; if (!mklass) mklass = data->klass; if (data->me->def->type == VM_METHOD_TYPE_ALIAS) { defined_class = data->me->def->body.alias.original_me->owner; } else { defined_class = method_entry_defined_class(data->me); } if (RB_TYPE_P(defined_class, T_ICLASS)) { defined_class = RBASIC_CLASS(defined_class); } if (FL_TEST(mklass, FL_SINGLETON)) { VALUE v = rb_ivar_get(mklass, attached); if (data->recv == Qundef) { rb_str_buf_append(str, rb_inspect(mklass)); } 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 { mklass = data->klass; if (FL_TEST(mklass, FL_SINGLETON)) { do { mklass = RCLASS_SUPER(mklass); } while (RB_TYPE_P(mklass, T_ICLASS)); } rb_str_buf_append(str, rb_inspect(mklass)); if (defined_class != mklass) { rb_str_catf(str, "(% "PRIsVALUE")", defined_class); } } rb_str_buf_cat2(str, sharp); rb_str_append(str, rb_id2str(data->me->called_id)); if (data->me->called_id != data->me->def->original_id) { rb_str_catf(str, "(%"PRIsVALUE")", rb_id2str(data->me->def->original_id)); } if (data->me->def->type == VM_METHOD_TYPE_NOTIMPLEMENTED) { rb_str_buf_cat2(str, " (not-implemented)"); } rb_str_buf_cat2(str, ">"); return str; }
Dissociates meth from its current receiver. The resulting
UnboundMethod
can subsequently be bound to a new object of the
same class (see UnboundMethod
).
static VALUE method_unbind(VALUE obj) { VALUE method; struct METHOD *orig, *data; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, orig); method = TypedData_Make_Struct(rb_cUnboundMethod, struct METHOD, &method_data_type, data); RB_OBJ_WRITE(method, &data->recv, Qundef); RB_OBJ_WRITE(method, &data->klass, orig->klass); RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me)); OBJ_INFECT(method, obj); return method; }