Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ruby / Yukihiro Matsumoto_Programming Ruby.doc
Скачиваний:
122
Добавлен:
06.06.2015
Размер:
2.71 Mб
Скачать

The Exception Class

The package that contains the information about an exception is an object of class Exception, or one of classException's children. Ruby predefines a tidy hierarchy of exceptions, shown in Figure 8.1 on page 91. As we'll see later, this hierarchy makes handling exceptions considerably easier.

Figure not available...

When you need to raise an exception, you can use one of the built-in Exceptionclasses, or you can create one of your own. If you create your own, you might want to make it a subclass ofStandardErroror one of its children. If you don't, your exception won't be caught by default.

Every Exceptionhas associated with it a message string and a stack backtrace. If you define your own exceptions, you can add additional information.

Handling Exceptions

Our jukebox downloads songs from the Internet using a TCP socket. The basic code is simple:

opFile = File.open(opName, "w")

while data = socket.read(512)

  opFile.write(data)

end

What happens if we get a fatal error halfway through the download? We certainly don't want to store an incomplete song in the song list. ``I Did It My *click*''.

Let's add some exception handling code and see how it helps. We enclose the code that could raise an exception in a begin/endblock and userescueclauses to tell Ruby the types of exceptions we want to handle. In this case we're interested in trappingSystemCallErrorexceptions (and, by implication, any exceptions that are subclasses ofSystemCallError), so that's what appears on therescueline. In the error handling block, we report the error, close and delete the output file, and then reraise the exception.

opFile = File.open(opName, "w")

begin

  # Exceptions raised by this code will

  # be caught by the following rescue clause

  while data = socket.read(512)

    opFile.write(data)

  end

rescue SystemCallError

  $stderr.print "IO failed: " + $!

  opFile.close

  File.delete(opName)

  raise

end

When an exception is raised, and independent of any subsequent exception handling, Ruby places a reference to the Exceptionobject associated with the exception in the global variable$!(the exclamation point presumably mirroring our surprise that any ofourcode could cause errors). In the previous example, we used this variable to format our error message.

After closing and deleting the file, we call raisewith no parameters, which reraises the exception in$!. This is a useful technique, as it allows you to write code that filters exceptions, passing on those you can't handle to higher levels. It's almost like implementing an inheritance hierarchy for error processing.

You can have multiple rescueclauses in abeginblock, and eachrescueclause can specify multiple exceptions to catch. At the end of each rescue clause you can give Ruby the name of a local variable to receive the matched exception. Many people find this more readable than using$!all over the place.

begin

  eval string

rescue SyntaxError, NameError => boom

  print "String doesn't compile: " + boom

rescue StandardError => bang

  print "Error running script: " + bang

end

How does Ruby decide which rescue clause to execute? It turns out that the processing is pretty similar to that used by the casestatement. For eachrescueclause in thebeginblock, Ruby compares the raised exception against each of the parameters in turn. If the raised exception matches a parameter, Ruby executes the body of therescueand stops looking. The match is made using$!.kind_of?(parameter), and so will succeed if the parameter has the same class as the exception or is an ancestor of the exception. If you write arescueclause with no parameter list, the parameter defaults toStandardError.

If no rescueclause matches, or if an exception is raised outside abegin/endblock, Ruby moves up the stack and looks for an exception handler in the caller, then in the caller's caller, and so on.

Although the parameters to the rescueclause are typically the names ofExceptionclasses, they can actually be arbitrary expressions (including method calls) that return anExceptionclass.

Соседние файлы в папке Ruby