Получение информации в Transmogrifier
В нашем последнем эпизоде мы преобразовали данные из одного формата в другой. Теперь вам нужно ввести данные в него, используя трансмогрификатор. Мы могли бы жестко закодировать имена файлов там, но это нас преследует. Давайте сделаем так, чтобы мы могли загрузить файл определения, файл данных и имя выходного файла.
Вам нужно будет прочитать файл данных CSV. Как вы читаете файл построчно в Ruby?
require 'csv'
File.open("def.txt") do |file|
while line = file.gets
puts line
end
end
Вы можете сохранить файл. Я сохранил его как transmogrifier.rb
Вы можете пойти дальше и запустить его.
$ ruby transmogrifier.rb
FIELD NAME FORMAT
NAME A(50)
ADDRESS1 A(50)
ADDRESS2 A(50)
CITY A(50)
STATE A(2)
ZIP A(10)
CONTACT A(50)
CONTACTPHONE A(10)
ACCOUNTOPENED 9(8)
Оно работает. У нас есть данные, теперь нам нужно загрузить определения. В transmogrifier.rb добавьте код, чтобы сделать это. Помните, что делать?
File.open("data.csv") do |file|
while line = file.gets
puts line
end
end
Если вам любопытно идти вперед и запустить его.
Теперь, когда у вас есть определения и загруженные данные, вам нужно отправить их в трансмогрификатор. Вам необходимо отправить данные, длину поля, тип и имя столбца. Три из четырех получены из файла определения.
Давайте выпишем тип, длину и имя поля. Имя поля начинается с начала строки
Мы могли бы разбить строку и поместить ее в массив. Поскольку файл использует пробелы, а не символы табуляции, для выравнивания мы можем использовать разделение.
require 'csv'
definitions = Array.new
File.open("def.txt") do |file|
while line = file.gets
definitions = line.split()
puts definitions[0]
puts definitions[1]
end
end
...
Это дает нам имя поля, но тип и длина все еще вместе. Вы думали о регулярных выражениях, чтобы найти тип и длину?
require 'csv'
definitions = Array.new
File.open("def.txt") do |file|
while line = file.gets
definitions = line.split()
field = definitions[0]
type = definitions[1] =~ /9/? '9' : 'A'
length = definitions[1].slice(1..definitions[1].length).gsub(/[^0-9]/, "")
puts 'field => ' + field.upcase + ' type => ' + type + ' length => ' + length.to_s
end
end
Давай, беги.
$ ruby transmogrifier.rb
field => FIELD type => A length =>
field => NAME type => A length => 50
field => ADDRESS1 type => A length => 50
field => ADDRESS2 type => A length => 50
field => CITY type => A length => 50
field => STATE type => A length => 2
field => ZIP type => A length => 10
field => CONTACT type => A length => 50
field => CONTACTPHONE type => A length => 10
field => ACCOUNTOPENED type => 9 length => 8
Теперь мы куда-то добираемся. Три из четырех переменных, которые передаются в трансмогрификатор. Маниакальный смех.
Один Квестон.
Как вы думаете, вы получите данные в этот массив?
Что если мы бросим массив в хеш? Затем перенесите этот хеш в другой хеш, где ключом является имя поля, а данные взяты из первого хеша.
Все, что нам нужно сделать, это перебрать данные, найти ключ из хэша, который идет с этим столбцом, и отправить все это в трансмогрификатор. Здесь все просто.
Во-первых, перейдите и поместите данные определения в хеш. Затем добавьте это в хеш. Ради интереса, выведите последний хеш, чтобы мы могли его увидеть.
require 'csv'
object_name = Hash.new
definitions = Array.new
File.open("def.txt") do |file|
while line = file.gets
definitions = line.split()
field = definitions[0]
type = definitions[1] =~ /9/? '9' : 'A'
length = definitions[1].slice(1..definitions[1].length).gsub(/[^0-9]/, "")
object_formatting = Hash.new
object_formatting["type"] = type
object_formatting["length"] = length
object_formatting["field"] = field
object_name[field.upcase] = object_formatting
end
end
puts object_name
Запустите его и давайте посмотрим, что у нас есть.
$ ruby transmogrifier.rb
{"FIELD"=>{"type"=>"A", "length"=>"", "field"=>"FIELD"}, "NAME"=>{"type"=>"A", "length"=>"50", "field"=>"NAME"}, "ADDRESS1"=>{"type"=>"A", "length"=>"50", "field"=>"ADDRESS1"}, "ADDRESS2"=>{"type"=>"A", "length"=>"50", "field"=>"ADDRESS2"}, "CITY"=>{"type"=>"A", "length"=>"50", "field"=>"CITY"}, "STATE"=>{"type"=>"A", "length"=>"2", "field"=>"STATE"}, "ZIP"=>{"type"=>"A", "length"=>"10", "field"=>"ZIP"}, "CONTACT"=>{"type"=>"A", "length"=>"50", "field"=>"CONTACT"}, "CONTACTPHONE"=>{"type"=>"A", "length"=>"10", "field"=>"CONTACTPHONE"}, "ACCOUNTOPENED"=>{"type"=>"9", "length"=>"8", "field"=>"ACCOUNTOPENED"}}
...
Прекрасный. Теперь вам нужно обработать файл данных. Давайте получим имя поля и данные для этого столбца
CSV.foreach("data.csv", headers: true) do |data|
data.headers.each do |field|
puts field + ' => ' + data[field].to_s
end
end
Оставайтесь на линии! Что это за вызов CVS.foreach ()? Давайте посмотрим на это .
Эта строка будет обрабатывать файл CSV и обрабатывать первую строку как заголовок, а не как данные.
Когда вы запускаете, вы должны выглядеть так
name => Wonder widgets
address1 => 1600 Vassar Street
address2 =>
city => dallas
state => tx
zip => 75220
contact => Tim Smith
contactPhone => 214-555-1212
accountOpened => 12052001
name => Timmy's Bikes
address1 => 2723 Auburn Street
address2 => Building 3
city => Erie
state => PA
zip => 16508-1234
contact =>
contactPhone => 814-555-4321
accountOpened => 865289
Мы почти дома.
Теперь у нас есть данные и определения. Давайте отправим эту информацию в трансмогрификатор.
Когда мы перебираем данные, нам нужно найти соответствующий ключ из хеша, который мы сделали ранее. Когда мы сопоставим его, отправьте его в трансмогрификатор
CSV.foreach("data.csv", headers: true) do |data|
data.headers.each do |field|
object_name.each do |key,value|
if field.upcase == key
field.upcase!
line = transmogrifier(data[field].to_s, object_name[field]["length"].to_i, object_name[field]["type"], field)
print line
end
end
end
puts ' '
puts ' --------- '
end
Это сделает все, о чем мы говорили. Если бы мы написали тесты, как в первой части, мы бы поймали кучу ошибок. Что делать, если нет данных для столбца? Как мы получаем все данные в одной строке? Как мы сохраняем данные? Как мы передаем определения и имена файлов данных?
Вот что я придумал перед рефакторингом
require 'csv'
def transmogrifier(data,len,type,column)
proper_formatted = ''
unless data.nil?
case
when data.length > len
data = data.slice(0..(len-1))
when data.length < len
if type == "A"
data = data.ljust(len)
else
data = data.rjust(len)
end
else
if column == "ACCOUNTOPENED"
data = data.slice(4..7)+data.slice(0..3)
else
data
end
end
proper_formatted += data
end
proper_formatted += '|' # added pipes to see where the field ends
proper_formatted
end
object_name = Hash.new
file = File.new(ARGV[0],"r")
definitions = Array.new
while (line = file.gets)
definitions = line.split()
field = definitions[0]
type = definitions[1] =~ /9/? '9' : 'A'
length = definitions[1].slice(1..definitions[1].length).gsub(/[^0-9]/, "")
object_formatting = Hash.new
object_formatting["type"] = type
object_formatting["length"] = length
object_formatting["field"] = field
object_name[field.upcase] = object_formatting
end
file.close
aFile = File.new(ARGV[2], "w")
CSV.foreach(ARGV[1], headers: true) do |data|
data.headers.each do |field|
object_name.each do |key,value|
if field.upcase == key
field.upcase!
line = transmogrifier(data[field].to_s, object_name[field]["length"].to_i, object_name[field]["type"], field)
aFile.write(line)
print line #so you can see something in the terminal window
end
end
end
aFile.write("n")
puts ' '
puts ' --------- '
end
aFile.close
Если вы запустите $ ruby transmogrifier.rb def.txt data.csv formated.txt
В папке, в которой вы работаете, должен быть новый файл с именем formated.txt.
А теперь иди и преобрази маниакальный смех.