1
\$\begingroup\$

I wrote the simple calculator in Ruby. This is my first program in this language. I've switched recently from Python to Ruby. What do you think about my work? Thanks

# frozen_string_literal: true
def read_number(prompt = 'Enter the number: ')
 loop do
 print prompt
 user_input = Float(gets.chomp)
 return Float(user_input)
 rescue ArgumentError
 puts 'Error: not a number.'
 end
end
loop do
 puts '*** Main menu ***'
 puts '1) Add'
 puts '2) Subtract'
 puts '3) Multiply'
 puts '4) Divide'
 puts '5) Quit'
 user_choice = read_number 'Your choice: '
 exit if user_choice == 5
 first = read_number
 last = read_number
 case user_choice
 when 1
 puts "The result is #{first + last}"
 when 2
 puts "The result is #{first - last}"
 when 3
 puts "The result is #{first * last}"
 when 4
 begin
 raise ZeroDivisionError if last.zero?
 puts "The result is #{first / last}"
 rescue ZeroDivisionError
 puts 'Error: cannot divide by zero.'
 end
 else
 puts 'Error: invalid choice.'
 end
end
asked Jul 8, 2023 at 10:12
\$\endgroup\$
2
  • \$\begingroup\$ I'm not too familiar with Ruby, but throwing an exception based on a condition (last.zero?) and directly catching it seems weird. Why not use a simple branch condition instead? \$\endgroup\$ Commented Aug 12, 2023 at 18:31
  • \$\begingroup\$ IMO, the user interface is terrible. If the user while entering the second number, changes his mind and wants to, say, multiply instead of add, or change the first number, he can't do it anymore. I would take the operations and the operand from the command line. In this way, the user can edit all input to his liking, AND the program can also be used in a non-interactive way (from a script). \$\endgroup\$ Commented Aug 26, 2024 at 12:41

1 Answer 1

1
\$\begingroup\$

Indent the when cases. You use 2 spaces - good.

case user_choice
 when 1
 puts "The result is #{first + last}"
 when 2
 puts "The result is #{first - last}"
 # ...

Using case ... else - very good. Always have a "none of the above" in every case statement. But "It will never happen" - hey! I write perfect code every time too!

Display the invalid entry to the user.


Be The User

Think about what a User can do, not what you expect or they should do.

Don't ask for the numbers after entering an invalid operation code. Users will interpret error messages in the context of what they just did. Prompting for numbers - operands - after entering, say, "8" for the operation seems like a bug. But then AFTER I enter numbers you tell me 'invalid choice'. What? You don't like the numbers I just entered? I know you mean the operator choice only because I read the code.

Show the user the invalid entry. Explain what is valid if necessary.

Keep the case ... else. No, it is not redundant.


Validating Operator Code Entry

Do this before prompting for the operands.

You can test the entry is within a Range. Read Ruby docs about Range objects. It make for nicely readable and concise code.

You can force the entry to an integer - to_i. , but maybe not second-guessing the user is better and just re-prompt. You decide. But as a general rule when comparing numbers it is best if they are the same - integer - integer, float - float.

You might assume anything NOT 1 - 4 means quit. Sure, keep "5 - Quit". Play around with it and see how it feels as a design feature of your app.


user_input = Float(gets.chomp)
return Float(user_input) # isn't this redundant? In two ways?

I mean the Float() call. Also, the following will return the number if it is the last statement in the method.

Float(gets.chomp) # explicit return not required

As a beginner keep using return explicity until you are comfortable with the idea that a method's last statement is what is returned with or without return.

Not using return is idiomatic. Ruby strives to be free of superfluous syntax and extranious verbiage.


Domain language

The domain is math. Use math-talk; "operator" and "operand". See below how that tells us what it is? Always write so the code reads as what it is about, i.e. its "domain."

# user_choice = read_number
operator = read_number 'Your choice: '
 # and ...
# first = read_number
# last = read_number
first_operand = read_number
last_operand = read_number
case operator
 # ...
 puts "The result is #{first_operand + last_operand}"
answered Jul 12, 2023 at 19:27
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.