class UnboundMethod

Parent:
Object

Ruby supports two forms of objectified methods. Class Method 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 Object#method.

Ruby also supports unbound methods; methods objects that are not associated with a particular object. These can be created either by calling Module#instance_method or by calling unbind on a bound method object. The result of both of these is an UnboundMethod 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

Public Instance Methods

meth == other_meth → true or false Show source
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;
}

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 Show source
static VALUE
method_arity_m(VALUE method)
{
    int n = method_arity(method);
    return INT2FIX(n);
}

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
bind(obj) → method Show source
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;
}

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
clone → new_method Show source
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;
}

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"
eql?(other_meth) → true or false Show source
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;
}

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 Show source
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);
}

Returns a hash value corresponding to the method object.

See also Object#hash.

inspect → string Show source
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;
}

Returns the name of the underlying method.

"cat".method(:count).inspect   #=> "#<Method: String#count>"
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->id);
}

Returns the name of the method.

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

Returns the original name of the method.

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

Returns the class or module that defines the method.

parameters → array Show source
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);
}

Returns the parameter information of this method.

source_location → [String, Fixnum] Show source
VALUE
rb_method_location(VALUE method)
{
    rb_method_definition_t *def = method_get_def(method);
    return method_def_location(def);
}

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() Show source
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);
}

Returns a Method of superclass, which would be called when super is used.

to_s → string Show source
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;
}

Returns the name of the underlying method.

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

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.