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
-
#== ⇒ 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? ⇒ 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).
-
#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.
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 |
# File 'proc.c', line 1240
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
2059 2060 2061 2062 2063 2064 |
# File 'proc.c', line 2059
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
1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 |
# File 'proc.c', line 1921
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"
1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 |
# File 'proc.c', line 1748
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.
1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 |
# File 'proc.c', line 1240
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.
1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 |
# File 'proc.c', line 1270
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>"
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 |
# File 'proc.c', line 2214
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.
1339 1340 1341 1342 1343 1344 1345 1346 |
# File 'proc.c', line 1339
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.
1355 1356 1357 1358 1359 1360 1361 1362 |
# File 'proc.c', line 1355
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.
1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 |
# File 'proc.c', line 1371
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.
2194 2195 2196 2197 2198 2199 2200 2201 2202 |
# File 'proc.c', line 2194
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)
2180 2181 2182 2183 2184 2185 |
# File 'proc.c', line 2180
VALUE
rb_method_location(VALUE method)
{
rb_method_definition_t *def = method_get_def(method);
return method_def_location(def);
}
|
#to_s ⇒ String #inspect ⇒ String
Returns the name of the underlying method.
"cat".method(:count).inspect #=> "#<Method: String#count>"
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 |
# File 'proc.c', line 2214
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;
}
|