Defining Simple Methods

You’ve seen many method invocations in examples throughout this book, and method invocation syntax was described in detail in Method Invocations. Now we turn to the syntax for defining methods. This section explains method definition basics. It is followed by three more sections that cover method names, method parentheses, and method arguments in more detail. These additional sections explain more advanced material and are relevant to both method definition and method invocation.

Methods are defined with the def keyword. This is followed by the method name and an optional list of parameter names in parentheses. The Ruby code that constitutes the method body follows the parameter list, and the end of the method is marked with the end keyword. Parameter names can be used as variables within the method body, and the values of these named parameters come from the arguments to a method invocation. Here is an example method:

# Define a method named 'factorial' with a single parameter 'n'
def factorial(n)
  if n < 1                # Test the argument value for validity
    raise "argument must be > 0"
  elsif n == 1            # If the argument is 1
    1                     # then the value of the method invocation is 1
  else                    # Otherwise, the factorial of n is n times
    n * factorial(n-1)    # the factorial of n-1
  end
end

This code defines a method named factorial. The method has a single parameter named n. The identifier n is used as a variable within the body of the method. This is a recursive method, so the body of the method includes an invocation of the method. The invocation is simply the name of the method followed by the argument value in parentheses.

Method Return Value

Methods may terminate normally or abnormally. Abnormal termination occurs when the method raises an exception. The factorial method shown earlier terminates abnormally if we pass it an argument less than 1. If a method terminates normally, then the value of the method invocation expression is the value of the last expression evaluated within the method body. In the factorial method, that last expression will either be 1 or n*factorial(n-1).

The return keyword is used to force a return prior to the end of the method. If an expression follows the return keyword, then the value of that expression is returned. If no expression follows, then the return value is nil. In the following variant of the factorial method, the return keyword is required:

def factorial(n)
  raise "bad argument" if n < 1
  return 1 if n == 1
  n * factorial(n-1)
end

We could also use return on the last line of this method body to emphasize that this expression is the method’s return value. In common practice, however, return is omitted where it is not required.

Ruby methods may return more than one value. To do this, use an explicit return statement, and separate the values to be returned with commas:

# Convert the Cartesian point (x,y) to polar (magnitude, angle) coordinates
def polar(x,y)
  return Math.hypot(y,x), Math.atan2(y,x)
end

When there is more than one return value, the values are collected into an array, and the array becomes the single return value of the method. Instead of using the return statement with multiple values, we can simply create an array of values ourselves:

# Convert polar coordinates to Cartesian coordinates
def cartesian(magnitude, angle)
  [magnitude*Math.cos(angle), magnitude*Math.sin(angle)]
end

Methods of this form are typically intended for use with parallel assignment (see Parallel Assignment) so that each return value is assigned to a separate variable:

distance, theta = polar(x,y)
x,y = cartesian(distance,theta)

Methods and Exception Handling

A def statement that defines a method may include exception-handling code in the form of rescue, else, and ensure clauses, just as a begin statement can. These exception-handling clauses go after the end of the method body but before the end of the def statement. In short methods, it can be particularly tidy to associate your rescue clauses with the def statement. This also means you don’t have to use a begin statement and the extra level of indentation that comes with it. See rescue with Method, Class, and Module Definitions for further details.

Invoking a Method on an Object

Methods are always invoked on an object. (This object is sometimes called the receiver in a reference to an object-oriented paradigm in which methods are called “messages” and are “sent to” receiver objects.) Within the body of a method, the keyword self refers to the object on which the method was invoked. If we don’t specify an object when invoking a method, then the method is implicitly invoked on self.

You’ll learn how to define methods for classes of objects in Chapter 7. Notice, however, that you’ve already seen examples of invoking methods on objects, in code like this:

first = text.index(pattern)

Like most object-oriented languages, Ruby uses . to separate the object from the method to be invoked on it. This code passes the value of the variable pattern to the method named index of the object stored in the variable text, and stores the return value in the variable first.

Defining Singleton Methods

The methods we’ve defined so far are all global methods. If we place a def statement like the ones shown earlier inside a class statement, then the methods that are defined are instance methods of the class; these methods are defined on all objects that are instances of the class. (Classes and instance methods are explained in Chapter 7.)

It is also possible, however, to use the def statement to define a method on a single specified object. Simply follow the def keyword with an expression that evaluates to an object. This expression should be followed by a period and the name of the method to be defined. The resulting method is known as a singleton method because it is available only on a single object:

o = "message"    # A string is an object
def o.printme    # Define a singleton method for this object
  puts self
end
o.printme        # Invoke the singleton 

Class methods (covered in Chapter 7) such as Math.sin and File.delete are actually singleton methods. Math is a constant that refers to a Module object, and File is a constant that refers to a Class object. These two objects have singleton methods named sin and delete, respectively.

Ruby implementations typically treat Fixnum and Symbol values as immediate values rather than as true object references. (See Immediate values.) For this reason, singleton methods may not be defined on Fixnum and Symbol objects. For consistency, singletons are also prohibited on other Numeric objects.

Undefining Methods

Methods are defined with the def statement and may be undefined with the undef statement:

def sum(x,y); x+y; end      # Define a method
puts sum(1,2)               # Use it
undef sum                   # And undefine it

In this code, the def statement defines a global method, and undef undefines it. undef also works within classes (which are the subject of Chapter 7) to undefine the instance methods of the class. Interestingly, undef can be used to undefine inherited methods, without affecting the definition of the method in the class from which it is inherited. Suppose class A defines a method m, and class B is a subclass of A and therefore inherits m. (Subclasses and inheritance are also explained in Chapter 7.) If you don’t want to allow instances of class B to be able to invoke m, you can use undef m within the body of the subclass.

undef is not a commonly used statement. In practice, it is much more common to redefine a method with a new def statement than it is to undefine or delete the method.

Note that the undef statement must be followed by a single identifier that specifies the method name. It cannot be used to undefine a singleton method in the way that def can be used to define such a method.

Within a class or module, you can also use undef_method (a private method of Module) to undefine methods. Pass a symbol representing the name of the method to be undefined.

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

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