This article provides a quick introduction to Ruby and compares Ruby to Ruby on Rails. It continues by highlighting the distinctions between debugging and troubleshooting. The Ruby debugger itself will be discussed, along with other debugging techniques. Then it discusses troubleshooting advice and the several approaches Ruby developers might use to manage errors.
To start off, let’s brush up our memories on the Ruby programming language.
Ruby is an object-oriented scripting language, making it robust to quickly build scalable applications. It is open-source, dynamic-typed, and considered the developer’s delight due to the fact that it embraces concepts from different languages and provides a wide range of options to developers.
To get things clear, the popular Ruby on Rails, which is an open-source web development framework built upon the Ruby programming language, should not be mistaken for Ruby. While the latter is a full-fledged programming language which has found its use in the development of desktop applications and server-side scripting, the former is preferred for building web applications wherein Ruby on Rails has been said to speed up the development process and simplify code.
While this is not a rigid approach, it is worth it to make an informed decision on which to choose before starting application development.
It might seem obvious as we go through this article that troubleshooting is only necessary when an issue or fault is present, but there are key distinctions between troubleshooting and debugging.
Debugging seeks to identify and correct faults in a particular application rather than a system or program as a whole. Troubleshooting, on the other hand, entails the detection of problems connected to computer code in a system or software.
The standard Ruby distribution comes with a debugger. To activate the debugger after Ruby installation, type into the command line;
1
2
3
4
-r debug //What this does is load the debugger library and then run the code to ask for user input
-
r debug filename[, ...]
The user then inputs the filename to be debugged.
The debugger comes with an in-built set of commands, some of which include;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
b[reak][ < file | class >: ] < line | method >
//this command sets breakpoints. Breakpoints are where you pause program execution so that debugging can start.
del[ete][n]
//this command deletes breakpoints.
up[n]
//this command moves up n level in the stack frame.
down[n]
//this command moves down n level in the stack frame.
fin[ish]
//this command finishes the running of the present method.
q[uit]
//this command closes the debugger.
v[ar] g[lobal]
//this command displays the global variable.
v[ar] l[ocal]
//this command displays the local variable.
h[elp]
//this command displays a help message.
This is not an exhaustive list of the debugger commands available.
Note: It is not compulsory to use the complete keywords in the square brackets[].
Let’s say there is a file welcome.rb
that needs to be debugged;
1
2
3
4
5
6
7
8
9
10
11
class Welcome
def initialize(welcome)
@welcome = welcome
end
def welcome
@welcome
end
end
salute = Welcome.new("Welcome, Lee!")
puts salute.welcome
To use the debugger, in the command terminal after the file input prompt has been received, type;
ruby -r debug welcome.rb
Once the execution gets to the debug command, a debugging prompt will be received.
The following advice might be helpful when trying to solve problems because troubleshooting can be a highly time-consuming and almost necessary activity.
Verify that the operating system, browser, or framework, as applicable, supports the different libraries, development/testing/staging/production environments, and components.
Below is a comparison of a few web frameworks and their respective Ruby versions:
Ruby on Rails is supported by Ruby version 3.2 or greater
Cuba is supported by Ruby version 3.0.0 or greater
Rails API is supported by Ruby version 0.4.0 or greater
Padrino is supported by Ruby version 0.12.0 or greater
Roda is supported by Ruby version 2.0.0 or greater
Rack is supported by Ruby version 1.4.5 or greater
Rails LT is supported by Ruby version 2.3 or greater
Sinatra is supported by Ruby version 1.1.4 or greater
Ensure that you are in control of the logging output and environment variables - especially true for Rails applications. This is essential to enable a controlled and more concise output. This can be achieved through the creation of configuration files that will be ready for installation along with the Ruby application.
Below are a few common environment configuration settings;
errors_enabled
- This is an optional setting that states whether error monitoring should be enabled or not. This is set to false by default and changing its value affects the application in no way.
log_level
- Also an optional setting that states the log level of a program. The various log levels that exist include error, log, debug, trace, info, fatal, and off, amongst others, are associated with their respective log messages.
These log levels have a fixed value associated with them.
monitor
- An optional setting that states if monitoring should be enabled or not.
These are a few of the configuration settings that can be enabled to ensure that the full control of logging and environment variables are traced easily.
Ensure that the installation steps were followed correctly. Do not download the wrong distribution to the wrong operating system. Likewise, ensure that the libraries, frameworks, and environment are compatible with the Ruby version to be used.
Various errors have techniques for troubleshooting them. Below are some errors in Ruby and ways to troubleshoot them.
To understand errors in Ruby, an understanding of exceptions is important.
What are exceptions in Ruby?
Exceptions are used to take charge of unwanted or unplanned errors during the execution of a program in Ruby. It is Ruby’s own internal control mechanism to handle programs that are not going the planned way. On the other hand, it tells us how to go about these failures in execution instead of terminating the program. This is pretty much the norm with other programming languages.
In other words, error handling is what comes to mind in exceptions, i.e., how do I tackle this error? Instead of - Oops! What to do, my program stopped?, that is likely going to be the case if there are no exceptions.
With Ruby being an object-oriented language, Exception takes the structure of a class which also has subclasses thereby creating a hierarchy. Below are the subclasses of Exception, some of which also have subclasses.
NoMemoryError
is raised anytime memory allocation fails. It means that the system tried to allocate more than is available for Ruby, leading to this error. It has no subclasses and is a direct descendant of the exception class.
ScriptError
is raised when at runtime a program fails to execute as expected, which could be due to a wrong file path or even syntax error. It has subclasses which include LoadError, NotImplementedError and SyntaxError
SecurityError
is raised when the program tries to run a potentially unsafe code. This is a direct descendant of the exception class.
SignalException
is raised when Ruby receives a signal while watching a program. It has interrupt as its subclass.
StandardError
is the most common type of error and is raised when the exception class is not specified to catch an error. It has the following subclasses; ArgumentError
, UncaughtThrowError
, EncodingError
, CompatibilityError
, ConverterNotFoundError
, InvalidByteSequenceError
, UndefinedConversionError
, FiberError
, IOError
, EOFError
, IndexError
, KeyError
, StopIteration
, LocalJumpError
, NameError
, NoMethodError
, RangeError
, FloatDomainError
, RegexpError
,RuntimeError
, SystemCallError
, ThreadError
, TypeError
, ZeroDivisionError
, and some others.
SystemExit
is raised to stop the execution of a Ruby program.
SystemStackError
is raised when all the available space in the stack has been used up.
fatal
is raised internally by Ruby when it encounters a fatal error and must terminate the program.
To tell Ruby to handle a type of exception, the following methods can be used;
The scope of the code that is needed to raise an exception starts with a begin and is closed with an end clause. Then rescue is used to declare the type of exception to be handled. See the example below;
1 2 3 4 5 6 7 8 9 10 11
begin # - line of code rescue IncludeATypeOfException # - line of code rescue IncludeAnotherTypeOfException # - line of code else # Other exceptions ensure # Always will be executed end
Note: If the exception does not match any of the error types by the parameters in the code block, the else statement can be used after the rescue clauses.
The scope of the code that is needed to raise an exception starts with a begin and is closed with an end clause. Raise is then used to call an exception whenever it is needed. See the example below;
1 2 3 4 5 6 7 8 9 10 11 12 13 14
raise OR raise "Error Message" OR raise ExceptionType, "Error Message" OR raise ExceptionType, "Error Message" condition
Any of the raise statements could be used.
Note: the first one calls the current exception if any is present at the moment. The second one creates an exception with a custom error message in the string parameter.
The third one creates an exception with the first parameter and then sets its custom message to the second parameter. And the fourth one is much like the third one but allows for conditional statements.
Used hand in hand. Catch defines a block of code that is labeled with a given name and would run only when a throw is encountered. See the example below;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
throw: labelname
# - this will not be executed
catch: labelname do
# - matching
catch
will be executed after a
throw is encountered.
end
The exception class - the various subclasses has been mentioned above.See example;
Defining the error normally in Ruby
class FileLoadError < StandardError
attr_reader: thecause
def initialize(thecause)
@thecause = thecause
end
end
Using the Exception
1
2
3
4
5
6
7
8
File.open(path, "w") do | file |
begin
# the code
rescue
# Oops, something went wrong!
raise FileLoadError.new($!)
end
end
There are more methods for handling exceptions, some of which even include the usage of libraries, therefore this list is not all-inclusive.
In conclusion, there are several ways to troubleshoot in Ruby. The debugger is a fantastic tool for handling various faults, but it might not be able to solve every problem. To debug our Ruby applications in the most effective way possible, it is crucial to be aware of the many sources and causes of problems in our software.