Simon said:
Really I’m after something along the lines of what Java’s JavaDoc might
give which lists the thrown exceptions and the reasons why
If the author includes that in the API documentation, then you'll have
it; if the author doesn't, then I'm afraid you won't.
In the case of Net::FTP you can see that the author decided to remove
all of the exception classes from the documentation
stopdoc
,
presumably to avoid cluttering it up.
or if there is a tool that can generate this
sort of info?
The documentation you are currently looking at is generated via rdoc,
which basically extracts comments and method signatures from the code.
However, Ruby is a very dynamic language and it's not possible to
determine from static source analysis which exceptions may or may not be
thrown.
This isn't just nitpicking. It's quite common in Ruby to pass around and
use objects of 'unrelated' classes at runtime: 'unrelated' in the sense
of not sharing a common ancestor class other than Object. Rather, they
implement the same 'duck-type' interface. In the case of Net::FTP you
might arrange that it uses a SOCKSSocket instead of a Socket, for
example, and SOCKSSocket could have its own set of exceptions that it
raises (SOCKS authentication error, for example).
You could argue that if it raises a different exception under similar
circumstances then that's a duck-type violation - the duck goes honk
instead of quack. Unfortunately, this aspect of duck-typing is often
overlooked.
Anyway: there's no formal "interface" in ruby, which means objects can
implement whatever methods they feel like, and raise whatever exceptions
they feel like, and change their behaviour at runtime whenever they feel
like.
You probably find this dirty. However it's what enables all sorts of
goodness, such as ActiveRecord being able to define model classes at
runtime based on the columns in your database. The advice I give to you
is: relax, and have good unit test coverage.
I did try looking at the source however the problem is just the time it
takes to go through everything to find what throws what
It's pretty obvious in this case. All you have to do is look for classes
of which Exception is an ancestor (or StandardError or RuntimeError),
and they are all bundled together at the top of the file. It's just
convention, rather than rigidly enforced.
and this is
fairly error-prone and time-consuming; e.g. if I call nlst() without a
network connection, the exception is thrown from nlst > retrlines >
voidcmd > putline, which is throwing an error from a call to
TCPSocket.write...
Indeed. Hence my advice to be generic in your rescue strategy.
But *why* would you be calling nlst on a connection which isn't open?
Isn't that a programmer error, and therefore you shouldn't be catching
the exception at all?
-- although I guess I may still need to search through all the code to
find the different IOError and SystemCallError instances, to see if I’d
want to treat them differently.
Those are pretty low-level - for example, Errno::ECONNREFUSED is a
subclass of SystemCallError, so to determine all possible exceptions
when opening a socket you'll really need to look at the documentation
for the unix open(2) call and the possible errno values which it can
set.
It has to be said that Ruby's own core documentation is a long way from
complete.
Regards,
Brian.