How to deal with not knowing what exceptions can be raised by a library method in Ruby?
Asked Answered
D

5

21

This is somewhat of a broad question, but it is one that I continue to come across when programming in Ruby. I am from a largely C and Java background, where when I use a library function or method, I look at the documentation and see what it returns on error (usually in C) or which exceptions it can throw (in Java).

In Ruby, the situation seems completely different. Just now I need to parse some JSON I receive from a server:

data = JSON.parse(response)

Naturally, the first thing I think after writing this code is, what if the input is bad? Is parse going to return nil on error, or raise some exception, and if so, which ones?

I check the documentation (http://flori.github.com/json/doc/JSON.html#M000022) and see, simply:

"Parse the JSON string source into a Ruby data structure and return it."

This is just an example of a pattern I have run into repeatedly in Ruby. Originally, I figured it was some shortcoming of the documentation of whatever library I was working with, but now I am starting to feel this is standard practice and I am in a somewhat different mindset than Ruby programmers. Is there some convention I am unaware of?

How do developers deal with this?

(And yes I did look at the code of the library method, and can get some idea of what exceptions are raised but I cannot be 100% sure and if it is not documented I feel uncomfortable relying on it.)

EDIT: After looking at the first two answers, let me continue the JSON parsing example from above.

I suspect I should not do:

begin
  data = JSON.parse(response)
  raise "parse error" if data.nil?
rescue Exception => e
  # blahblah
end

because I can look at the code/tests and see it seems to raise a ParserError on error (returning nil seems to not be standard practice in Ruby). Would I be correct in saying the recommended practice is to do:

begin
  data = JSON.parse(response)
rescue JSON::ParserError => e
  # blahblah
end

...based upon what I learned about ParserError by looking through the code and tests?

(I also edited the example to clarify it is a response from a server that I am parsing.)

Droplight answered 8/9, 2009 at 7:15 Comment(0)
H
9

(And yes I did look at the code of the library method, and can get some idea of what exceptions are raised but I cannot be 100% sure and if it is not documented I feel uncomfortable relying on it.)

I suggest having a look at the tests, as they will show some of the "likely" scenarios and what might be raised. Don't forget that good tests are documentation, too.

Hellbent answered 8/9, 2009 at 7:30 Comment(2)
agreed, write all possible spec/test for your input data to your method and develop your application to manage those exceptions.Misalliance
This is a good point, and I'll look at the tests from now on.Droplight
G
4

Should you want to discard non valid JSON data:

begin
  res = JSON.parse(string)
rescue JSON::ParserError => e
  # string was not valid
end
Gothenburg answered 25/8, 2015 at 12:43 Comment(0)
T
3

I guess that if no documentation is provided, you have to rely on something like this :

begin
   # code goes here
rescue
   # fail reason is in $!
end
Thyme answered 8/9, 2009 at 8:31 Comment(1)
this is basically the same as Preet Sangha's answer https://mcmap.net/q/606935/-how-to-deal-with-not-knowing-what-exceptions-can-be-raised-by-a-library-method-in-ruby. also, you say "if no documentation is provided," as if no documentation on this is an edge case. but in reality, "no documentation" - or at least poor documentation about specific exceptions being raised by methods - is the norm even in core and std libary.Reviere
T
1

You can never be sure what exceptions can be raised, unless the library code catches all and then wraps them. Your best bet is to assume good input from your code by sanitising what goes in and then use your own higher level exception handling to catch bad input from your inputs.

Tridimensional answered 8/9, 2009 at 7:18 Comment(2)
I don't think this is realistic. In this particular case, I am parsing a response from a server. In the rare case that the server sent me bad data, I want to at least be able to fail gracefully and say "bad response from server".Droplight
In this case you need to catch the general exception from this method and and reraise with appropriate message.Tridimensional
R
0

Your question boils down to basically two questions: is there a convention or standard for finding possible exceptions, and also where is the documentation related to such a convention?

For the first question, the closest thing to a convention or standard is the location and existence of an exceptions.rb file. For libraries or gems where the source code is publicly available, you can typically find the types of exceptions in this file. (Ref here).

If source code is not available or easily accessed, the documentation is your next best source of information. This brings us to your second question. Unfortunately documentation does not have a consistent format concerning potential exceptions, even in standard libraries. For example, the Net::Http documentation doesn't make it obvious what exceptions are available, although if you dig through it you will find that all exceptions inherit from Net::HTTPExceptions.

As another example (again from the standard library documentation), JSON documentation shows an Exception class (which is indeed in an exceptions.rb file, albeit in the source at json/lib/json/add/exceptions.rb). The point here is that it's inconsistent; the documentation for the Exception class is not listed in a way similar to that of Net::HTTPException.

Moreover, in documentation for most methods there is no indication of the exception that may be raised. Ref for example parse, one of the most-used methods of the JSON module already mentioned: exceptions aren't mentioned at all.

The lack of standard and consistency is also found in core modules. Documentation for Math doesn't contain any reference to an exceptions.rb file. Same with File, and its parent IO.

And so on, and so on.

A web search will turn up lots of information on how to rescue exceptions, and even multiple types of exceptions (ref here, here, here, here, etc). However, none of these indicate an answer to your questions of what is the standard for finding exceptions that can be raised, and where is the documentation for this.

As a final note, it has been suggested here that if all else fails you can rescue StandardError. This is a less-than-ideal practice in many cases (ref this SO answer), although I'm assuming you already understand this based on your familiarity with Java and the way you've asked this question. And of course coming from a Java world, you'll need to remember to rescue StandardError and not Exception.

Reviere answered 5/5, 2020 at 11:57 Comment(1)
fwiw i'm adding this answer because i've also been wondering the same question, coming from a .NET background (similar to Java), and I've come across the same frustration writing Ruby code on the sideReviere

© 2022 - 2024 — McMap. All rights reserved.