Read from a file and Update - ruby

i have a text file called text.txt with stored text like so
713,socks,3.99
888,hat,12.99
634,shirt,7.99
I want to open my file and choose a item number then i want to update the description and price. and save that back to the file.
heres my code so far
puts "Whats's the item number of the product you wish to update?"
item_num = gets.chomp
puts 'Enter new products description. '
new_description = gets.chomp
puts 'Enter new products price. '
new_price = gets.chomp.to_s
open('text.txt', 'r+') { |update|
update.puts "#{item_num},#{new_description},#{new_price}"
}
end
all this is doing is adding a new product with the same item number.

The easiest way to achieve a goal is to use CSV class to operate your file content. After all, the content is csv, right?
So, instead of:
open('text.txt', 'r+') { |update|
update.puts "#{item_num},#{new_description},#{new_price}"
}
you might want to search for an element inside loaded array, update it and then write the content back to file:
require 'csv'
items = CSV.read("text.txt")
items.map! { |i|
next i unless i.first == item_num # skip unless it’s our item
i[1] = new_description
i[2] = new_price
i
}
# here should go the code whether you need to insert line if `num` is not found
CSV.open("text.txt", "wb") do |csv|
items.each { |i| csv << i }
end
This is definitely not a best production-quality code, the intent was to demonstrate how it’s to be done in general. Hope it helps.

Related

How to generate a column in a CSV file instead of a row

So what I'm trying to do is read a specific column from an existing CSV file, parse some information out of the pulled data, then make a new CSV file with the newly parsed information in a single column. The header and first entry of the generated array go into the CSV file correctly, but after those, every other entry goes into the adjacent cells of the same row instead of creating a column, so it's like an L shape instead of just a line. Any ideas?
#!ruby.exe
require 'csv'
puts "Please enter a file name:" #user input file name (must be in same
folder as this file)
file = gets.chomp
begin
File.open(file, 'r')
rescue
print "Failed to open #{file}\n"
exit
end #makes sure that the file exists, if it does not it posts an error
data_file = File.new(file)
data = [] #initializes array for addresses from .csv
counter=0 #set counter up to allow for different sized files to be used
without issue
CSV.foreach(data_file, headers: true) do |row|
data << row.to_hash
counter+=1
end #goes through .csv one line ar a time
data.reject(&:empty?)
puts "Which column do you want to parse?"
column = gets.chomp
i=0
streets = []
while (i<counter)
address = data[i][column]
street_name = address.gsub(/^((\d[a-zA-Z])|[^a-zA-Z])*/, '')
streets.push(street_name)
i+=1
end
streets.reject(&:empty?)
puts "What do you want the output to be called?"
new_file = gets.chomp
CSV.open(new_file, "w", :write_headers=> true, :headers => [column]) do |hdr|
hdr << streets
end
You should scan the street array and insert it as a row, which means you need to place the line of data into an array before to send to the csv. Ok, maybe the code is simpler than the explanation:
CSV.open(new_file, "w", :write_headers=> true, :headers => [column]) do |csv_line|
streets.each { |street| csv_line << [street] }
end

Ruby - Matching a value and returning a corresponding value from a separate file

I'm looking to match one value (A sku from a website) to the same value (A sku from lookup.csv) and return a corresponding model (From lookup.csv).
Here's sample data from lookup.csv:
SKU , Model
2520045 , DQ.SUNAA.002
7423599 , DA.MX00.1CC
9547543 , DX.MF01.2BM
Here's my code thus far:
url = "http://www.bestbuy.com/site/acer-aspire-23-touch-screen-all-in-one-intel-core-i5-8gb-memory-2tb-hard-drive-black/2520045.p?id=1219547718151&skuId=2520045"
page = Nokogiri::HTML(open(url))
sku = page.css('span#sku-value').text
#model = match the sku to the sku in lookup.csv and return corresponding model
puts model
I know that I can open the file with
open("lookup.csv", 'r')
but past that, I'm not quite sure how to match/return a corresponding value.
Any help is appreciated!
The suggestion of Aoukar would work but be slow with large data sets.
Here a better solution, read the CSV once, using the CSV gem (no need to reinvent the wheel) and store the data in a hash, after that you can just ask fort the right Model, here a working sample.
I'm using the CSV data in the DATA part of the script here so I don't need the CSV file itself.
require "csv"
lookup = {}
CSV.parse(DATA, col_sep: " , ", headers: true, force_quotes: false, :quote_char => "\x00").each do |row|
lookup.merge! Hash[row['SKU'], row['Model']]
end
lookup #{"2520045"=>"DQ.SUNAA.002", "7423599"=>"DA.MX00.1CC", "9547543"=>"DX.MF01.2BM"}
lookup['2520045'] #"DQ.SUNAA.002"
__END__
_ ,SKU , Model #the first element is to work around a bug in CSV used this way
2520045 , DQ.SUNAA.002
7423599 , DA.MX00.1CC
9547543 , DX.MF01.2BM
you can try this code, but I didn't test it so it might need some modifications, I've written it as a function since it's what I'm used to.
def search(path,key) #path to file, and word to search for
File.open(path,'r') do |file| #open file
file.readlines.each { |line| #read lines array
if line.split(' , ')[0] == key #match the SKU
return line.split(' , ')[1] #return the Model
end
}
end
end

Delete a line of information from a text file

I have a text file called text.txt, and it has the following text:
123,shirt,9.99
234,pants,19.50
456,socks,3.99
How do I delete one row (e.g 123,shirt,9.99). How would I go about deleting this row?
My code so far:
test_file = File.new('text.txt', "a")
while (line = test_file)
puts 'Enter the products item number you wish to delete. '
user_delete = gets.chomp.to_i
line.delete(user_delete)
end
You're making a lot of mistakes here.
First of all opening the file with a (you need to use r+ or w+).
In Ruby we use a more elegant to iterate over files.
Check this answer, it will help you with your problem.
After that a look at IO library to understand how it all works
I imagine there are a bunch of better ways to do this, but here's quick and dirty:
puts "What's the item number?"
item_num = gets.chomp
read_file = File.new('read.txt', "r").read
write_file = File.new('read.txt', "w")
read_file.each_line do |line|
write_file.write(line) unless line.include? item_num
end

Reading every line in a CSV and using it to query an API

I have the following Ruby code:
require 'octokit.rb'
require 'csv.rb'
CSV.foreach("actors.csv") do |row|
CSV.open("node_attributes.csv", "wb") do |csv|
csv << [Octokit.user "userid"]
end
end
I have a csv called actors.csv where every row has one entry - a string with a userid.
I want to go through all the rows, and for each row do Octokit.user "userid", and then store the output from each query on a separate row in a CSV - node_attributes.csv.
My code does not seem to do this? How can I modify it to make this work?
require 'csv'
DOC = 'actors.csv'
DOD = 'new_output.csv'
holder = CSV.read(DOC)
You can navigate it by calling
holder[0][0]
=> data in the array
holder[1][0]
=> moar data in array
make sense?
#make this a loop
profile = []
profile[0] = holder[0][0]
profile[1] = holder[1][0]
profile[2] = 'whatever it is you want to store in the new cell'
CSV.open(DOD, "a") do |data|
data << profile.map
end
#end the loop here
That last bit of code will print whatever you want into a new csv file

How to parse a CSV file, update a field, then save

I need to read a CSV file, update a field, then save the changes. I have everything working fine except saving my changes to the field I'm updating:
require 'csv'
#parsed_file = CSV::Reader.parse(File.open("#{RAILS_ROOT}/doc/some.csv"))
#parsed_file.each_with_index do |row, x|
address = row[5]
l = Location.address_find(address)
if l != nil
puts "#{l.name} at #{l.address}"
row[14] = l.store_code
puts row[14]
else
puts "No matching address Found!!!"
end
#What do I do here? Something like this? CSV::Writer.generate(#parsed_file)
end
What do I do here? How do I save the changes I made and update the file?
What I would do is write the updated records to a new file and then, if you want, after you have finished your program can delete the old file and rename the new file to have the original file name.
To do this I would open the output file at the top of your code, outside the each_with_index loop. e.g.
csv_out = CSV::Writer.generate(File.open('new.csv', 'wb'))
Then inside your each_with_index loop you can write the current row to the new file like this:
csv_out << row
Then at the end you can close the new file:
csv_out.close
As mentioned in the comments, CSV::Writer is no longer in the standard library. An equivalent version of the code using the newer CSV.foreach (for reading) and CSV.open (for writing) is:
CSV.open("path/to/updated_file.csv", "wb") do |csv_out|
CSV.foreach("#{RAILS_ROOT}/doc/some.csv") do |row|
address = row[5]
l = Location.address_find(address)
if l != nil
puts "#{l.name} at #{l.address}"
row[14] = l.store_code
puts row[14]
else
puts "No matching address Found!!!"
end
csv_out << row
end
end

Resources