سؤال

I am currently playing with creating a one function to create a simple calculator. I am learning Ruby/Python. So far I am playing with Ruby to see if I can grasp it easier than Python. I was reading a ebook and came across how to use multiple parameters in a function.

#!/bin/ruby

def menu()
  print <<MENU
    1.Add
    2.Subtract
    3.Multiply
    4.Divide
MENU
end

def calc(a=number, b=operator, c=number, d=operator, e=number)
  puts "Answer: #{a} #{b} #{c} #{d} #{e}"
end
puts "Enter formula, seperated by comma"
a,b,c,d,e = gets()
calc(a,b,c,d,e)

Is my source, keep in mind this is not meant to be a used program. As it is right now, it is prints the "answer" as a string.

So, if I enter 1+3, answer is 1+3. But if I use gets().to_f, it prints 1.0 every time. If I enter the math problem in the text file, it works perfectly, just not from user input.

هل كانت مفيدة؟

المحلول 2

I believe that all that what is missing in your code is to split the gets answer:

#!/bin/ruby

def menu()
  print <<MENU
    1.Add
    2.Subtract
    3.Multiply
    4.Divide
MENU
end

def calc(a, b, c, d, e)
  puts "Answer: #{a} #{b} #{c} #{d} #{e}"
end
puts "Enter formula, seperated by comma"
a,b,c,d,e = gets.split('')
calc(a,b,c,d,e)

Now, when the user will input 2*7+1 you will get Answer: 2 * 7 + 1, and you can go and implement your code:

def calc(a, b=:+, c=0, d=:+, e=0)
  puts a.to_f.send(b, c.to_f).send(d, e.to_f)
end

Now your answer will be 15.0.

DO NOT USE EVAL, especially when you expect something structured - it is a serious security flaw!


For your code to support less than 5 elements, you need to change it to:

params = gets.chomp.split('')
calc(*params)

This way, missing elements will not be evaluated as 'nil', and the method's default parameter values will kick in.

نصائح أخرى

Well, there's a few things going on here.

First, your function definition: def calc(a=number, b=operator, c=number, d=operator, e=number)

This should probably be def calc(a=nil, b=nil, c=nil, d=nil, e=nil)

I understand that the example is telling me, the user, that a should be a number, b should be an operator, etc, but when you actually define a function that way, what you are doing is setting default values for the parameters. When you use 'number' and 'operator' in the definition, these have no value and end up assigning nil as default. The end result is the same, but it's confusing to anyone reading the code.

Next, I understand what you are trying to do with a,b,c,d,e = gets().
If you just run

a,b,c,d,e = 1,2,3,4,5
puts a,b,c,d,e #=>
1
2
3
4
5

Makes sense. However, when you run a Ruby script and use gets(), then everything that is input at the command line is received as a single string. Therefore when a,b,c,d,e = gets() is executed, the user input of "1+3" is taken as a string and assigned to a.
b, c, d, and e are nil

You then call calc("1+3",nil,nil,nil,nil).
calc then evaluates its one line method definition like so:
puts "Answer: #{"1+3"} #{nil} #{nil} #{nil} #{nil}"
And that's why you just see "Answer: 1+3" as the output.

So, why does it work if you hard code a,b,c,d,e=2*7+1?
When that line is evaluated, 2*7+1 is evaluated first (15). 15 is then assigned to a and all the other variables are nil, like before. Then calc just prints out the value of a, which is 15.

So....Let's look at how to make the example work as you expect.
First, I'm going to ignore the menu method since it's not actually used anywhere in the example.

#!/bin/ruby

def calc(user_input)
  result = eval(input_string)
  puts "Answer: #{result}"
end
puts "Enter formula"

user_input = gets()
# e.g. "1+3*8"

calc(user_input)

All I'm doing is evaluating the entered string. Be very careful with eval. I would never actually use it in this case since a user could enter any kind of ruby script and your program would just run it. Here is an SO question that demonstrates how to implement checks before evaluating the formula.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top