Class: UnboundMethod
Overview
********************************************************************
Ruby supports two forms of objectified methods. Class
<code>Method</code> is used to represent methods that are associated
with a particular object: these method objects are bound to that
object. Bound method objects for an object can be created using
<code>Object#method</code>.
Ruby also supports unbound methods; methods objects that are not
associated with a particular object. These can be created either by
calling <code>Module#instance_method</code> or by calling
<code>unbind</code> on a bound method object. The result of both of
these is an <code>UnboundMethod</code> object.
Unbound methods can only be called after they are bound to an
object. That object must be be a kind_of? the method's original
class.
class Square
def area
@side * @side
end
def initialize(side)
@side = side
end
end
area_un = Square.instance_method(:area)
s = Square.new(12)
area = area_un.bind(s)
area.call #=> 144
Unbound methods are a reference to the method at the time it was
objectified: subsequent changes to the underlying class will not
affect the unbound method.
class Test
def test
:original
end
end
um = Test.instance_method(:test)
class Test
def test
:modified
end
end
t = Test.new
t.test #=> :modified
um.bind(t).call #=> :original
Instance Method Summary collapse
-
#==(other) ⇒ Object
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.
-
#arity ⇒ Fixnum
Returns an indication of the number of arguments accepted by a method.
-
#bind(obj) ⇒ Object
Bind umeth to obj.
-
#clone ⇒ Object
Returns a clone of this method.
-
#eql?(other) ⇒ Boolean
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.
-
#hash ⇒ Integer
Returns a hash value corresponding to the method object.
-
#inspect ⇒ Object
Returns the name 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 that defines the method.
-
#parameters ⇒ Array
Returns the parameter information of this method.
-
#source_location ⇒ Array, Fixnum
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.
-
#to_s ⇒ Object
Returns the name of the underlying method.
Instance Method Details
#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 their owners are the same class or module.
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 |
# File 'proc.c', line 1269
static VALUE
method_eq(VALUE method, VALUE other)
{
struct METHOD *m1, *m2;
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);
if (!rb_method_entry_eq(m1->me, m2->me) ||
m1->rclass != m2->rclass ||
m1->recv != m2->recv) {
return Qfalse;
}
return Qtrue;
}
|
#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
2092 2093 2094 2095 2096 2097 |
# File 'proc.c', line 2092
static VALUE
method_arity_m(VALUE method)
{
int n = method_arity(method);
return INT2FIX(n);
}
|
#bind(obj) ⇒ Object
Bind umeth to obj. If Klass
was the class from which umeth was obtained, obj.kind_of?(Klass)
must be true.
class A
def test
puts "In test, class = #{self.class}"
end
end
class B < A
end
class C < B
end
um = B.instance_method(:test)
bm = um.bind(C.new)
bm.call
bm = um.bind(B.new)
bm.call
bm = um.bind(A.new)
bm.call
produces:
In test, class = C
In test, class = B
prog.rb:16:in `bind': bind argument must be an instance of B (TypeError)
from prog.rb:16
1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 |
# File 'proc.c', line 1954
static VALUE
umethod_bind(VALUE method, VALUE recv)
{
struct METHOD *data, *bound;
VALUE methclass;
VALUE rclass;
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
methclass = data->rclass;
if (!RB_TYPE_P(methclass, T_MODULE) &&
methclass != CLASS_OF(recv) && !rb_obj_is_kind_of(recv, methclass)) {
if (FL_TEST(methclass, FL_SINGLETON)) {
rb_raise(rb_eTypeError,
"singleton method called for a different object");
}
else {
rb_raise(rb_eTypeError, "bind argument must be an instance of % "PRIsVALUE,
rb_class_name(methclass));
}
}
method = TypedData_Make_Struct(rb_cMethod, struct METHOD, &method_data_type, bound);
*bound = *data;
bound->me = ALLOC(rb_method_entry_t);
*bound->me = *data->me;
if (bound->me->def) bound->me->def->alias_count++;
rclass = CLASS_OF(recv);
if (BUILTIN_TYPE(bound->defined_class) == T_MODULE) {
VALUE ic = rb_class_search_ancestor(rclass, bound->defined_class);
if (ic) {
rclass = ic;
}
else {
rclass = rb_include_class_new(methclass, rclass);
}
}
bound->recv = recv;
bound->rclass = rclass;
data->ume = ALLOC(struct unlinked_method_entry_list_entry);
return method;
}
|
#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"
1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 |
# File 'proc.c', line 1780
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);
*data = *orig;
data->me = ALLOC(rb_method_entry_t);
*data->me = *orig->me;
if (data->me->def) data->me->def->alias_count++;
data->ume = ALLOC(struct unlinked_method_entry_list_entry);
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 their owners are the same class or module.
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 |
# File 'proc.c', line 1269
static VALUE
method_eq(VALUE method, VALUE other)
{
struct METHOD *m1, *m2;
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);
if (!rb_method_entry_eq(m1->me, m2->me) ||
m1->rclass != m2->rclass ||
m1->recv != m2->recv) {
return Qfalse;
}
return Qtrue;
}
|
#hash ⇒ Integer
Returns a hash value corresponding to the method object.
See also Object#hash.
1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 |
# File 'proc.c', line 1301
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->rclass);
hash = rb_hash_uint(hash, (st_index_t)m->recv);
hash = rb_hash_method_entry(hash, m->me);
hash = rb_hash_end(hash);
return INT2FIX(hash);
}
|
#to_s ⇒ String #inspect ⇒ String
Returns the name of the underlying method.
"cat".method(:count).inspect #=> "#<Method: String#count>"
2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 |
# File 'proc.c', line 2247
static VALUE
method_inspect(VALUE method)
{
struct METHOD *data;
VALUE str;
const char *s;
const char *sharp = "#";
VALUE mklass;
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
str = rb_str_buf_new2("#<");
s = rb_obj_classname(method);
rb_str_buf_cat2(str, s);
rb_str_buf_cat2(str, ": ");
mklass = data->me->klass;
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 {
rb_str_buf_append(str, rb_class_name(data->rclass));
if (data->rclass != mklass) {
rb_str_buf_cat2(str, "(");
rb_str_buf_append(str, rb_class_name(mklass));
rb_str_buf_cat2(str, ")");
}
}
rb_str_buf_cat2(str, sharp);
rb_str_append(str, rb_id2str(data->id));
if (data->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;
}
|
#name ⇒ Object
Returns the name of the method.
1370 1371 1372 1373 1374 1375 1376 1377 |
# File 'proc.c', line 1370
static VALUE
method_name(VALUE obj)
{
struct METHOD *data;
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
return ID2SYM(data->id);
}
|
#original_name ⇒ Object
Returns the original name of the method.
1386 1387 1388 1389 1390 1391 1392 1393 |
# File 'proc.c', line 1386
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 that defines the method.
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 |
# File 'proc.c', line 1402
static VALUE
method_owner(VALUE obj)
{
struct METHOD *data;
VALUE defined_class;
TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data);
defined_class = data->defined_class;
if (RB_TYPE_P(defined_class, T_ICLASS)) {
defined_class = RBASIC_CLASS(defined_class);
}
return defined_class;
}
|
#parameters ⇒ Array
Returns the parameter information of this method.
2227 2228 2229 2230 2231 2232 2233 2234 2235 |
# File 'proc.c', line 2227
static VALUE
rb_method_parameters(VALUE method)
{
rb_iseq_t *iseq = rb_method_get_iseq(method);
if (!iseq) {
return unnamed_parameters(method_arity(method));
}
return rb_iseq_parameters(iseq, 0);
}
|
#source_location ⇒ Array, Fixnum
Returns the Ruby source filename and line number containing this method or nil if this method was not defined in Ruby (i.e. native)
2213 2214 2215 2216 2217 2218 |
# File 'proc.c', line 2213
VALUE
rb_method_location(VALUE method)
{
rb_method_definition_t *def = method_get_def(method);
return method_def_location(def);
}
|
#super_method ⇒ Object
Returns a Method of superclass, which would be called when super is used.
2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 |
# File 'proc.c', line 2382
static VALUE
method_super_method(VALUE method)
{
struct METHOD *data;
VALUE defined_class, super_class;
rb_method_entry_t *me;
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
defined_class = data->defined_class;
if (BUILTIN_TYPE(defined_class) == T_MODULE) defined_class = data->rclass;
super_class = RCLASS_SUPER(defined_class);
if (!super_class) return Qnil;
me = rb_method_entry_without_refinements(super_class, data->id, &defined_class);
if (!me) return Qnil;
return mnew_internal(me, defined_class,
super_class, data->recv, data->id,
rb_obj_class(method), FALSE, FALSE);
}
|
#to_s ⇒ String #inspect ⇒ String
Returns the name of the underlying method.
"cat".method(:count).inspect #=> "#<Method: String#count>"
2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 |
# File 'proc.c', line 2247
static VALUE
method_inspect(VALUE method)
{
struct METHOD *data;
VALUE str;
const char *s;
const char *sharp = "#";
VALUE mklass;
TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
str = rb_str_buf_new2("#<");
s = rb_obj_classname(method);
rb_str_buf_cat2(str, s);
rb_str_buf_cat2(str, ": ");
mklass = data->me->klass;
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 {
rb_str_buf_append(str, rb_class_name(data->rclass));
if (data->rclass != mklass) {
rb_str_buf_cat2(str, "(");
rb_str_buf_append(str, rb_class_name(mklass));
rb_str_buf_cat2(str, ")");
}
}
rb_str_buf_cat2(str, sharp);
rb_str_append(str, rb_id2str(data->id));
if (data->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;
}
|