Learning to code, Undefined variable troubles - ruby

I am in the process of teaching myself Ruby, and I came onto something I don't quite understand. I am gettign an error of branchingcalc.rb:53:in `<main>': undefined local variable or method `userChoice' for main:Object (NameError)
In my code (below) I have userChoice defined in the method above it. Is the issue I'm having that it's defined in a method, above, or can the if/elsif tree not read the variable because it's defined in a method?
I have removed the userInput method, placing it in the #Begining portion, and that solves my issue, however, I would like the calc to be repeatable.
def userInput
puts "Enter the first number"
num1 = gets.chomp
puts "Enter the second number"
num2 = gets.chomp
puts "What would you like to do?"
puts "1 - Muiltiply"
puts "2 - Divide"
puts "3 - Add"
puts "4 - Subtract"
puts "5 - Exit"
25.times { print "-" }
puts
userChoice = gets.chomp # <- variable defined here
puts
end
# Begining
puts "Branching Clac"
25.times { print "-" }
puts
puts userInput
# Choice tree
if userChoice == "1" # <- undefined variable error here
# ...
elsif userChoice == "2"
# ...
end

You've introduced the userChoice variable in the userInput method. This variable only exists within that method. If you want to communicate this information outside of the method, the best option is to return it from the method, and then use that return value later.

Related

assigning a method result to a variable in ruby

I'm sure it would be hard to find an easier question, but I'm a complete newbie. I have searched extensively and for some reason can't find the answer to this. Here's my code:
puts "Enter F for Fahrenheit and C for Celsius."
x = gets.chomp.downcase
def ftoc(fahrenheit)
(fahrenheit.to_f - 32.0) * (5.0 / 9.0)
end
if x == "f"
puts "Enter your temp:"
temp = gets.chomp.to_i
ftoc temp
elsif x == "c"
puts "Enter your temp:"
temp = gets.chomp.to_i
ctof temp
else
puts "That does not compute."
end
I'm just trying to get the returned result of the method into a variable so I can use it elsewhere....
Remember that calls like ctof temp just initiate a method and then, as you're not putting the result anywhere, discard it immediately.
To clean up this code let's organize it better:
# Temperature conversion method
def ftoc(fahrenheit)
(fahrenheit.to_f - 32.0) * (5.0 / 9.0)
end
# User input method
def temperature_prompt!
puts "Enter F for Fahrenheit and C for Celsius."
x = gets.chomp.downcase
case (x)
when "f"
puts "Enter your temp:"
temp = gets.chomp.to_i
ftoc temp
when "c"
puts "Enter your temp:"
temp = gets.chomp.to_i
ctof temp
else
puts "That does not compute."
end
end
Now you can make use of the fact that in Ruby things like if and case actually return values. In this case it's the value of the last thing to execute in each block, so that result isn't discarded, it's just passed along:
temp = temperature_prompt!
If you enter an invalid value you get the result of puts which is conveniently nil.
Here's something to consider: Ruby is very good at parsing arbitrary text if you can describe the patterns. Here's a simple input routine:
def temperature_prompt!
puts "Enter degrees (e.g. 8F, 2C)"
case (input = gets.chomp.downcase)
when /(\d+)f/
ftoc $1
when /(\d+)c/
ctof $1
else
puts "That does not compute."
end
end
You could add to those patterns to allow things like -2C and 3.4°F if you wanted.

Ruby undefined variable

I have a code below:
secret_number = 8
user_input = ""
def number_guesser(user_input)
while user_input != secret_number
puts "Guess a number between 1 and 10:"
user_input = gets.chomp
if user_input != secret_number
puts "Wrong! Try again."
else
puts "You guessed correctly!"
end
end
end
number_guesser(user_input)
when I tried to run the above program it showed as below:
****undefined local variable or method secret_number' for main:Object
(repl):211:innumber_guesser'
(repl):221:in `'****
Any ideas?
You can't use a local variable like that inside another scope such as a method, it's two different contexts. Instead you need to pass that in if you want to use it.
It's a simple change:
def number_guesser(user_input, secret_number)
# ...
end
Then just feed that argument in.
You'll note that user_input isn't really necessary as a parameter, you can always initialize and use that locally, so it's actually pointless as an argument.
The pattern to use in that case:
loop do
input = gets.chomp
# Prompting...
break if input == secret_number
# Guessed wrong...
end

I'm trying to design a simple Ruby calculator and I'm getting an error

So I've been messing around with Ruby for the first time after finishing the codecademy course up to "Object Oriented Programming, Part I" and I decided to start making a calculator. For some reason though, I get this error:
calc.rb:13:in `addition': undefined local variable or method `user_input' for main:Object (NameError)
from calc.rb:21:in `<main>'
I'm confused why it doesn't see my "user_input" array. Is it out of the scope of the method? Did I initialize it wrong?
Here's the code so you can see for yourself, it's obviously nothing sophisticated and it's not finished. I'm just trying to test for addition right now.
#!/usr/bin/env ruby
user_input = Array.new
puts "Would you like to [a]dd, [s]ubtract, [m]ultiply, or [d]ivide? "
type_of_math = gets.chomp
def addition
operator = :+
puts "Please enter the numbers you want to add (enter \"=\" to stop adding numbers): "
until gets.chomp == "="
user_input << gets.chomp.to_i
end
sum = user_input.inject(operator)
return sum
end
case type_of_math
when "a"
addition
when "s"
puts "Test for subtraction"
when "m"
puts "Test for multiplication"
when "d"
puts "Test for division"
else
puts "Wrong"
end
Consider this untested variation on your code. It's more idiomatic:
def addition
user_input = []
puts 'Please enter the numbers you want to add (enter "=" to stop adding numbers): '
loop do
input = gets.chomp
break if input == '='
user_input << input
end
user_input.map(&:to_i).inject(:+)
end
Notice that it puts user_input into the method. It also uses the normal [] direct assignment of an empty array to initialize it. Rather than chomp.to_i each value as it's entered it waits to do that until after the loop exits.
Instead of while loops, consider using loop do. They tend to be more easily seen when scanning code.
Also notice there's no return at the end of the method. Ruby automatically returns the last value seen.

Looking for help cleaning up code

This is for an assignment for a class. I want to create a register type application for a donut shop. The application should accept "l" to list flavors, "a" to add flavors, "d" to delete flavors, and "e" to exit. The prices should be listed in ascending order. When adding a flavor, it should ask first the flavor, then the price.
I have the application working. It uses Jekyll (what the class uses).
item = {}
item_asc = {}
puts "Welcome to d0nutz flavor menu"
input = ""
division_line = lambda {30.times {|x| print "="}}
while input != "e"
division_line.call
puts "\n(l)ist flavors\n(a)dd a flavor\n(d)elete a flavor\n(e)xit application"
division_line.call
print "\nYour choice: "
input = gets.chomp
case input
when "l"
item_asc.each {|x,y| puts "Flavor: #{x} - Cost: $#{y}"}
when "a"
puts "Enter new flavor: "
flavor = gets.chomp
puts "Enter cost: "
cost = gets.chomp.to_i
item[flavor] = cost
item_asc = item.sort_by {|flavor,price| price}
input = ""
when "d"
puts "Enter a flavor to remove"
to_delete = gets.chomp
item.delete("#{to_delete}") {|x| puts "#{x} not found."}
item_asc = item.sort_by {|flavor,price| price}
item_asc.each {|x,y| puts "Flavor: #{x} - Cost: $#{y}"}
input = ""
when "e"
else
puts "\nThat is not a recognised command"
end
end
However it's even uglier than what I have here. I appreciate any input. I am interested in seeing what I should have done for clean up purposes, and maybe adding classes/methods where they should be, and making this more Rubyesque.
I would change the code to the following. This is not refactor since it is not equivalent to your code. In particular, it is not inconsistent like your code is. For example, when it prompts, it does not sometimes change a line and sometimes not as in your code; My code never changes a line. My code also always prints the list after an operation, unlike your code, which does not do so particularly when an item is added. Also, unlike your code, it does not end a message sometimes with and sometimes without a period; Messages in my code never end with period.
def prompt s
print "#{s}: "
gets.chomp
end
def list_items
#items.each{|k, v| puts "Flavor: #{k} - Cost: $#{v}"}
end
def sort_items
#items = #items.sort_by{|flavor, price| price}.to_h
list_items
end
puts "Welcome to d0nutz flavor menu"
#items = {}
loop do
puts(
?= * 30,
"(l)ist flavors",
"(a)dd a flavor",
"(d)elete a flavor",
"(e)xit application",
?= * 30,
)
case prompt("Your choice")
when ?l
list_items
when ?a
#items[prompt("Enter new flavor")] = prompt("Enter cost").to_i
sort_items
when ?d
#items.delete(prompt("Enter a flavor to remove")){|k| puts "#{k} not found"}
sort_items
when ?e
break
else
puts "That is not a recognised command"
end
end

undefined method `include?' for nil:NilClass ruby beginner

Here is some code:
print "What is your name?"
userinput = gets.chomp.downcase!
if userinput.include? "s"
print "I found it"
else
print "found nothing"
end
It gives the error: undefined method `include?' for nil:NilClass
but when I change it to:
print "What is your name?"
userinput = gets.chomp
userinput.downcase!
if userinput.include? "s"
print "I found it"
else
print "found nothing"
end
It works just fine. Any idea why this is?
downcase! returns nil when there is nothing to downcase. If you reassign that to userinput, then userinput can become nil as in your first example. If you use downcase instead, then the error will go away. In your second example, you are not reassigning the result of downcase! to userinput, so userinput is not overwritten as nil.

Resources