Looking for help cleaning up code - ruby

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

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.

How to sum variables values RUBY

First, I am new to ruby so please be gentle hehe.
I have a school project where the assignment is to calculate the total cost of a project. In my code, the user is giving the variables some input. Later on, I want to show the total of all these inputs. (the inputs is number)
So basically I need to add them up and it needs to give me a sum of them.
How do I do that?
Hope you amazing people can help me:)
Here is my code:
file = File.new("testing.txt", "a")
class Project
def call_acc
prompt = "> "
puts
puts "What is the salary for an accountant?"
print prompt
while #accountant = gets.chomp
if !/\A\d+\z/.match(#accountant)
puts
puts "Error: Only use numbers, please try again"
print prompt
else
break
end
end
end
def call_dev
prompt = "> "
puts
puts "What is the salary for an developer?"
print prompt
while #developer = gets.chomp
if !/\A\d+\z/.match(#developer)
puts
puts "Error: Only use numbers, please try again"
print prompt
else
break
end
end
end
def call_mana
prompt = "> "
puts
puts "What is the salary for the top management?"
print prompt
while #management = gets.chomp
if !/\A\d+\z/.match(#management)
puts
puts "Error: Only use numbers, please try again"
print prompt
else
break
end
end
end
def call_office
prompt = "> "
puts
puts "What is the total office rent for the project?"
print prompt
while #office = gets.chomp
if !/\A\d+\z/.match(#office)
puts
puts "Error: Only use numbers, please try again"
print prompt
else
break
end
end
end
def call_lunch
prompt = "> "
puts
puts "What is the daily cost for lunch per person?"
print prompt
while #lunch = gets.chomp
if !/\A\d+\z/.match(#lunch)
puts
puts "Error: Only use numbers, please try again"
print prompt
else
break
end
end
end
def call_utilites
prompt = "> "
puts
puts "What is the total cost for utilites (internet, subscriptions etc)?"
print prompt
while #utilites = gets.chomp
if !/\A\d+\z/.match(#utilites)
puts
puts "Error: Only use numbers, please try again"
print prompt
else
break
end
end
end
def call_show
prompt = "> "
puts "____________________________________"
puts
puts "Is this information correct?"
puts
puts "Accountant salary (per hour): #{#accountant}kr\nDevelepor salary (per hour): #{#developer}kr\nTop management salary (per hour): #{#management}kr"
puts
puts "Total rent cost of office space: #{#office}kr\nLunch per person per day: #{#lunch}kr\nTotal cost of utilites #{#utilites}kr"
puts
puts "____________________________________"
puts "Yes or No"
print prompt
while user_imput = gets.chomp.upcase
case user_imput
when "YES"
file = File.new("testing.txt", "a")
file.puts("Account salary: #{#accountant}kr\nDeveloper selary: #{#developer}kr\nTop management salary #{#management}kr\nTotal rent cost: #{#office}kr\nLunch per person #{#lunch}kr\nUtilites cost #{#utilites}kr")
file.close
puts
puts "The information has now been stored"
puts "____________________________________"
break
when "NO"
puts
puts "The information has not been stored. Exiting application"
puts "____________________________________"
abort
else
puts
puts "Please either write Yes or No"
print prompt
end
end
end
def call_total
prompt = "> "
puts
puts "________Your information_______"
puts
puts "Accountant salary (per hour): #{#accountant}kr\nDevelepor salary (per hour): #{#developer}kr\nTop management salary (per hour): #{#management}kr"
puts
puts "Total rent cost of office space: #{#office}kr\nLunch per person per day: #{#lunch}kr\nTotal cost of utilites #{#utilites}kr"
puts
puts "________Total cost of project________"
puts
puts ?????????#accountant + #developer??????????????+
puts
end
project = Project.new
require 'io/console'
select = 0
prompt = "> "
puts
puts
puts "Welcome to KEA"
puts "____________________________________"
loop do(select != 7)
puts
puts "Press 1 to calculate"
puts "____________________________________"
select = STDIN.getch.to_i
if (select == 1)
project.call_acc
project.call_dev
project.call_mana
project.call_office
project.call_lunch
project.call_utilites
project.call_show
project.call_total
break
else
puts
puts "Invalid input. Please try again"
puts "____________________________________"
end
end
end
Answering the question stated in title:
numbers =
loop.inject([]) do |acc, _|
val = gets.to_i
break acc unless val > 0
acc << val
end
numbers.reduce(:+)

Can this be optimized without using a global variable?

I've recently begun learning ruby and I'm trying to avoid using global variables where possible. I wrote the below program which accepts user input and outputs math tables of the users choice (currently just +, * but to be expanded upon). I'm following suggestions from https://adriann.github.io/programming_problems.html to get me learning.
class User_input
.
# multiply
def User_input.mult1_to_12
by = (0..12).each do | range |
result = $choice_int * range
puts "#{$choice_int} x #{range} = #{result}"
end
end
# add
def User_input.add1_to_12
add = (0..12).each do | range |
result = $choice_int + range
puts "#{$choice_int} + #{range} = #{result}"
end
end
# accepts user input
puts "Please enter the tables you require (1-12): "
$choice_int = gets.to_i
puts "You have selected #{$choice_int}"
puts "Which tables do you require (+ - * /): "
choice_method = gets.chomp
puts "the method you have chosen is #{choice_method}"
if choice_method == "*"
User_input.mult1_to_12
elsif
choice_method == "+"
add1_to_12
end
end
You will note that I am currently using a global variable for $choice. Can someone with more experience suggest a more optimal solution. Please feel free to tear my code apart : ) Thanks.
Methods can accept parameters, for example:
# add numbers
def add(a,b)
a+b
end
puts add(1,2)
# will output 3
Here's a simple modification to your code using parameters:
class UserInput
# multiply
def self.mult1_to_12(choice_int)
(0..12).each do | range |
result = choice_int * range
puts "#{choice_int} x #{range} = #{result}"
end
end
# add
def self.add1_to_12(choice_int)
(0..12).each do | range |
result = choice_int + range
puts "#{choice_int} + #{range} = #{result}"
end
end
end
# accepts user input
puts "Please enter the tables you require (1-12): "
choice_int = gets.to_i
puts "You have selected #{choice_int}"
puts "Which tables do you require (+ - * /): "
choice_method = gets.chomp
puts "the method you have chosen is #{choice_method}"
if choice_method == "*"
UserInput.mult1_to_12(choice_int)
elsif choice_method == "+"
UserInput.add1_to_12(choice_int)
end
And here's a bit prettier solution that can also handle - and / (and a bunch of other operations provided by Ruby's Fixnum):
class UserInputProcessor
# define accessors to instance variables
attr_accessor :choice_int, :choice_method
def process
(0..12).map do |range|
if choice_method.eql?('/')
next if range.eql?(0) # need to skip X/0 to avoid division by zero
range = range.to_f # need to convert range to float to get float results
end
"#{choice_int} #{choice_method} #{range.to_i} = #{choice_int.send(choice_method, range)}"
end
end
end
handler = UserInputProcessor.new
print "Please enter the tables you require (1-12): "
handler.choice_int = gets.chomp.to_i
puts "You have selected #{handler.choice_int}"
print "Which tables do you require (+ - * /): "
handler.choice_method = gets.chomp
puts "the method you have chosen is #{handler.choice_method}"
puts "And here are the results:"
puts handler.process.join("\n")

Conversion to integer isn't executing?

i have this code :
#require_relative '../lib/hackex/net/typhoeus'
require_relative '../lib/hackex'
require 'rubygems'
require 'faker'
print "how many farms do you want : "
choice = gets.chomp
choice.to_i
check = choice.is_a?(Integer)
puts check
if choice > 250
puts "Error! you cannot make more than 250 farms at once"
elsif choice < 250
puts "Error! you have to make at least one farm..."
elsif choice.is_a?(Integer) == false
puts "Error, something went wrong !"
else
puts "making #{choice} acounts ! ! !"
cnt = 1
while choice>cnt
gen = Faker::Name.first_name + Faker::Name.last_name
path=("created1.txt")
email = gen+'#gmail.com'
password = Faker::Internet.password(8)
username = gen.to_s+'/>'
puts HackEx::Request.Do(http,HackEx::Request.CreateUser(username, email, password, facebook_id = nil))
cnt +=1
open(path, 'a') { |f|
f << "#{email};"
f << "#{password}"
f << "\n"
}
puts "Account created!"
puts "#{choice - cnt} accounts remaining!"
end
end
i am trying to determing if the choice is an integer... i did the .to_i on choice, but it returns false, meaning its not an integer, its a string, why isnt it switching ?
ps : i do not get any errors, and the rest of the code works fine, except for the if part
choice.to_i returns an integer, but does not change choice. If you want choice to be changed to the integral value of the old choice, you need to reassign it explicitly:
choice = choice.to_i
Quoting the doc of String::to_i, emphasis is mine
to_i(base=10) → integer
Returns the result of interpreting leading characters in str as an
integer base base (between 2 and 36).
So you have to assign the return to something, or itself:
choice = choice.to_i

Two Parts, If I read in a file that's formatted like an array, can it be treated as such? And another about searching strings

I have two questions with this sample of code i'm about to drop in. The first deals with
person = gets.chomp
puts "Good choice! Here are #{person}'s tags!"
person = "#{person}.txt"
file = File.open(person)
while line = file.gets do
puts line
end
If the file that's opened is formatted exactly like an array (in this case its actually an array ruby has previously written to a txt file lets say, ["Funny", "Clever", "Tall", "Playboy"] ) Is there an easy way just make that an array again? Nothing I tried seemed to work.
The second deals with this
puts "Which tag would you like to vote on?"
tag = gets.chomp
if File.open(person).grep(/tag/) == true
puts "Found it!"
else
puts "Sorry Nope"
end
#f = File.new("#{person}")
#text = f.read
#if text =~ /tag/ then
#puts "Alright, I found that!"
#else
#puts "Can't find that sorry."
#exit
#end
This section just doesn't seem to be working. It never finds the string, also the commented out attempt didn't work either. I wasn't sure if the grep line actually returned a true or false value, but the commented out part avoids that and still doesn't return the string. I tried formatting the input with "" around it and every possible configuration ruby might be looking for but it always passes to the negative result.
and for the sake of completeness here is all the code.
puts "This is where you get to vote on a Tag!"
puts "Whose Tags would you like to alter?"
Dir.glob('*.txt').each do|f|
puts f[0..-5]
end
puts ".........."
person = gets.chomp
puts "Good choice! Here are #{person}'s tags!"
person = "#{person}.txt"
file = File.open(person)
while line = file.gets do
puts line
end
puts "Which tag would you like to vote on?"
tag = gets.chomp
if File.open(person).grep(tag) == true
puts "Found it!"
else
puts "Sorry Nope"
end
#f = File.new("#{person}")
#text = f.read
#if text =~ /tag/ then
#puts "Alright, I found that!"
#else
#puts "Can't find that sorry."
#exit
#end
Part 1 - Parse a string into an array
Use JSON.parse:
require 'json'
JSON.parse('["Funny", "Clever", "Tall", "Playboy"]')
# => ["Funny", "Clever", "Tall", "Playboy"]
Part 2 - Find a string in a file
As bjhaid recommended, use File.read and include?:
File.read(person).include?(tag)
This returns either true or false.
change:
if File.open(person).grep(tag) == true
puts "Found it!"
else
puts "Sorry Nope"
end
to
if File.read(person).include?(tag)
puts "Found it!"
else
puts "Sorry Nope"
end
File#open returns an IO object so you can't call grep on it like you would have done on an array, so I would suggest File.read which returns a String object that you can now call include? on

Resources