How to permanently update a hash in Ruby? - ruby

So I've seen questions on here about how to write to an external text file etc.
For example to write my hash to another file I put:
hash = {
Key1: Value1,
Key2: Value2
}
open(FileToWriteTo, 'w') do |f|
hash.each { |key, value| f.puts "#{key}: #{value}" }
But what I'd like to achieve is if I run the program and add something to my hash list, then the next time I run and display the hash, the new addition will be there. Here's the code I'm using to add to my hash:
puts "Type 'add' to add an item to the hash"
choice = gets.chomp.downcase
case choice
when 'add'
puts "What do you want to add?"
addition = gets.chomp
if hash[addition.to_sym].nil?
puts "What value will #{addition} have? (integer)"
add_value = gets.chomp
hash[addition.to_sym] = add_value.to_i
puts "#{addition} has been added with a value of #{value}."
else
puts "That item already exists! Its value is #{hash[addition.to_sym]}."
end
So if I add the item, rerun the program and choose to display instead of add, how should I get the last addition to show. Thanks.

Here is code you could use. It takes advantage of yaml to store the hash.
require 'yaml'
file = '/tmp/test.yml'
if File.exists?(file)
hash = YAML::load_file(file) # load yaml
else
hash = Hash.new
end
puts "Type 'add' to add an item to the hash"
choice = gets.chomp.downcase
if choice == 'add'
puts "What do you want to add?"
addition = gets.chomp
if hash[addition.to_sym].nil?
puts "What value will #{addition} have? (integer)"
add_value = gets.chomp
hash[addition.to_sym] = add_value.to_i
puts "#{addition} has been added with a value of #{add_value}."
else
puts "That item already exists! Its value is # {hash[addition.to_sym]}."
end
end
File.open(file, 'w') {|f| f.write hash.to_yaml } #store yaml

If I understood the question correctly, you want to show the added option.
Since you are using the file and rerunning the code, better read the file (and store it in hash) at start and append new items (key-val) to file.
So whenever anyone adds something, append it to file. Now when you read the file again at start, its updated.
Let me know if this is not your use case.

Related

List in Ruby gem cli

I am making a ruby cli that outputs a list of game deals scraped from a site.
The list prints out promptly using
def games_sales
Deal.all.each_with_index do |deal, index|
puts "#{index + 1}. #{deal.title}"
end
puts "What game do you want to see?"
input = gets.strip
game_selection(input.to_i)
end
My problem comes when asking the user to select an item from the list.
def game_selection(input)
deal = Deal.find_by_index(input)
#binding.pry
deal.each do |deal|
puts "#{deal.index}"
puts " Name: #{deal.title}"
puts " Price: #{deal.price}"
puts " Store: #{deal.store}"
puts " Expiration: #{deal.expiration}"
end
deal
end
It returns the int input but only the first item on the list every time.
I forgot my find_by_index method:
def self.find_by_index(input)
all.select do |deal|
end
end
which is incomplete
Not 100% sure if I got your question right and if you're using Rails, but Deals.all let me think of this.
I had to replace Deals.all with DEALS for testing as I haven't got a rails app running. So I used an Array of OpenStructs to fake your Model result.
# this fakes Deals.all
require 'ostruct'
DEALS = [
# add any more properties the same way as title, separated by comma
OpenStruct.new(title: 123),
OpenStruct.new(title: 456)
]
def games_sales
DEALS.each_with_index do |deal, index|
puts "#{index + 1}. #{deal.title}"
end
puts "What game do you want to see?"
input = gets.strip
game_selection(input.to_i)
end
def game_selection(input)
deal = DEALS.at(input-1)
p deal[:title]
end
def self.find_by_index(input)
all.select do |deal|
deal.index == input
end
end
games_sales
Result when choosing 1 is 123, choosing 2 you'll get 456, due to p deal[:title] above in the code.
I think your find_by_index need to get the right index and in my example I had to use at(index) as at(input-1) in order to get the right result.
I really hope this helps somehow and I suggest that you add the expected result to your question, in case my answer does not help you.

Get a value to access a value in a hash

I want to use an input from gets to access a value in a hash.
This code does not work:
puts "Which word?"
question = gets
question = question.to_s
puts dic_hash["#{question}"]
nor does this:
puts "Which word?"
question = gets
question = question.to_s
puts dic_hash[question]
but this works:
puts "Which word?"
puts dic_hash["zwembad"]
How do I get the gets input from the user to access a value in a hash?
You may not be aware of this, but the gets result includes the return character you typed to submit the value.
result = gets
type "hello"
p result
"hello\n"
Change your gets to gets.chomp to remove the trailing '\n`
puts "Which word?"
question = gets.chomp
puts dic_hash[question]

How to save a hash in a file and use it later in ruby?

So i got in big troubles with this exam at university because i am stuck with a part in my ruby code. I just can't figure out how
" If the user presses 2 the program shall ask for an employee number and afterwards search for the employee. If the program finds it, then print and if not, print a message saying it doesn’t have it."
My problem is that i'm not sure that the information is saved corectly in the file. But if it is... the problem is that the hash i've made isn't taking the information that already is saved in the file and only works with the information it has received last.
puts "Insert Registration number \n"
search = gets.chomp
hash = Hash.new()
hash = {(regnr) => (name)}
hash.each do |key, value|
puts "#{key} \t | \t #{value}"
end
search =~ File.new("employees.txt", "r")
if hash.has_key? (search)
print "The person you were looking for is "
puts hash [search]
else
puts "He isn't one of our employees"
end
I have to tell you guys that i have only been coding for one month and the school isn't taking me easy...
I'd recommend using yaml. Take a look around the web for some examples on using YAML. It's a structured markup that can represent hashes. You can easily dump and load simple ruby objects like hashes and arrays.
require 'yaml'
parsed = begin
employee_hash = YAML.load(File.open("employees.yml"))
rescue ArgumentError => e
puts "Could not parse YAML: #{e.message}"
end

Trying to reference earlier 'case' in a case statement

When someone tries to update a value that is not currently stored in my hash, I would like to immediately refer back to when 'add' without restarting the entire case statement since I already know they want to add and don't want to prompt them again.
Is there a way to refer back to the case choice -> when "add" section of my code without restarting the entire case statement?
I know I could use nested case statements but I would rather not copy/paste identical code if I don't have to.
hash = {}
puts "Would you like to add or update this hash?"
choice = gets.chomp
case choice
when "add"
puts "What key you like to add?"
key = gets.chomp
puts "With what value?"
value = gets.chomp
hash[key] = value
when "update"
puts "Which key would you like to update?"
key = gets.chomp
if hash[key].nil?
puts "Key not present, would you like to add it?"
#here I would like the code that references back to "when 'add'" if the user types 'yes'
Sorry for the abrupt ending of the code. I didn't want to put in anything unnecessary to the solution.
Create a method/function that wraps the functionality inside that case. Then you can call that function from both places
hash = {}
def add_key
puts "What key you like to add?"
key = gets.chomp
puts "With what value?"
value = gets.chomp
hash[key] = value
end
puts "Would you like to add or update this hash?"
choice = gets.chomp
case choice
when "add"
add_key
when "update"
puts "Which key would you like to update?"
key = gets.chomp
if hash[key].nil?
puts "Key not present, would you like to add it?"
add_key

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