I am new to Ruby. What I understood from below code that a New class MyClass is created with in the ABC module. What #1 to #4 is doing. Is this throwing different exceptions which is a subtype of CommonError?
class ABC::MyClass
class AException < CommonError; end #1
class BException < CommonError; end #2
class CFailure < CommonError; end #3
class DException < CommonError; end #4
include ABC::Something
# ::::::::::::::::::::::::::::::::::::
end
class CommonError < Exception
end
That's just defining specific exceptions that can, presumably, be used within the code somewhere else, as in:
raise AException, "Something went wrong!"
This means you can rescue those later:
begin
do_stuff!
rescue AException => e
puts "Uh oh, AException went off! Those are super bad!"
puts e # The message supplied in the raise call
end
The reason for CommonError is to act as a base-class for all these other exceptions. The argument to rescue is actually not a specific class, but a class and all subclasses, so if you rescue CommonError you get to capture all of these and potentially others defined elsewhere.
Related
I am relatively new to ruby and I am stuck with this problem which is rather hard to solve.
What I want to achieve is that I could catch custom errors which I throw from the sub class in a parent class. Given an example below, how could I make the parent class to understand the RequestTimeout class? Because, now when I run the code it results to a following output:
test_raise.rb:5:in `rescue in handle_errors': uninitialized constant BaseService::RequestTimeout (NameError)
from test_raise.rb:4:in `handle_errors'
from test_raise.rb:14:in `first_service_method'
from test_raise.rb:31:in `<main>'
The code:
class BaseService
def handle_errors
yield
rescue RequestTimeout => e # <-- the problem
p e.message
end
end
class FirstService < BaseService
class RequestTimeout < StandardError; end
def first_service_method
handle_errors do
raise RequestTimeout, "FirstService RequestTimeout"
end
end
end
class SecondService < BaseService
class RequestTimeout < StandardError; end
def second_service_method
handle_errors do
raise RequestTimeout, "SecondService RequestTimeout"
end
end
end
a = FirstService.new
a.first_service_method
Ofc. I could solve the problem by changing:
rescue RequestTimeout => e
to:
rescue => e
But I dont want to do that because I wan't to catch multiple exceptions (more than RequestTimeout) which are defined and raised by me. Any help would be awesome!
There is an option to move
class RequestTimeout < StandardError; end
declaration into the base class. It hence will become available to all children.
Whether you have different exceptions for different child classes, you are forced to use namespaces, as #Marek said in sibling comment.
The problem is about namespaces - RequestTimeout is defined in different namespace than BaseService. You should have:
rescue FirstService::RequestTimeout => e
I am trying to create an instance of an inner class in the outer class in Ruby, in the following way,
myclass.rb
require 'mylibs'
class myClass
class ClientNotInitializedError < StandardError
end
def myMethod
if not #client raise ClientNotInitializedError.new
#do stuff
end
end
However this is failing in build where I am trying to throw the Exception. What am I doing wrong?
I tried things like self.ClientNotInitializedError.new and self::ClientNotInitializedError.new but still no luck.
The ClientNotInitializedError is very specific to this class so I would like to keep it inside the class or at least in the same file.
I've tried to run your code and got several mistakes:
a) Class names must ALWAYS begin with a capital letter (else you'll get the error: class/module name must be CONSTANT (SyntaxError))
b) You don't have a closing end block for your if statement where you're raising the error. This should work:
class MyClass
class ClientNotInitializedError < StandardError; end
def my_method
raise ClientNotInitializedError.new unless #client
#do stuff
end
end
MyClass.new.my_method #=> will raise the appropriate error
I recommend you familiarize yourself with Ruby's naming conventions.
Here's what I'm trying to do:
class Foo
def foo
raise "lol noob"
end
# ... many other methods here ...
rescue StandardError => e
puts "error caught: #{e}"
end
Foo.new.foo
RuntimeError: lol noob
from (pry):45:in `foo'
As you can see, this does not work.
What I'm trying to avoid is to put a rescue block into every single method, given that they're many. Is it possible? If not, what's the best practice?
TL;DR
In Ruby, you generally have to wrap the caller with rescue, rather than the receiver.
Explanation
It's likely that you're finding this behavior surprising because you're not thinking of classes as executable code. A rescue clause in a class definition will capture exceptions raised while the class is being interpreted. Consider the following example:
class Foo
raise 'bar'
rescue
'Rescued!'
end
#=> "Rescued!"
Here, the rescue clause works because the exception is raised while the class code is executing. However, some Foo#bar method wouldn't normally get rescued by this clause (except possibly while being defined) because Foo is no longer the caller, it's the receiver.
A rescue clause on the class will catch exceptions raised when the class itself is being defined. However, to rescue within a method at run-time, you need to rescue within the caller (in this case, the #bar method) as follows:
class Foo
def bar
raise 'method exception'
rescue
'Rescued method exception.'
end
end
Foo.new.bar
#=> "Rescued method exception."
It would make no sense to have a common rescue block for a class, each method does different things right? How would you handle the variety of errors all in the same way? Error handling is just as much part of the logic as the "main" part of the method(s).
There's no silver bullet here, you rescue where you need to, and do what is needed when it is needed.
The Exceptional Ruby book may be of interest if you want to learn some common best practices.
If you're absolutely sure that the only error handling you need to do is log out errors, you can abstract away some of the repetitive error logging by defining a helper method that takes in a block and do your error handling there.
For example,
class Foo
def foo
handle_exception do
raise "lol noob"
end
end
def bar
handle_exception do
raise "rofl"
end
end
def handle_exception
yield
rescue => e
puts "error caught: #{e}"
end
end
Foo.new.foo # error caught: lol noob
Foo.new.bar # error caught: rofl
This has the benefit that later on you decide that want some alternate behavior, ie adding in a backtrace, you only have to touch one line of code:
def handle_exception
yield
rescue => e
puts "error caught: #{e}\n#{e.backtrace.join("\n")}"
end
We can put a class or module after a rescue statement, but in the code below, I see a method following rescue, which does not fit into this pattern. How is it working and how is it producing the output it has been designed to show?
def errors_with_message(pattern)
# Generate an anonymous "matcher module" with a custom threequals
m = Module.new
(class << m; self; end).instance_eval do
define_method(:===) do |e|
pattern === e.message
end
end
m
end
puts "About to raise"
begin
raise "Timeout while reading from socket"
rescue errors_with_message(/socket/)
puts "Ignoring socket error"
end
puts "Continuing..."
Output
About to raise
Ignoring socket error
Continuing...
Rescue requires a class or a module, true. So, that method creates an anonymous module with special behaviour. You see, when rescue searches for a handler, it applies === operator to exception classes/modules you provided, passing as an argument the actual exception.
begin
# do something
rescue MyCustomError
# process your error
rescue StandardError
# process standard error
end
So, if StandardError (or one of its descendants) was raised, the first handler will be skipped and second handler will be matched.
Now, the module from errors_with_message is special. It redefines threequals operator to match on exception message. So, if an error was raised and its message contains word "socket", this handler will match. Cool trick, huh?
I have seen Ruby code that raises exceptions using a class:
raise GoatException, "Maximum of 3 goats per bumper car."
Other code uses an instance:
raise GoatException.new "No leotard found suitable for goat."
Both of these are rescued the same way. Is there any reason to use an instance vs a class?
It makes no difference; the exception class will be instiantiated in either case.
If you provide a string, either as the argument to new or as the second argument to raise, it be passed to initialize and will become the exception instance's .message.
For example:
class GoatException < StandardError
def initialize(message)
puts "initializing with message: #{message}"
super
end
end
begin
raise GoatException.new "Goats do not enjoy origami." #--|
# | Equivilents
raise GoatException, "Goats do not enjoy origami." #--|
rescue Exception => e
puts "Goat exception! The class is '#{e.class}'. Message is '#{e.message}'"
end
If you comment the first raise above, you'll see that:
In both cases, initialize is called.
In both cases, the exception class is GoatException, not class as it would be if we were rescuing the exception class itself.