Method Objects

Ruby’s methods and blocks are executable language constructs, but they are not objects. Procs and lambdas are object versions of blocks; they can be executed and also manipulated as data. Ruby has powerful metaprogramming (or reflection) capabilities, and methods can actually be represented as instances of the Method class. (Metaprogramming is covered in Chapter 8, but Method objects are introduced here.) You should note that invoking a method through a Method object is less efficient than invoking it directly. Method objects are not typically used as often as lambdas and procs.

The Object class defines a method named method. Pass it a method name, as a string or a symbol, and it returns a Method object representing the named method of the receiver (or throws a NameError if there is no such method). For example:

m = 0.method(:succ)  # A Method representing the succ method of Fixnum 0

In Ruby 1.9, you can also use public_method to obtain a Method object. It works like method does but ignores protected and private methods (see Method Visibility: Public, Protected, Private).

The Method class is not a subclass of Proc, but it behaves much like it. Method objects are invoked with the call method (or the [] operator), just as Proc objects are. And Method defines an arity method just like the arity method of Proc. To invoke the Method m:

puts m.call    # Same as puts 0.succ. Or use puts m[].

Invoking a method through a Method object does not change the invocation semantics, nor does it alter the meaning of control-flow statements such as return and break. The call method of a Method object uses method-invocation semantics, not yield semantics. Method objects, therefore, behave more like lambdas than like procs.

Method objects work very much like Proc objects and can usually be used in place of them. When a true Proc is required, you can use Method.to_proc to convert a Method to a Proc. This is why Method objects can be prefixed with an ampersand and passed to a method in place of a block. For example:

def square(x); x*x; end
puts (1..10).map(&method(:square))

One important difference between Method objects and Proc objects is that Method objects are not closures. Ruby’s methods are intended to be completely self-contained, and they never have access to local variables outside of their own scope. The only binding retained by a Method object, therefore, is the value of self—the object on which the method is to be invoked.

In Ruby 1.9, the Method class defines three methods that are not available in 1.8: name returns the name of the method as a string; owner returns the class in which the method was defined; and receiver returns the object to which the method is bound. For any method object m, m.receiver.class must be equal to or a subclass of m.owner.

Unbound Method Objects

In addition to the Method class, Ruby also defines an UnboundMethod class. As its name suggests, an UnboundMethod object represents a method, without a binding to the object on which it is to be invoked. Because an UnboundMethod is unbound, it cannot be invoked, and the UnboundMethod class does not define a call or [] method.

To obtain an UnboundMethod object, use the instance_method method of any class or module:

unbound_plus = Fixnum.instance_method("+")

In Ruby 1.9, you can also use public_instance_method to obtain an UnboundMethod object. It works like instance_method does, but it ignores protected and private methods (see Method Visibility: Public, Protected, Private).

In order to invoke an unbound method, you must first bind it to an object using the bind method:

plus_2 = unbound_plus.bind(2)   # Bind the method to the object 2

The bind method returns a Method object, which can be invoked with its call method:

sum = plus_2.call(2)    # => 4

Another way to obtain an UnboundMethod object is with the unbind method of the Method class:

plus_3 = plus_2.unbind.bind(3)

In Ruby 1.9, UnboundMethod has name and owner methods that work just as they do for the Method class.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.36.231