Class: Method
Overview
********************************************************************
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)>]
Instance Method Summary collapse
-
#<<(g) ⇒ Proc
Returns a proc that is the composition of this method and the given g.
-
#==(other) ⇒ Object
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.
-
#call(args, ...) ⇒ Object
Invokes the meth with the specified arguments, returning the method’s return value.
-
#>>(g) ⇒ Proc
Returns a proc that is the composition of this method and the given g.
-
#call(args, ...) ⇒ Object
Invokes the meth with the specified arguments, returning the method’s return value.
-
#arity ⇒ Integer
Returns an indication of the number of arguments accepted by a method.
-
#call(args, ...) ⇒ Object
Invokes the meth with the specified arguments, returning the method’s return value.
-
#clone ⇒ Object
Returns a clone of this method.
-
#curry(*args) ⇒ Object
Returns a curried proc based on the method.
-
#dup ⇒ Object
:nodoc:.
-
#eql?(other) ⇒ Object
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.
-
#hash ⇒ Integer
Returns a hash value corresponding to the method object.
-
#inspect ⇒ Object
Returns a human-readable description of the underlying method.
-
#name ⇒ Object
Returns the name of the method.
-
#original_name ⇒ Object
Returns the original name of the method.
-
#owner ⇒ Object
Returns the class or module on which this method is defined.
-
#parameters ⇒ Array
Returns the parameter information of this method.
-
#receiver ⇒ Object
Returns the bound receiver of the method object.
-
#source_location ⇒ Array, Integer
Returns the Ruby source filename and line number containing this method or nil if this method was not defined in Ruby (i.e. native).
-
#super_method ⇒ Object
Returns a Method of superclass which would be called when super is used or nil if there is no method on superclass.
-
#to_proc ⇒ Proc
Returns a Proc object corresponding to this method.
-
#to_s ⇒ Object
Returns a human-readable description of the underlying method.
-
#unbind ⇒ Object
Dissociates meth from its current receiver.
Instance Method Details
#<<(g) ⇒ Proc
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
3875 3876 3877 3878 3879 3880 3881 |
# File 'proc.c', line 3875
static VALUE
rb_method_compose_to_left(VALUE self, VALUE g)
{
g = to_callable(g);
self = method_to_proc(self);
return proc_compose_to_left(self, g);
}
|
#eql?(other_meth) ⇒ Boolean #==(other_meth) ⇒ Boolean
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.
1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 |
# File 'proc.c', line 1824
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 *)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;
}
|
#call(args, ...) ⇒ Object
Invokes the meth with the specified arguments, returning the method’s return value.
m = 12.method("+")
m.call(3) #=> 15
m.call(20) #=> 32
2510 2511 2512 2513 2514 |
# File 'proc.c', line 2510
static VALUE
rb_method_call_pass_called_kw(int argc, const VALUE *argv, VALUE method)
{
return rb_method_call_kw(argc, argv, method, RB_PASS_CALLED_KEYWORDS);
}
|
#>>(g) ⇒ Proc
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
3899 3900 3901 3902 3903 3904 3905 |
# File 'proc.c', line 3899
static VALUE
rb_method_compose_to_right(VALUE self, VALUE g)
{
g = to_callable(g);
self = method_to_proc(self);
return proc_compose_to_right(self, g);
}
|
#call(args, ...) ⇒ Object
Invokes the meth with the specified arguments, returning the method’s return value.
m = 12.method("+")
m.call(3) #=> 15
m.call(20) #=> 32
2510 2511 2512 2513 2514 |
# File 'proc.c', line 2510
static VALUE
rb_method_call_pass_called_kw(int argc, const VALUE *argv, VALUE method)
{
return rb_method_call_kw(argc, argv, method, RB_PASS_CALLED_KEYWORDS);
}
|
#arity ⇒ Integer
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
2888 2889 2890 2891 2892 2893 |
# File 'proc.c', line 2888
static VALUE
method_arity_m(VALUE method)
{
int n = method_arity(method);
return INT2FIX(n);
}
|
#call(args, ...) ⇒ Object
Invokes the meth with the specified arguments, returning the method’s return value.
m = 12.method("+")
m.call(3) #=> 15
m.call(20) #=> 32
2510 2511 2512 2513 2514 |
# File 'proc.c', line 2510
static VALUE
rb_method_call_pass_called_kw(int argc, const VALUE *argv, VALUE method)
{
return rb_method_call_kw(argc, argv, method, RB_PASS_CALLED_KEYWORDS);
}
|
#clone ⇒ Object
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"
2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 |
# File 'proc.c', line 2432
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);
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;
}
|
#curry ⇒ Proc #curry(arity) ⇒ 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 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]
3719 3720 3721 3722 3723 3724 |
# File 'proc.c', line 3719
static VALUE
rb_method_curry(int argc, const VALUE *argv, VALUE self)
{
VALUE proc = method_to_proc(self);
return proc_curry(argc, argv, proc);
}
|
#dup ⇒ Object
:nodoc:
2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 |
# File 'proc.c', line 2450
static VALUE
method_dup(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_dup_setup(self, clone);
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;
}
|
#eql?(other_meth) ⇒ Boolean #==(other_meth) ⇒ Boolean
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.
1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 |
# File 'proc.c', line 1824
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 *)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;
}
|
#hash ⇒ Integer
Returns a hash value corresponding to the method object.
See also Object#hash.
1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 |
# File 'proc.c', line 1877
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);
}
|
#to_s ⇒ String #inspect ⇒ String
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
).
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#+(_)>""
3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 |
# File 'proc.c', line 3165
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));
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);
name = RARRAY_AREF(pair, 1);
// FIXME: in tests it turns out that kind, name = [:req] produces name to be false. Why?..
if (NIL_P(name) || name == Qfalse) {
// 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");
}
}
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;
}
|
#name ⇒ Object
Returns the name of the method.
1943 1944 1945 1946 1947 1948 1949 1950 |
# File 'proc.c', line 1943
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);
}
|
#original_name ⇒ Object
Returns the original name of the method.
class C
def foo; end
alias foo
end
C.instance_method(:bar).original_name # => :foo
1965 1966 1967 1968 1969 1970 1971 1972 |
# File 'proc.c', line 1965
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);
}
|
#owner ⇒ Object
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 also Method#receiver.
(1..3).method(:map).owner #=> Enumerable
1992 1993 1994 1995 1996 1997 1998 |
# File 'proc.c', line 1992
static VALUE
method_owner(VALUE obj)
{
struct METHOD *data;
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
return data->owner;
}
|
#parameters ⇒ Array
Returns the parameter information of this method.
def foo(); end
method(:foo).parameters #=> [[:req, :bar]]
def foo(, baz, bat, &blk); end
method(:foo).parameters #=> [[:req, :bar], [:req, :baz], [:req, :bat], [:block, :blk]]
def foo(, *args); end
method(:foo).parameters #=> [[:req, :bar], [:rest, :args]]
def foo(, baz, *args, &blk); end
method(:foo).parameters #=> [[:req, :bar], [:req, :baz], [:rest, :args], [:block, :blk]]
3126 3127 3128 3129 3130 |
# File 'proc.c', line 3126
static VALUE
rb_method_parameters(VALUE method)
{
return method_def_parameters(rb_method_def(method));
}
|
#receiver ⇒ Object
Returns the bound receiver of the method object.
(1..3).method(:map).receiver # => 1..3
1927 1928 1929 1930 1931 1932 1933 1934 |
# File 'proc.c', line 1927
static VALUE
method_receiver(VALUE obj)
{
struct METHOD *data;
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
return data->recv;
}
|
#source_location ⇒ Array, Integer
Returns the Ruby source filename and line number containing this method or nil if this method was not defined in Ruby (i.e. native).
3038 3039 3040 3041 3042 |
# File 'proc.c', line 3038
VALUE
rb_method_location(VALUE method)
{
return method_def_location(rb_method_def(method));
}
|
#super_method ⇒ Object
Returns a Method of superclass which would be called when super is used or nil if there is no method on superclass.
3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 |
# File 'proc.c', line 3414
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_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);
}
|
#to_proc ⇒ Proc
Returns a Proc object corresponding to this method.
3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 |
# File 'proc.c', line 3383
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_block_call(rb_mRubyVMFrozenCore, idLambda, 0, 0, bmcall, method);
GetProcPtr(procval, proc);
proc->is_from_method = 1;
return procval;
}
|
#to_s ⇒ String #inspect ⇒ String
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
).
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#+(_)>""
3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 |
# File 'proc.c', line 3165
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));
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);
name = RARRAY_AREF(pair, 1);
// FIXME: in tests it turns out that kind, name = [:req] produces name to be false. Why?..
if (NIL_P(name) || name == Qfalse) {
// 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");
}
}
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;
}
|
#unbind ⇒ Object
Dissociates meth from its current receiver. The resulting UnboundMethod can subsequently be bound to a new object of the same class (see UnboundMethod).
1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 |
# File 'proc.c', line 1900
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, 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;
}
|