/* * call-seq: * umeth.bind(obj) -> method * * Bind <i>umeth</i> to <i>obj</i>. If <code>Klass</code> was the class * from which <i>umeth</i> was obtained, * <code>obj.kind_of?(Klass)</code> 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 * * <em>produces:</em> * * 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(method, recv) VALUE method, recv; { struct METHOD *data, *bound; VALUE rklass = CLASS_OF(recv); Data_Get_Struct(method, struct METHOD, data); if (data->rklass != rklass) { if (FL_TEST(data->rklass, FL_SINGLETON)) { rb_raise(rb_eTypeError, "singleton method bound for a different object"); } if (TYPE(data->rklass) == T_MODULE) { st_table *m_tbl = RCLASS(data->rklass)->m_tbl; while (RCLASS(rklass)->m_tbl != m_tbl) { rklass = RCLASS(rklass)->super; if (!rklass) goto not_instace; } } else if (!rb_obj_is_kind_of(recv, data->rklass)) { not_instace: rb_raise(rb_eTypeError, "bind argument must be an instance of %s", rb_class2name(data->rklass)); } } method = Data_Make_Struct(rb_cMethod,struct METHOD,bm_mark,free,bound); *bound = *data; bound->recv = recv; bound->rklass = rklass; return method; }