How to deal with not knowing what exceptions can be raised by a library method in Ruby? - ruby

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.)

(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.

Should you want to discard non valid JSON data:
begin
res = JSON.parse(string)
rescue JSON::ParserError => e
# string was not valid
end

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

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.

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.

Related

What does Rubinius.primitive do?

I'm reading through the Rubinius source code, and I keep coming across methods that go something like this:
def self.do_something
Rubinius.primitive :vm_do_something
raise SomeError, "primitive failed to do something"
end
For example, kernel/alpha.rb and kernel/bootstrap/rubinius.rb both have a lot of these. They're all over the place, and I can't seem to find where Rubinius.primitive is defined.
Since I have no idea what it does, I'm having a lot of trouble understanding how Rubinius gets stuff done.
I went on IRC at freenode.net #rubinius, and learned that the behavior of Rubinius.primitive is to replace the method it's called in with a call to C++ code. The calls to raise that commonly follow calls to primitive are only executed if primitive somehow fails.

Cutting off from backtrace the steps coming from particular libraries

Sometimes, we use libraries that are pretty much well debugged and are usually not a cause of an error. Still, these libraries can return errors due to our misuse of their API. In such case, the steps internal to these libraries show up within the backtrace of an error, which are just garbage from the point of view of the programmers using the library, and make it difficult to spot the cause of the error. Even some methods in the core Ruby insert some internal steps into the backtrace. For example, whenever you see a backtrace involving Enumerable#inject, there is always Enumerable#each being called from it, which shows up in the backtrace and is annoying.
What is a good way to remove from the backtrace the steps internal to certain given libraries? I am currently dong it by parsing the backtrace and filtering it by the file name. Is there a better way to do it?
When you are writing a library by yourself, is there a good way to suppress the internal steps appearing in a backtrace involving a method call that uses the library? An obvious way might be to insert a pair of rescue and raise for every method that is to be used from outside of the library, but that does not seem right.
Well...
There isn't really a better way to filter. If you can get the full filepath for the backtrace, though, you can filter by directory which can rule out all stdlibs and gems. Beyond that, it's more trouble than it's worth.
There is a much better solution for this. However, it requires that you catch all exception thrown by Ruby in your library, and then rethrow them after doing this (also do this to all your own excpetions). So wrap all your method with this:
begin
...
rescue Exception
e = $!
e.set_backtrace(caller(nesting_level))
raise e
end
The nesting_level is how many methods of this library the current method was called from. If it was called directly from user code, put 0. If it was called by one method that was called in user code, put in 1, and so on.

Asserting that a particular exception is thrown in Cucumber

Scenario
I'm writing a library (no Ruby on Rails) for which I'd like to have very detailed Cucumber features. This especially includes describing errors/exceptions that should be thrown in various cases.
Example
The most intuitive way to write the Cucumber steps would probably be something like
When I do something unwanted
Then an "ArgumentError" should be thrown
Problem
There are two issues I have to address:
The first step should not fail when an exception is thrown.
The exception that the first step throws should be accessible to the second step in order to do some assertion magic.
Unelegant And Cumbersome Solution
The best approach I've been able to come up with is caching the exception in the first step and putting it into an instance variable that the second step can access, like so:
When /^I do something unwanted$/ do
begin
throw_an_exception!
rescue => #error
end
end
Then /^an "(.*)" should be thrown$/ do |error|
#error.class.to_s.should == error
end
However, this makes the first step more or less useless in cases where I don't want it to fail, and it requires an instance variable, which is never a good thing.
So, can anyone help me out with an at least less cumbersome solution? Or should I write my features differently anyway? Any help would be much appreciated.
I thought about it once more, and maybe the answer is:
There is no elegant solution, because the Given-When-Then-Scheme is violated in your case.
You expect that "Then an exception should be thrown" is the outcome of "When I do something unwanted".
But when you think about it, this is not true! The exception is not the outcome of this action, in fact the exception just shows that the "When"-Statement failed.
My solution to this would be to test at a higher level:
When I do something unwanted
Then an error should be logged
or
When I do something unwanted
Then the user should get an error message
or
When I do something unwanted
Then the program should be locked in state "error"
or a combination of these.
Then you would "cache the exception" in your program - which makes perfect sense, as you most likely need to do that anyway.
The two problems you've stated would be solved, too.
In case you really must test for exceptions
Well, i guess then cucumber isn't the right test suite, hmm? ;-)
As the Given-When-Then-Scheme is violated anyway, I would simply write
When I do something unwanted it should fail with "ArgumentError"
and in the step definitions something like (untested, please correct me if you try it)
When /^I do something unwanted it should fail with "(.*)"$/ do |errorstring|
expect {
throw_an_exception!
}.to raise_error(errorstring)
end
As said above, that is horribly wrong as the scheme is broken, but it would serve the purpose, wouldn't it? ;-)
You'll find further documentation at testing errors at rspec expectations.
One option is to mark the scenario with #allow-rescue and check the page's output and status code. For example
In my_steps.rb
Then(/^the page (?:should have|has) content (.+)$/) do |content|
expect(page).to have_content(content)
end
Then(/^the page should have status code (\d+)$/) do |status_code|
expect(page.status_code.to_s).to eq(status_code)
end
Then /^I should see an error$/ do
expect(400..599).to include(page.status_code)
end
In my_feature.feature
#allow-rescue
Scenario: Make sure user can't do XYZ
Given some prerequisite
When I do something unwanted
Then the page should have content Routing Error
And the page should have status code 404
or alternatively:
#allow-rescue
Scenario: Make sure user can't do XYZ
Given some prerequisite
When I do something unwanted
Then I should see an error
This may not be exactly what you were hoping for, but it might be an acceptable workaround for some people who come across this page. I think it will depend on the type of exception, since if the exception is not rescued at any level then the scenario will still fail. I have used this approach mostly for routing errors so far, which has worked fine.
It is possible to raise an exception in a When block and then make assertions about it in the following Then blocks.
Using your example:
When /^I do something unwanted$/ do
#result = -> { throw_an_exception! }
end
Then /^an "(.*)" should be thrown$/ do |error|
expect{ #result.call }.to raise_error(error)
end
That example uses RSpec's matchers but the important part is the -> (Lambda); which allows the reference to the throw_an_exception! method to be passed around.
I hope that helps!
I'm answering from the perspective of someone who uses Cucumber features in a Behavior-Driven Development situation, so take it or leave it...
Scenarios should be written to test a 'feature' or functionality of the application, as opposed to being used to test the code itself. An example being:
When the service is invoked
Then a success code should be returned
It sounds like your test case (i.e. If I do this, then this exception should be thrown) is a candidate for unit or integration testing - in my case, we would use some Mocking or unit testing framework.
My suggestion would be to re-evaluate your feature scenarios to see if they are really testing what you intend them to test. From personal experience, I've found that if my test classes are becoming abnormally complex, then my features are 'wrong.'

Where are catch and throw useful in Ruby?

I really don't see a sane use for these. There is already rescue and raise, so why the need for throw and catch? It seems they are supposed to be used to jump out of deep nesting, but that just smells like a goto to me. Are there any examples of good, clean use for these?
Note: It looks like a few things have changed with catch/throw in 1.9. This answer applies to Ruby 1.9.
A big difference is that you can throw anything, not just things that are derived from StandardError, unlike raise. Something silly like this is legal, for example:
throw Customer.new
but it's not terribly meaningful. But you can't do:
irb(main):003:0> raise Customer.new
TypeError: exception class/object expected
from (irb):3:in `raise'
from (irb):3
from /usr/local/bin/irb:12:in `<main>'
They can be really useful in simplifying DSLs for end users by passing control out of the DSL without the need for complex case / if statements
I have a Ruby app which allows users to extend it via an internal DSL. Some of the functions in the DSL need to return control to specific parts of my application. Let's take a simple example. Suppose the user is developing a simple extension concerning dates
if today is a holiday then
do nothing
end
week_of_year = today.week.number
if week_of_year < 10 then
...
The do nothing bit triggers a throw which passes control out of the exec statement and back to me.
Rather than continuing to execute the DSL, on some condition, we want it to exit and hand control back to my application. Now you could get the user to use lots of embedded if statements and have the DSL end naturally but that just obscures what the logic is trying to say.
Throw really is a goto which is 'considered dangerous' but damn it sometimes they are the best solution.
It's basically a goto, and slightly more akin to a call/cc, except that the control flow is wired up implicitly by name instead of explicitly as a parameter. The difference between throw/catch and raise/rescue is that the former is intended to be used for control flow instead of only exceptional situations, and it doesn't waste time putting together a stack trace.
Sinatra uses throw/catch for HTTP error codes, where a handler can use throw to cede control to the Sinatra library in a structured way. Other sorts of HTTP frameworks use exceptions, or by returning a different class of response, but this lets Sinatra (for example) try another request handler after catching it.
The difference between the two is that you can only 'raise' exceptions but can 'throw' anything (1.9). Other than that, they should be interchangeable, that is, it should be possible to rewrite one with another, just like the example given by #john-feminella.

Is it idiomatic Ruby to add an assert( ) method to Ruby's Kernel class?

I'm expanding my Ruby understanding by coding an equivalent of Kent Beck's xUnit in Ruby. Python (which Kent writes in) has an assert() method in the language which is used extensively. Ruby does not. I think it should be easy to add this but is Kernel the right place to put it?
BTW, I know of the existence of the various Unit frameworks in Ruby - this is an exercise to learn the Ruby idioms, rather than to "get something done".
No it's not a best practice. The best analogy to assert() in Ruby is just raising
raise "This is wrong" unless expr
and you can implement your own exceptions if you want to provide for more specific exception handling
I think it is totally valid to use asserts in Ruby. But you are mentioning two different things:
xUnit frameworks use assert methods for checking your tests expectations. They are intended to be used in your test code, not in your application code.
Some languages like C, Java or Python, include an assert construction intended to be used inside the code of your programs, to check assumptions you make about their integrity. These checks are built inside the code itself. They are not a test-time utility, but a development-time one.
I recently wrote solid_assert: a little Ruby library implementing a Ruby assertion utility and also a post in my blog explaining its motivation. It lets you write expressions in the form:
assert some_string != "some value"
assert clients.empty?, "Isn't the clients list empty?"
invariant "Lists with different sizes?" do
one_variable = calculate_some_value
other_variable = calculate_some_other_value
one_variable > other_variable
end
And they can be deactivated, so assert and invariant get evaluated as empty statements. This let you avoid performance problems in production. But note that The Pragmatic Programmer: from journeyman to master recommends against deactivating them. You should only deactivate them if they really affect the performance.
Regarding the answer saying that the idiomatic Ruby way is using a normal raise statement, I think it lacks expressivity. One of the golden rules of assertive programming is not using assertions for normal exception handling. They are two completely different things. If you use the same syntax for the two of them, I think your code will be more obscure. And of course you lose the capability of deactivating them.
Some widely-regarded books that dedicate whole sections to assertions and recommend their use:
The Pragmatic Programmer: from Journeyman to Master by Andrew Hunt and David Thomas
Code Complete: A Practical Handbook of Software Construction by Steve McConnell
Writing Solid Code by Steve Maguire
Programming with
assertions
is an article that illustrates well what assertive programming is about and
when to use it (it is based in Java, but the concepts apply to any
language).
What's your reason for adding the assert method to the Kernel module? Why not just use another module called Assertions or something?
Like this:
module Assertions
def assert(param)
# do something with param
end
# define more assertions here
end
If you really need your assertions to be available everywhere do something like this:
class Object
include Assertions
end
Disclaimer: I didn't test the code but in principle I would do it like this.
It's not especially idiomatic, but I think it's a good idea. Especially if done like this:
def assert(msg=nil)
if DEBUG
raise msg || "Assertion failed!" unless yield
end
end
That way there's no impact if you decide not to run with DEBUG (or some other convenient switch, I've used Kernel.do_assert in the past) set.
My understanding is that you're writing your own testing suite as a way of becoming more familiar with Ruby. So while Test::Unit might be useful as a guide, it's probably not what you're looking for (because it's already done the job).
That said, python's assert is (to me, at least), more analogous to C's assert(3). It's not specifically designed for unit-tests, rather to catch cases where "this should never happen".
How Ruby's built-in unit tests tend to view the problem, then, is that each individual test case class is a subclass of TestCase, and that includes an "assert" statement which checks the validity of what was passed to it and records it for reporting.

Resources