Objectives
- Understand how to debug syntax errors.
- Understand the concept of error handling.
- Raise exceptions.
- Properly format code.
Some terminology:
- When something goes wrong in code, the interpreter will raise an error.
- If you predict that error ahead of time, you can determine how that error is handled by rescuing it and then specifying the behavior to follow.
Ruby doesn't care much about whitespace. An exception to that is if the whitespace is included within a string.
- Best Practices:
- The definition is right against the left margin of the box.
- The scope defined by the method is indented 2 spaces (1 tab) from where our definition began.
- If we defined a scope inside our method, its contents would be indented 2 spaces from where our new scope was defined and not 2 spaces from where our
print_number
method was defined. - For example:
def print_number(num)
p "You are printing the number #{num}"
if num < 0
p "Don't be so negative."
end
p "back outside"
end
Some methods behave incorrectly without raising errors. Create another example by writing a method that uses a birthday date as an argument. The method should return the day of the week that the birthday will fall on in the coming year
require 'date' # Makes Ruby's date library available to our code
def next_birthday(birthday)
a_year_off = birthday.next_year
a_year_off.strftime("%D")
end
next_birthday(Date.new(2017, 6, 1))
- This method returns: "06/01/18", so it returned the next year's date, the first of June 2018, but not the day of the week. Where did we go wrong?
- Break this method down:
- We defined a
next_birthday
method that uses one argument,birthday
. - Within the method, we assigned the value of
birthday.next_year
to a variable calleda_year_off
- We called
strftime("D%")
ona_year_off
.
- We defined a
- The method finds the correct date, but returns a string representing the whole date, not the word represetning the day of the week.
- We can assume that
next_date
is working correctly and our problem is likely the next line of code. - We're assigning the correct value to the variable
a_year_off
, but failing to convert that value to the desired string. - We've narrowed the problem down to the
strftime
method.
- We can assume that
- Now that we're relatively confident about what's wrong, let's review the Ruby Docs on the
strftime
method, which we suspect we're using incorrectly.- We need to pass the formatting string
%A
instead of%D
- We need to pass the formatting string
Means following your code from the top as if you were the computer. When the program fails, the programmer can understand what happened by looking at the incomplete list of instructions and "executing" them in their mind, on at a time.
When you're "playing computer", you can get the computer to help you follow the code.
- For example:
def add_four(num)
num + 4
end
- Imagine that we’re calling that method with another variable as the argument
- Something like
result = add_four(counter)
- Something like
- But when we run the code, we’re surprised by the value of the result, because we might have assumed that the value of
counter
was 5, we expected to get 9 back in the result. Since the code looks fine, we’re confused. - All the bugs in code come from assumptions. The hard part is figuring out what the assumption is. What if the value of counter was -1, but we were pretty sure it would be 5?
- A way to help us check our assumption about the value of counter is to simply print it out while the code is running:
def add_four(num)
puts num
num + 4
end
- Adding
p
orputs
lines is a way to trace how your program is running. - Be sure to remove them when you're done with them.
- Tip: Don't indent those lines at all so that they attract your attention and you'll be eager to remove them.
When a program raises and exception, it can crash the application if it's not handled. If you anticipate the possibility of an operation causing an error, you can wrap it in a rescue
block.
- Take a look at this
hello
method:
def hello(name)
"Hello #{name}"
end
- If you call this method with 2 arguments instead of 1, you'll get an
ArgumentError
and the application will crash. - Prevent that crash by calling the method inside a rescue block.
begin
hello("George", "Washington")
rescue
p "An error was raised but rescue prevented a crash!"
end
begin
keyword starts our block- The code we want to execute is nested inside.
rescue
keyword can be caclled with a specific type of of error that we'd like to rescue from.- In this case, not passing anything will raise a
StandardError
that can catch any type of error. - Anything we want to do after the error is "rescued" would be nested here.
- In this case, not passing anything will raise a
Exercises
NoMethodError
NoMethodError: undefined method `hello` for main:Object
Specs:
Method:
NameError
Specs:
Method:
Wrong Number of Arguments
Specs:
Method:
TypeError
Specs:
Method:
Unexpected end
end
is one type of syntax error, but there are others where we might have a missing quotation mark, or a missing closing parenthesis.Specs:
Method: