-1

I want to make a four-functioning calculator. I tried to make methods that would store operations.

def mul
  puts num1*num2
end

def div
  puts num1/num2
end

def sub
  puts num1-num2
end

def add
  puts num1+num2
end

num1=gets.chomp.to_f
op=gets.chomp
num2=gets.chomp.to_f

puts "Multiplication=mul\n Addition=add\n Subtract=sub\n Division=div"
puts ("This is your answer"+num1+op+num2)

But I couldn't make the calculator.

I tried running the code, but it won't work. Can someone help?

sawa
  • 165,429
  • 45
  • 277
  • 381
  • Are you sure you want your function to return the value of `puts`? `puts num1+num2` might not be returning what you think it should. Does `puts num1+num2` and `num1+num2` return the same thing? You can check in IRB. – user3574603 Feb 27 '19 at 11:10
  • I'd suggest to pass parameters to your methods, then return just the result. – iGian Feb 27 '19 at 11:22
  • If you want to call methods dynamically: https://stackoverflow.com/questions/5349624/how-to-call-methods-dynamically-based-on-their-name/26284769 – iGian Feb 27 '19 at 11:26

4 Answers4

1

Best Way to do so, is

def perform_operation(op, a, b)
  op = { 'add' => '+', 'sub' => '-', 'mul' => '*', 'div' => '/' }[op]
  a.send(op, b)
end

num1=gets.chomp.to_f
op=gets.chomp
num2=gets.chomp.to_f

puts "This is your answer", perform_operation(op, num1, num2)

If your op is +, -, * or / passed by input you can directly do it without method like below,

puts "This is your answer", num1.send(op, num2)
ray
  • 5,454
  • 1
  • 18
  • 40
0

You can't use local variables defined outside a method within that method. Instead, you have to pass it as an argument:

def mul(num1, num2)
  puts num1 * num2
end

You also don't have to use the same variable names, use whatever makes sense in the context of the method:

def mul(a, b)
  puts a * b
end

mul(2, 3)
# prints 6

Methods usually become more versatile if they do one thing. The above implementation multiplies a and b and then prints the result via puts. Let's move the printing outside the method:

def mul(a, b)
  a * b
end

puts mul(2, 3)
# prints 6

We can now perform actual calculations:

x = mul(2, 3) #=> 6
y = mul(2, 5) #=> 10
puts mul(x, y)
# prints 60

This wouldn't have been possible with the variant which incorporated puts.


With user input and output: (using whole numbers for demonstration purposes)

print "first factor: "
num1 = gets.to_i

print "second factor: "
num2 = gets.to_i

puts "#{num1} * #{num2} = #{mul(num1, num2)}"

Note that #{...} is needed to interpolate other values.

Example session:

first factor: 2
second factor: 3
2 * 3 = 6

To have different output based on a given operator, you need a conditional, e.g. a case statement:

op = gets.chomp

case op
when 'mul'
  puts mul(num1, num2)
when 'add'
  puts add(num1, num2)
# ...
end

Hope this will get you started.

Stefan
  • 109,145
  • 14
  • 143
  • 218
  • I think `#to_i` is not good for calculator. `#to_f` is better – mechnicov Feb 27 '19 at 11:46
  • @mechnicov try `0.1 * 0.2` in IRB – the result is probably not what you expect from a calculator ;-) – Stefan Feb 27 '19 at 11:48
  • 1
    @Stefan `.to_f.round(8)` would be what I probably expect from a calculator :) – Aleksei Matiushkin Feb 27 '19 at 11:54
  • 1
    I meant, if you want to know how much will be 2.5 multiplied by 2.5, then instead of 6.25 your variant will write `2 * 2 = 4`. It is not a calculator ;-) So `#to_f` is better I think – mechnicov Feb 27 '19 at 12:12
  • @mechnicov _"It is not a calculator"_ – that's right, this is just some example code. Writing an actual calculator is beyond the scope of this answer. (and I don't think an actual calculator should be floating-point-based) – Stefan Feb 27 '19 at 13:31
0

Once you defined the methods with parameters, for example:

def sub(x, y)
  x - y
end

def add(x, y)
  x + y
end

Once you gat the variables set by user input (I'm assigning by hard coding just to show):

op = "add".to_sym # or user input
num1 = 10 # or user input
num2 = 20 # or user input

You can use the case expression to select the result to show. For example:

res = case op
  when :add
    add(num1, num2)
  when :sub
    sub(num1, num2)
end

So you can show the result as:

puts res

As mentioned, you can also call the method on the user input using send:

iGian
  • 11,023
  • 3
  • 21
  • 36
0

Using heredoc and proc

def mul(num1, num2)
  num1 * num2
end

def div(num1, num2)
  num1 / num2
end

def sub(num1, num2)
  num1 - num2
end

def add(num1, num2)
  num1 + num2
end

puts 'First number'
num1 = gets.to_f

puts 'Second number'
num2 = gets.to_f

puts <<-OPERATORS
Multiplication = mul
Addition = add
Subtract = sub
Division = div
OPERATORS

op = method(gets.chomp).to_proc

puts "This is your answer: #{op.call(num1, num2)}"

How it works on the example of String#downcase:

downator = :downcase.to_proc
downator.call('WORD') #=> "word"

# It is equal to
'WORD'.downcase #=> "word"

It is because downator stores block proc { |arg| arg.downcase }

In practice, this property is often used for operations with arrays, for example:

['WORD', 'STRING'].map(&:downcase) #=> ["word", "string"]

# It is equal to
['WORD', 'STRING'].map { |arg| arg.downcase } #=> ["word", "string"]
mechnicov
  • 12,025
  • 4
  • 33
  • 56