1

Ruby newbie here.

I'm trying to write a very simple calculator where I store the numbers in variables and check if the user input for the operator is included in the array of possible operators, if it is then it should perform the calculation using those variables

Is there a way I can get the result from combining theses 3 variables? Right now is throwing me the error "String can't be coerced into Integer"

puts "enter a number!"
num1 = gets.chomp().to_i
puts "enter an operator!"
op = gets.chomp()
puts "enter another number"
num2 = gets.chomp().to_i
operators = ["+", "*", "-", "/"]
result = nil

if operators.include?(op)
  result =  num1 + "#{op}" + num2
else
  puts "enter a valid operator"
end

puts result
anothermh
  • 9,815
  • 3
  • 33
  • 52
  • Not quite sure what you mean by "combining". What's your expected result for `num1 = 1`, `op = "+"` and `num2 = 2`? The string `"1+2"` or the integer `3`? – Stefan Jul 14 '20 at 11:27

3 Answers3

2

You could use public_send

num1.public_send(op, num2)

https://apidock.com/ruby/Object/public_send

But a more clear approach would be to just use if / else statements.

if op == "+"
  num1 + num2
elsif op == "-"
  num1 - num2
elsif op == "*"
  num1 * num2
elsif op == "/"
  num1 / num2
end
  • Instead of `if` / `elsif` you can use a [`case` expression](https://ruby-doc.org/core-2.7.1/doc/syntax/control_expressions_rdoc.html#label-case+Expression) to avoid repeating the comparison. – Stefan Jul 14 '20 at 11:22
2

Let's break down your example into something a little more simple:

num1 = 1
num2 = 2
op = '+'
result = num1 + op + num2

When you attempt to assign result, here's what's actually happening:

result = 1 + '+' + 2

Ruby reports String can't be coerced into Integer because it is attempting to add the string + to the integer 1 and Ruby can't add a string to an integer. You can read more about this at String can't be coerced into Fixnum (TypeError).

You can reproduce it with an even simpler example:

1 + '+'
TypeError: String can't be coerced into Integer

In your question you say it should perform the calculation using those variables so I am assuming that you expect result to be equal to 3. (because it should calculate 1 + 2 from the three variables) That's not what happens in your result = ... line for the reasons described above.

The proper way to do this is to use public_send as described in these other questions and answers here on Stack Overflow:

Thus the answer is:

num1.public_send(op, num2)
=> 3

And integrated into your example:

if operators.include?(op)
  result = num1.public_send(op, num2)
else
  puts "enter a valid operator"
end
anothermh
  • 9,815
  • 3
  • 33
  • 52
1

Use the Object#send Method

Your current code isn't working because you're trying to append op, which is currently a String, to an Integer. What you actually want to do is invoke the method by sending the appropriate message to the first Integer, with the second number passed as an argument to the method. You could do this with Object#send as follows:

print "Enter a number: "
num1 = Integer gets

loop do
  print "Enter an operator: "
  op = gets.strip
  break if %w[+ - / *].include? op
end

print "Enter another number: "
num2 = Integer gets

p num1.send(op, num2)

Other modifications and refactorings aside, it's the use of #send that allows this approach to work. There are certainly plenty of other ways to represent what you're trying to do, but this one certainly works.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199