class Method
Method objects are created byObject#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 anUnboundMethod) and bound to another.
classThingdefsquare(n)n*nendendthing =Thing.newmeth =thing.method(:square)meth.call(9)#=> 81[1,2,3 ].collect(&meth)#=> [1, 4, 9][1,2,3 ].each(&method(:puts))#=> prints 1, 2, 3require'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)>]
Public Instance Methods
Source
static VALUErb_method_compose_to_left(VALUE self, VALUE g){ g = to_callable(g); self = method_to_proc(self); return proc_compose_to_left(self, g);}Returns a proc that is the composition of this method and the giveng. The returned proc takes a variable number of arguments, callsg with them then calls this method with the result.
deff(x)x*xendf =self.method(:f)g =proc {|x|x+x }p (f<<g).call(2)#=> 16
Source
static VALUEmethod_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 *)RTYPEDDATA_GET_DATA(method); m2 = (struct METHOD *)RTYPEDDATA_GET_DATA(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;}Two method objects are equal if they are bound to the same object and refer to the same method definition and the classes defining the methods are the same class or module.
Source
static VALUErb_method_compose_to_right(VALUE self, VALUE g){ g = to_callable(g); self = method_to_proc(self); return proc_compose_to_right(self, g);}Returns a proc that is the composition of this method and the giveng. The returned proc takes a variable number of arguments, calls this method with them then callsg with the result.
deff(x)x*xendf =self.method(:f)g =proc {|x|x+x }p (f>>g).call(2)#=> 8
Source
static VALUEmethod_arity_m(VALUE method){ int n = method_arity(method); return INT2FIX(n);}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.
classCdefone;enddeftwo(a);enddefthree(*a);enddeffour(a,b);enddeffive(a,b,*c);enddefsix(a,b,*c,&d);enddefseven(a,b,x:0);enddefeight(x:,y:);enddefnine(x:,y:,**z);enddeften(*a,x:,y:);endendc =C.newc.method(:one).arity#=> 0c.method(:two).arity#=> 1c.method(:three).arity#=> -1c.method(:four).arity#=> 2c.method(:five).arity#=> -3c.method(:six).arity#=> -3c.method(:seven).arity#=> -3c.method(:eight).arity#=> 1c.method(:nine).arity#=> 1c.method(:ten).arity#=> -2"cat".method(:size).arity#=> 0"cat".method(:replace).arity#=> 1"cat".method(:squeeze).arity#=> -1"cat".method(:count).arity#=> -1
Source
static VALUErb_method_call_pass_called_kw(int argc, const VALUE *argv, VALUE method){ return rb_method_call_kw(argc, argv, method, RB_PASS_CALLED_KEYWORDS);}Invokes themeth with the specified arguments, returning the method’s return value.
m =12.method("+")m.call(3)#=> 15m.call(20)#=> 32
Source
static VALUEmethod_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); rb_obj_clone_setup(self, clone, Qnil); RB_OBJ_WRITE(clone, &data->recv, orig->recv); RB_OBJ_WRITE(clone, &data->klass, orig->klass); RB_OBJ_WRITE(clone, &data->iclass, orig->iclass); RB_OBJ_WRITE(clone, &data->owner, orig->owner); RB_OBJ_WRITE(clone, &data->me, rb_method_entry_clone(orig->me)); return clone;}Returns a clone of this method.
classAdeffooreturn"bar"endendm =A.new.method(:foo)m.call# => "bar"n =m.clone.call# => "bar"
Source
static VALUErb_method_curry(int argc, const VALUE *argv, VALUE self){ VALUE proc = method_to_proc(self); return proc_curry(argc, argv, proc);}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 optionalarity argument should be supplied when currying methods with variable arguments to determine how many arguments are needed before the method is called.
deffoo(a,b,c) [a,b,c]endproc =self.method(:foo).curryproc2 =proc.call(1,2)#=> #<Proc>proc2.call(3)#=> [1,2,3]defvararg(*args)argsendproc =self.method(:vararg).curry(4)proc2 =proc.call(:x)#=> #<Proc>proc3 =proc2.call(:y,:z)#=> #<Proc>proc3.call(:a)#=> [:x, :y, :z, :a]
Two method objects are equal if they are bound to the same object and refer to the same method definition and the classes defining the methods are the same class or module.
Source
static VALUEmethod_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 hash value corresponding to the method object.
See alsoObject#hash.
Source
static VALUEmethod_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)); mklass = data->iclass; if (!mklass) mklass = data->klass; if (RB_TYPE_P(mklass, T_ICLASS)) { /* TODO: I'm not sure why mklass is T_ICLASS. * UnboundMethod#bind() can set it as T_ICLASS at convert_umethod_to_method_components() * but not sure it is needed. */ mklass = RBASIC_CLASS(mklass); } 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 (UNDEF_P(data->recv)) { // UnboundMethod rb_str_buf_append(str, rb_inspect(defined_class)); } else if (RCLASS_SINGLETON_P(mklass)) { VALUE v = RCLASS_ATTACHED_OBJECT(mklass); if (UNDEF_P(data->recv)) { 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 (RCLASS_SINGLETON_P(mklass)) { VALUE v = RCLASS_ATTACHED_OBJECT(mklass); if (!(RB_TYPE_P(v, T_CLASS) || RB_TYPE_P(v, T_MODULE))) { 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)"); } // parameter information { VALUE params = rb_method_parameters(method); VALUE pair, name, kind; const VALUE req = ID2SYM(rb_intern("req")); const VALUE opt = ID2SYM(rb_intern("opt")); const VALUE keyreq = ID2SYM(rb_intern("keyreq")); const VALUE key = ID2SYM(rb_intern("key")); const VALUE rest = ID2SYM(rb_intern("rest")); const VALUE keyrest = ID2SYM(rb_intern("keyrest")); const VALUE block = ID2SYM(rb_intern("block")); const VALUE nokey = ID2SYM(rb_intern("nokey")); int forwarding = 0; rb_str_buf_cat2(str, "("); if (RARRAY_LEN(params) == 3 && RARRAY_AREF(RARRAY_AREF(params, 0), 0) == rest && RARRAY_AREF(RARRAY_AREF(params, 0), 1) == ID2SYM('*') && RARRAY_AREF(RARRAY_AREF(params, 1), 0) == keyrest && RARRAY_AREF(RARRAY_AREF(params, 1), 1) == ID2SYM(idPow) && RARRAY_AREF(RARRAY_AREF(params, 2), 0) == block && RARRAY_AREF(RARRAY_AREF(params, 2), 1) == ID2SYM('&')) { forwarding = 1; } for (int i = 0; i < RARRAY_LEN(params); i++) { pair = RARRAY_AREF(params, i); kind = RARRAY_AREF(pair, 0); if (RARRAY_LEN(pair) > 1) { name = RARRAY_AREF(pair, 1); } else { // FIXME: can it be reduced to switch/case? if (kind == req || kind == opt) { name = rb_str_new2("_"); } else if (kind == rest || kind == keyrest) { name = rb_str_new2(""); } else if (kind == block) { name = rb_str_new2("block"); } else if (kind == nokey) { name = rb_str_new2("nil"); } else { name = Qnil; } } if (kind == req) { rb_str_catf(str, "%"PRIsVALUE, name); } else if (kind == opt) { rb_str_catf(str, "%"PRIsVALUE"=...", name); } else if (kind == keyreq) { rb_str_catf(str, "%"PRIsVALUE":", name); } else if (kind == key) { rb_str_catf(str, "%"PRIsVALUE": ...", name); } else if (kind == rest) { if (name == ID2SYM('*')) { rb_str_cat_cstr(str, forwarding ? "..." : "*"); } else { rb_str_catf(str, "*%"PRIsVALUE, name); } } else if (kind == keyrest) { if (name != ID2SYM(idPow)) { rb_str_catf(str, "**%"PRIsVALUE, name); } else if (i > 0) { rb_str_set_len(str, RSTRING_LEN(str) - 2); } else { rb_str_cat_cstr(str, "**"); } } else if (kind == block) { if (name == ID2SYM('&')) { if (forwarding) { rb_str_set_len(str, RSTRING_LEN(str) - 2); } else { rb_str_cat_cstr(str, "..."); } } else { rb_str_catf(str, "&%"PRIsVALUE, name); } } else if (kind == nokey) { rb_str_buf_cat2(str, "**nil"); } if (i < RARRAY_LEN(params) - 1) { rb_str_buf_cat2(str, ", "); } } rb_str_buf_cat2(str, ")"); } { // source location VALUE loc = rb_method_location(method); if (!NIL_P(loc)) { rb_str_catf(str, " %"PRIsVALUE":%"PRIsVALUE, RARRAY_AREF(loc, 0), RARRAY_AREF(loc, 1)); } } rb_str_buf_cat2(str, ">"); return str;}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 intoRange).
inspect also provides, when possible, method argument names (call sequence) and source location.
require'net/http'Net::HTTP.method(:get).inspect#=> "#<Method: Net::HTTP.get(uri_or_host, path=..., port=...) <skip>/lib/ruby/2.7.0/net/http.rb:457>"
... in argument definition means argument is optional (has some default value).
For methods defined in C (language core and extensions), location and argument names can’t be extracted, and only generic information is provided in form of* (any number of arguments) or_ (some positional argument).
"cat".method(:count).inspect#=> "#<Method: String#count(*)>""cat".method(:+).inspect#=> "#<Method: String#+(_)>""
Source
static VALUEmethod_name(VALUE obj){ struct METHOD *data; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data); return ID2SYM(data->me->called_id);}Returns the name of the method.
Source
static VALUEmethod_namespace(VALUE obj){ struct METHOD *data; const rb_namespace_t *ns; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data); ns = data->me->def->ns; if (!ns) return Qfalse; if (ns->ns_object) return ns->ns_object; // This should not happen rb_bug("Unexpected namespace on the method definition: %p", (void*) ns); return Qtrue;}call-see:
meth.namespace -> namespace or nil
Returns the namespace wheremeth is defined in.
Source
static VALUEmethod_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 original name of the method.
classCdeffoo;endaliasbarfooendC.instance_method(:bar).original_name# => :foo
Source
static VALUEmethod_owner(VALUE obj){ struct METHOD *data; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data); return data->owner;}Returns the class or module on which this method is defined. In other words,
meth.owner.instance_methods(false).include?(meth.name)# => true
holds as long as the method is not removed/undefined/replaced, (with private_instance_methods instead of instance_methods if the method is private).
See alsoMethod#receiver.
(1..3).method(:map).owner#=> Enumerable
Source
static VALUErb_method_parameters(VALUE method){ return method_def_parameters(rb_method_def(method));}Returns the parameter information of this method.
deffoo(bar);endmethod(:foo).parameters#=> [[:req, :bar]]deffoo(bar,baz,bat,&blk);endmethod(:foo).parameters#=> [[:req, :bar], [:req, :baz], [:req, :bat], [:block, :blk]]deffoo(bar,*args);endmethod(:foo).parameters#=> [[:req, :bar], [:rest, :args]]deffoo(bar,baz,*args,&blk);endmethod(:foo).parameters#=> [[:req, :bar], [:req, :baz], [:rest, :args], [:block, :blk]]
Source
static VALUEmethod_receiver(VALUE obj){ struct METHOD *data; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data); return data->recv;}Returns the bound receiver of the method object.
(1..3).method(:map).receiver# => 1..3
Source
VALUErb_method_location(VALUE method){ return method_def_location(rb_method_def(method));}Returns the location where the method was defined. The returnedArray contains:
(1) the Ruby source filename(2) the line number where the definition starts(3) the column number where the definition starts(4) the line number where the definition ends(5) the column number where the definitions ends
This method will returnnil if the method was not defined in Ruby (i.e. native).
Source
static VALUEmethod_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_with_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 aMethod of superclass which would be called when super is used or nil if there is no method on superclass.
Source
static VALUEmethod_to_proc(VALUE method){ VALUE procval; rb_proc_t *proc; /* * class Method * def to_proc * lambda{|*args| * self.call(*args) * } * end * end */ procval = rb_block_call(rb_mRubyVMFrozenCore, idLambda, 0, 0, bmcall, method); GetProcPtr(procval, proc); proc->is_from_method = 1; return procval;}Returns aProc object corresponding to this method.
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 intoRange).
inspect also provides, when possible, method argument names (call sequence) and source location.
require'net/http'Net::HTTP.method(:get).inspect#=> "#<Method: Net::HTTP.get(uri_or_host, path=..., port=...) <skip>/lib/ruby/2.7.0/net/http.rb:457>"
... in argument definition means argument is optional (has some default value).
For methods defined in C (language core and extensions), location and argument names can’t be extracted, and only generic information is provided in form of* (any number of arguments) or_ (some positional argument).
"cat".method(:count).inspect#=> "#<Method: String#count(*)>""cat".method(:+).inspect#=> "#<Method: String#+(_)>""
Source
static VALUEmethod_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, Qundef); RB_OBJ_WRITE(method, &data->iclass, orig->iclass); RB_OBJ_WRITE(method, &data->owner, orig->me->owner); RB_OBJ_WRITE(method, &data->me, rb_method_entry_clone(orig->me)); return method;}Dissociatesmeth from its current receiver. The resultingUnboundMethod can subsequently be bound to a new object of the same class (seeUnboundMethod).