Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions calculator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# The program should use the input operation and two numbers
# to provide the result of applying the operation to the two numbers

# The program should have support for these four operations: addition,
# subtraction, multiplication, and division

# The program should accept both the name (add) and the symbol
# (+) for each possible operation

# The program should handle unexpected user input

# Print operators options method
def print_operator_options()
puts "1. add(+)"
puts "2. subtract(-)"
puts "3. multiply(*)"
puts "4. divide(/)"
puts "5. modulo(%)"
puts "6. exponential(^)"
puts
end


# Addition method
def add_numbers(num1, num2)
return num1 + num2
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that you've broken each of these operations out as its own method, and that you're returning a value rather than putsing it here.


# Subtraction method
def subtract_numbers(num1, num2)
return num1 - num2
end

# Multiplication method
def multiply_numbers(num1, num2)
return num1 * num2
end

# Division method
def divide_numbers(num1, num2)
return num1 / num2
end

# Modulo method
def modulo_numbers(num1, num2)
integer_division = (num1 / num2) * num2
return num1 - integer_division
end

# Exponential method
def raise_number_to_power(num1, num2)
return num1 ** num2
end

# Welcome message, ask user for operator (name or symbol)
puts
puts "Welcome to the Calculator program! Which operator would you like to use? "
print_operator_options()

print "Please choose one operator(name or symbol): "
user_symbol = gets.chomp.strip.downcase

symbols = [
"add", "+", "subtract", "-", "multiply", "*",
"divide", "/", "modulo", "%", "exponential", "^"
]

# Check to make sure user input matches the name or symbol operators
until symbols.include?(user_symbol)
puts "Sorry, '#{user_symbol}' is an invalid input"
print "Please enter at least one operator(name or symbol): "
user_symbol = gets.chomp.strip.downcase
end

puts
puts "Thank you! Let's do some math!"
puts

print "Please enter your first number: "
first_number = gets.chomp

# Check to get digits entered from user for first number
until first_number.match?(/^(?=.*[\d])/) ||
first_number.match?(/^(?=.*[-])(?=.*[\d])/)
# '?=pat' positive lookahead assertion to check if there is at least
# one or more digits in the string (starting from beginning of line)
# including the symbol '-' to make sure negative numbers work also
puts "Hm, something went wrong..."
print "Please enter your first number: "
first_number = gets.chomp
end

first_number = first_number.to_i

# Check to get digits entered from user for second number
print "Please enter your second number: "
second_number = gets.chomp

until second_number.match?(/^(?=.*[\d])/) ||
second_number.match?(/^(?=.*[-])(?=.*[\d])/)
puts "Hm, something went wrong..."
print "Please enter your second number: "

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've written almost exactly the same code here twice, to get the first number and the second number. Could you DRY that up by putting this logic in a method?

second_number = gets.chomp
end

second_number = second_number.to_i

puts

# Output message as string, based on the symbols entered by user
case user_symbol
when "add", "+"
sum = add_numbers(first_number, second_number)
puts "#{first_number} + #{second_number} = #{sum}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code isn't repeated, but I think it would still increase readability to wrap this case/when section in a method. That would clearly delineate where it starts and ends, and make it explicit what data it needs to work. The method signature might be something like perform_calculation(op, first, second).


when "subtract", "-"
difference = subtract_numbers(first_number, second_number)
puts "#{first_number} - #{second_number} = #{difference}"

when "multiply", "*"
product = multiply_numbers(first_number, second_number)
puts "#{first_number} * #{second_number} = #{product}"

when "divide", "/"
if second_number == 0
puts "Undefined - cannot divide a number by zero"
else

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you put this division-specific error handling code in the division method?

quotient = divide_numbers(first_number, second_number)
puts "#{first_number} / #{second_number} = #{quotient}"
end

when "modulo", "%"
remainder = modulo_numbers(first_number, second_number)
puts "#{first_number} % #{second_number} = #{remainder}"

when "exponential", "^"
power = raise_number_to_power(first_number, second_number)
puts "#{first_number} ^ #{second_number} = #{power}"
end

puts
puts