Ruby 2.4

UnboundMethod

class UnboundMethod

Parent:Object

Ruby支持两种形式的客体化方法。Class Method用于表示与特定对象关联的方法:这些方法对象绑定到该对象。可以使用创建对象的绑定方法对象Object#method

Ruby还支持未绑定的方法; 方法不与特定对象关联的对象。这些可以通过调用Module#instance_method或通过调用unbind绑定的方法对象来创建。这两者的结果都是一个UnboundMethod对象。

未绑定的方法只能在绑定到对象后才能调用。该对象必须是一种kind?该方法的原始类。

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

未绑定的方法是该方法在客体化时的引用:对基础类的后续更改不会影响未绑定的方法。

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

公共实例方法

meth == other_meth → true or false Show source

如果两个方法对象绑定到同一个对象并引用相同的方法定义,并且它们的所有者是相同的类或模块,则它们是相等的。

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; }

arity → integer Show source

返回一个方法接受的参数个数的指示。返回具有固定数量参数的方法的非负整数。对于采用可变数量参数的Ruby方法,返回-n-1,其中n是所需参数的数量。对于用C编写的方法,如果调用需要可变数量的参数,则返回-1。

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

static VALUE method_arity_m(VALUE method) { int n = method_arity(method return INT2FIX(n }

bind(obj) → method Show source

umeth绑定到obj。如果Klass从中获得了umeth的阶级,那么obj.kind_of?(Klass)必须是真实的。

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

static VALUE umethod_bind(VALUE method, VALUE recv) { struct METHOD *data, *bound; VALUE methclass, klass; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data methclass = data->me->owner; 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) } } klass = CLASS_OF(recv method = TypedData_Make_Struct(rb_cMethod, struct METHOD, &method_data_type, bound RB_OBJ_WRITE(method, &bound->recv, recv RB_OBJ_WRITE(method, &bound->klass, data->klass RB_OBJ_WRITE(method, &bound->me, rb_method_entry_clone(data->me) if (RB_TYPE_P(bound->me->owner, T_MODULE)) { VALUE ic = rb_class_search_ancestor(klass, bound->me->owner if (ic) { klass = ic; } else { klass = rb_include_class_new(methclass, klass } RB_OBJ_WRITE(method, &bound->me, rb_method_entry_complement_defined_class(bound->me, bound->me->called_id, klass) } return method; }

clone → new_method Show source

返回此方法的克隆。

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; }

eql?(other_meth) → true or false Show source

如果两个方法对象绑定到同一个对象并引用相同的方法定义,并且它们的所有者是相同的类或模块,则它们是相等的。

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; }

hash → integer Show source

返回与方法对象相对应的哈希值。

另请参阅 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 INT2FIX(hash }

inspect → string Show source

返回基础方法的名称。

"cat".method(:count).inspect #=> "#<Method: String#count>"

static VALUE method_inspect(VALUE method) { struct METHOD *data; VALUE str; const char *s; const char *sharp = "#"; VALUE mklass; VALUE defined_class; 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->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 { rb_str_buf_append(str, rb_class_name(mklass) if (defined_class != mklass) { rb_str_buf_cat2(str, "(" rb_str_buf_append(str, rb_class_name(defined_class) rb_str_buf_cat2(str, ")" } } 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; }

name → symbol Show source

返回方法的名称。

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 → symbol Show source

返回方法的原始名称。

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 → class_or_module Show source

返回定义该方法的类或模块。

static VALUE method_owner(VALUE obj) { struct METHOD *data; TypedData_Get_Struct(obj, struct METHOD, &method_data_type, data return data->me->owner; }

parameters → array Show source

返回此方法的参数信息。

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 unnamed_parameters(method_arity(method) } return rb_iseq_parameters(iseq, 0 }

source_location → String, Integer()

返回包含此方法的Ruby源文件名和行号,如果此方法未在Ruby中定义(即本机),则返回nil。

VALUE rb_method_location(VALUE method) { return method_def_location(method_def(method) }

super_method → method Show source

返回当使用super时会调用的超类的方法,或者如果超类没有方法,则返回nil。

static VALUE method_super_method(VALUE method) { const struct METHOD *data; VALUE super_class; const rb_method_entry_t *me; TypedData_Get_Struct(method, struct METHOD, &method_data_type, data super_class = RCLASS_SUPER(method_entry_defined_class(data->me) if (!super_class) return Qnil; me = (rb_method_entry_t *)rb_callable_method_entry_without_refinements(super_class, data->me->called_id if (!me) return Qnil; return mnew_internal(me, super_class, data->recv, data->me->called_id, rb_obj_class(method), FALSE, FALSE }

to_s → string Show source

返回基础方法的名称。

"cat".method(:count).inspect #=> "#<Method: String#count>"

static VALUE method_inspect(VALUE method) { struct METHOD *data; VALUE str; const char *s; const char *sharp = "#"; VALUE mklass; VALUE defined_class; 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->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 { rb_str_buf_append(str, rb_class_name(mklass) if (defined_class != mklass) { rb_str_buf_cat2(str, "(" rb_str_buf_append(str, rb_class_name(defined_class) rb_str_buf_cat2(str, ")" } } 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; }