My source code:
books = {
Harry_Potter: 5,
Steve_Jobs: 10
}
def finder(bookName)
books.each {
|n| if n == bookName
puts "Are you sure you want to #{choice} #{n}?"
confirmAction = gets.chomp
if confirmAction == "yes"
case choice
when "update"
puts "Enter the new name:"
newName = gets.chomp.to_sym
books[newName.to_sym] = books.delete(n)
puts "Update the rating for #{newName}:"
newRating = gets.chomp.to_i
books[newName.to_sym] = newRating.to_i
puts "Successfully updated #{newName} with rating of #{newRating}"
when "delete"
books.delete(n)
else puts "Invalid option!"
end
else puts "Invalid book name."
end
end
}
end
puts "What would you like to do?\n[Add] [Update] [Delete] [View]"
action = gets.chomp.capitalize
case action
when "Add"
puts "Enter the new book name:"
title = gets.chomp.to_sym
puts "Please rate the book [1-10]:"
rating = gets.chomp.to_i
books[title.to_sym] = rating.to_i
puts "Successfully added #{title} with rating of #{rating}"
puts books
when "Update"
choice = "update"
puts "Enter the name of the book:"
bookName = gets.chomp.to_sym
finder(bookName)
when "Delete"
choice = "delete"
puts "Enter the name of the book:"
bookName = gets.chomp.to_sym
finder(bookName)
when "View"
choice = "view"
puts books.each {
|k, v| puts "#{k}: #{v}"
}
end
Whenever I use add option and add something it works. But once I exit and re-open the program, it doesn't show books that I've added using the add option, it returns to the default list.
I need Ruby to save all the changes permanently.
You have to save your objects yourself, e.g. using YAML:
require 'yaml'
File.write('data.yml', YAML.dump(books))
The contents of "data.yml" will be:
---
:Harry_Potter: 5
:Steve_Jobs: 10
To read the file use:
books = YAML.load(File.read('data.yml'))
#=> {:Harry_Potter=>5, :Steve_Jobs=>10}
Well, you could use Maglev which is a ruby interpreter based on the GemStone/S Object Server which will be able to store your books persistently (by setting a reference to your books Hash and Maglev.commit_transaction). However this might be a bit of an overkill for your purposes :-)
Related
I've just completed the Ruby CodeAcademy task, 'night at the movies' (code below).
When searching for existing movies in the database, I want the user to be able to input the title (in this case only StarWars or Divergent) without it having to be case sensitive? At the moment a search of 'starwars' returns an error (as opposed to StarWars which doesn't)!
Thanks
movies = {
StarWars: 4.8,
Divergent: 4.7
}
puts "What would you like to do? "
choice = gets.chomp
case choice
when "add"
puts "What movie would you like to add? "
title = gets.chomp.downcase
if movies[title.to_sym].nil?
puts "What rating does the movie have? "
rating = gets.chomp
movies[title.to_sym] = rating.to_i
else
puts "That movie already exists! Its rating is #{movies[title.to_sym]}."
end
when "update"
puts "Please enter movie title."
title = gets.chomp.to_sym
if movies[title].nil?
puts "This title doesn't exist!"
else
puts "what's the new rating for this movie (0 to 4)"
rating = gets.chomp
movies[title.to_sym] = rating.to_i
puts "#{title} has been updated with a rating of
#{rating}."
end
when "display"
movies.each do |movies, rating|
puts "#{movies}: #{rating}"
end
when "delete"
puts "Please enter movie title:"
title = gets.chomp.to_sym
if movies[title.to_sym].nil?
puts "Title doesn't exist"
else
movies.delete(title)
puts "#{title} has been deleted!"
end
else
puts "Error!"
end
You could use lowercase symbols
movies = { starwars: 4.8, divergent: 4.7}
and then turn the users input into all lowercase letters
title = gets.chomp.downcase.to_sym
this would turn any variance in capitalization of the titles (STARwars, StARwarS, ect...) into starwars
I need to create a program in which the user can take different tests. As i dont want to copy paste my code all over for every test, i have tried to setup a class for that purpose - but i have problems with this class.
Error message = undefined variables or method in 'display_test'
I have predefined som test as a .txt file
I want to choose the file in the class depending on what the user answer - is that possible?
Class code:
class Test
#correct_answers = 0
def display_question( question, options, answer )
puts question
options.each_with_index { |option, idx| puts "#{ idx + 1 }: #{ option
}" }
print 'Answer: '
reply = gets.to_i
if answer == reply
puts 'Correct!'
#correct_answers += 1
puts "#{#correct_answers}"
else
puts 'Wrong. The correct answer was: ' + answer.to_s
end
end
def display_test()
f = File.new(userinput, 'r')
while ! (f.eof?) #logikken til at splitte
line = f.gets()
question = line.split("|")
question[1] = question[1].split(";")
display_question question[0], question[1], question[2].to_i
end
end
display_test
puts "________________________________________________________"
puts "Total score:"
puts "You've got" + " #{#correct_answers}" + " correct answers!"
Before hand i have used ("geografitest.txt") instead of username in the File.new so it looked like this:
f = File.new('geografitest.txt','r')
But now i am trying to let the user decide what test to take.
I am very new to ruby, so please bear with me.
I have tried to do it this way, which obviously is not working.
puts "Which test do you want to take?"
select = 0
while (select != 3)
puts "Press 1 to take Geografi test."
puts "Press 2 to take Math test."
puts "Press 3 to take Religion test."
puts "Press 3 to exit"
select = gets.chomp.to_i
if (select == 1)
gets.chomp = userinput
userinput =`geografitest.txt`
echo $userinput
end
if (select == 2)
gets.chomp = userinput
userinput =`matematiktest.txt`
echo $userinput
end
if (select == 3)
gets.chomp = userinput
userinput =`religionstest.txt`
echo $userinput
end
if (select > 4)
puts "Not a correct selection"
elsif (select == 4)
puts "Goodbye"
end
end
abort
So my questions is now;
How can i make the user choose what test to take? Can i make a variable instead of the textfile as i have tried, but in a different way? Or is there a smarter way?
And in what way is my class wrong and how do i fix it? I know its not the way to make it, but i simple cant get my head around how to make it right.
Please help a rookie out.
Cheers!
You can pass file as dependency to you Test class based on user input with object constructor. Something like this
class Test
attr_reader :correct_answers_count
def initialize(file)
#file = file
#correct_answers_count = 0
end
#other code goes here
end
loop do
case user_input = gets.chomp
when '1'
file_name = 'some_file1'
when '2'
file_name = 'some_file1'
when '3'
break
else
puts 'wrong variant'
end
test = Test.new(File.new(file_name, 'r'))
test.display
end
I'm having a problem in my ruby code. My project is to:
Make a new file and put the data inside and than search:
1. Enter a new employee (number, name, date of birth).
2. Search for an employee by number. (in the database)
3. To exit press 3
This is the code I have, but the terminal won't run it.
class Person
def setNumber(number)
#number=number
end
def setInfo(name)
#name=name
end
def getInfo()
return #name
end
def setInf(dateofBirth)
#dateofBirth=dateofBirth
end
def getInf()
return dateofBirth
end
puts "Companies employees"
select = 0
while(select!=3)
puts "Press 1 to Enter information about new employee"
puts "Press 2 to Search for employee by number"
puts "Press 3 to exit"
select=gets.chomp.to_i
if(select == 1)
f=File.new("Repository.txt","a+")
puts "Please enter employee number:"
number = gets.chomp.to_s
f.puts (number)
person = Person.new
person.setInfo(number)
puts "Please enter the employee name:"
name = gets.chomp.to_s
f.puts (name)
set_name = Person.new
set_name.setInfo(name)
puts "Please enter the employees date of birth:"
dateofBirth = gets.chomp.to_s
f.puts (dateofBirth)
dateofBirth = Person.new
dateofBirth.setInfo(dateofBirth)
f.close()
elsif(select==2)
puts "Which employee number would you like to search for?"
search = gets.chomp
f = File.open("Repository.txt","r")
while !(f.eof?)
line.include?(search)
end
f.close()
elsif(select > 3)
puts "Incorrect selection."
elsif(select == 3)
puts "Goodbye!"
end
end
This looks incredibly similar to someone else who asked a similar question yesterday. Maybe a school project going around.
You might check the code here: I trying to make a code that gives the user a personal number after they have made an user
I've seen similar answers to this question but I think I need something more specific to my code. Basically I've called the row from the CSV file but now I need to delete the called row. Sounds simple as I write this yet here I am asking you all for help. I know there is a lot of code here but I figured the more there is the more easier you will be able to understand the context. Apologies if there is too much noise in the code.
def delete_user_menu
puts "============================================"
delete_users_active_list
puts " "
puts "Please type in the name of the user you wish to eradicate: "
print "> "
eradicate(gets.chomp)
end
def eradicate(delete_input)
delete_row = delete_authentication(delete_input)
if delete_row
puts "Are you sure you want to delete #{delete_input} from the database?"
puts "[y]es or [n]o"
print "> "
delete_answer = gets.chomp
if delete_answer == "y"
delete_user
after_deletion_menu
elsif delete_answer == "n"
puts "Close call! Taking you back to main menu."
sleep 2
admin_main_menu
else
puts "Input not recognised. Please try again."
eradicate(delete_input)
end
else
puts "User not recognized. Please try again."
sleep 1
delete_user_menu
end
end
def delete_user
# this is where the delete user function needs to go
after_deletion_menu
end
def after_deletion_menu
puts " "
puts "User deleted! What would you like to do now?"
puts "1. Delete another user"
puts "2. Back to main menu"
print "> "
after_deletion_choice = gets.chomp
if after_deletion_choice == "1"
delete_user_menu
elsif after_deletion_choice == "2"
admin_main_menu
else
puts "Input not recognized. Please try again."
after_deletion_menu
end
end
def delete_users_active_list
CSV.foreach("./users.csv", headers: true) do |row|
username = row['username']
puts "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
puts "Username: #{username}"
end
end
def delete_authentication(username)
CSV.open('users.csv', headers: true).find { |row| row['username'] == username }
end
I've had a look at this question How to remove a row from a CSV with Ruby
but I don't fully understand the answers, hence why I'm here. Any help is much appreciated.
I looked at the link. First, they are reading the entire csv file into table:
table = CSV.table(#csvfile)
then deleting the row from table:
table.delete_if do |row|
row[:foo] == 'true'
end
Finally, they are completely replacing the original file with the new table minus the row:
File.open(#csvfile, 'w') do |f|
f.write(table.to_csv)
end
This is generally how you have to do this kind of operation when you are dealing with a file. It's not like a database.
EDIT - in your case:
delete_user(delete_input)
...
def delete_user(user)
...
table.delete_if { |row| row[:username] == user }
...
I'm trying to create an if/else statement that compares a user's input against all the name keys within a hash that's stored with a text file. How would I write this?
user_accts is the array.
Update of full if/else statement:
elsif choice == "2"
puts "====== NEW CUSTOMER ======"
puts "Choose a username:"
prompt; login_name = gets.chomp
#file.open("cust_accts.txt", "r")
#if #user_accts.map { |acct| acct["name"]}.include?(login_name)
if #user_accts.any? {|acct| acct["name"] == login_name }
puts "Sorry, that username has already been taken"
elsif
puts "Choose a password:"
prompt; login_password = gets.chomp
user_accts << create_account(login_name, login_password)
File.open("cust_accts.txt", "a") { |file| file.puts(user_accts)}
end
original if/else statement:
if login_name == #??? #user_accts.has_key?(login_name) ???
puts "Sorry, that username has already been taken"
elsif
puts "Choose a password:"
prompt; login_password = gets.chomp
user_accts << create_account(login_name, login_password)
File.open("cust_accts.txt", "a") { |file| file.puts(user_accts)}
end
This is exactly what is inputted to the cust_accts.txt file using this command:
user_accts << create_account(login_name, login_password)
File.open("cust_accts.txt", "a") { |file| file.puts(user_accts)}
cust_accts.txt
{"name"=>"Tom", "password"=>"popcorn", "balance"=>0}
{"name"=>"Avril", "password"=>"chain", "balance"=>0}
It's not quite clear what your starting point is.
Assuming you have parsed your text file into #user_accts, so you have:
#user_accts = [{"name"=>"Tom", "password"=>"popcorn", "balance"=>0},
{"name"=>"Avril", "password"=>"chain", "balance"=>0}]
Then you would want to do:
if #user_accts.map {|acct| acct["name"]}.include?(login_name)
puts "Sorry, that username has already been taken"
else
# ...
end
#user_accts = [{"name"=>"Tom", "password"=>"popcorn", "balance"=>0},
{"name"=>"Avril", "password"=>"chain", "balance"=>0}]
if #user_accts.any? {|acct| acct["name"] == "Tom" }
puts "Sorry, that username has already been taken"
else
# ...
end
#=> Sorry, that username has already been taken
It seems like your problem is "How do I store objects in ruby for use at a later date?". If you want to use a text file you need to put it into a format that can be parsed back into a ruby object like JSON or XML. I would recommend using a database though. A database like SQLite is very light weight and easy to learn. An advantage to using a DB is that when you use a DB you can set an option to have your results returned as a hash.
I had a similar problem, eventually decided that a DB was the way to go.