What does Rubinius.primitive do? - rubinius

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.

Related

Using Minitest to Test File Write

Is there a way to use minitest to mock/stub file reads and writes (text files) without actually having them existing?
the actual code is something like
def write_to_file(filename)
f = File.open(filename,"w")
f.puts "hello world"
f.close
end
I really don't know how to try something since I couldn't find any examples for mocking File IO, only comparing variables
If I were going to do what you're suggesting, I would stub File.open to return a mock like:
def test_something_that_reads_a_file
file_mock = Minitest::Mock.new
file_mock.expect(:readline, "It was the best of times...")
File.stub(:open, file_mock) do
# your test logic here
end
file_mock.verify
end
You still have the problem of returning EOF at some point, but whether that's an issue for you depends on context that I don't have given what you've written.
But there are a couple of reasons why I would probably never approach the problem like this.
Don't mock what you don't own. Yes, the semantics of File#readline are probably not going to change tomorrow, but making assumptions about an interface that's outside your control is a bad practice.
To me, this reads like a non-public method. If I'm right about that, then I wouldn't test it at all. Private methods are implementation details that don't need their own tests. If you're dead set on not doing any I/O here, I'd rather stub the result of the method rather than what I've done above.
The approach I would take would be to include a small test file and actually read from it. Your tests will be easier to understand as a result.

Is it possible to change Ruby's frozen object handling behaviour?

I am submitting solutions to Ruby puzzles on codewars.com and experimenting with how locked into the testing enviroment I am for one of the challenges.
I can redefine the classes used to test my solution but they are defined by the system after I submit my code. If I freeze these objects, the system cannot write over them but a RunTime error is raised when it tries to.
I'm fairly new to Ruby, so I'm not sure which parts (other than falsiness and truthiness) are impossible to override. Can I use Ruby code to force modification of frozen objects to silently fail instead of terminate the program or is that bound up in untouchable things like the assignment operator or similar?
The real answer here is that if you might want to modify an object later, you shouldn't freeze it. That's inherent in the whole concept of "freezing" an object. But since you asked, note that you can test whether an object is frozen with:
obj.frozen?
So if those pesky RuntimeErrors are getting you down, one solution is to use a guard clause like:
obj.do_something! if !obj.frozen?
If you want to make the guard clauses implicit, you can redefine the "problem" methods using a monkey patch:
class Array
# there are a couple other ways to do this
# read up on Ruby metaprogramming if you want to know
alias :__pop__ :pop
def pop
frozen? ? nil : __pop__
end
end
If you want your code to work seamlessly with any and all Ruby libraries/gems, adding behavior to built-in methods like this is probably a bad idea. In this case, I doubt it will cause any problems, but whenever you choose to start hacking on Ruby's core classes, you have to be ready for the possible consequences.

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.

How to deal with not knowing what exceptions can be raised by a library method in 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.

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.

Resources