Как мне разобрать поле в файле YAML на еще три поля в том же файле?
У меня есть файл YAML, содержащий:
cat:
name: Cat
description: catlike reflexes
dog:
name: Dog
description: doggy breath
Я хочу разобрать его и разбить описание на key1
а также key2
вот так:
cat:
name: Cat
description: catlike reflexes
info:
key1: catlike
key2: reflexes
dog:
name: Dog
description: doggy breath
info:
key1: doggy
key2: breath
Но по какой-то причине я не могу сделать это правильно. До сих пор я пробовал варианты приведенного ниже кода, которые, как мне кажется, я слишком усложняю:
# to get the original file's data
some_data = YAML.load(File.open("#{Rails.root}/config/some_data.yml"))
new_data = some_data.collect do |old_animal|
animal = old_animal.second
if animal && animal["description"]
new_blocks = Hash.new
blocks = animal["description"].split(" ")
new_blocks["key1"] = blocks.first
new_blocks["key2"] = blocks.second
animal["info"] = new_blocks
end
old_animal.second = animal
old_animal
end
# to write over the original file
File.write("#{Rails.root}/config/some_data.yml", new_data.to_yaml)
1 ответ
Решение
Вы не говорите, можете ли вы описать несколько слов в описании, но это вполне логично, поэтому я бы сделал что-то вроде этого:
require 'yaml'
data = YAML.load(<<EOT)
cat:
name: Cat
description: catlike reflexes rules
dog:
name: Dog
description: doggy breath
EOT
data # => {"cat"=>{"name"=>"Cat", "description"=>"catlike reflexes rules"}, "dog"=>{"name"=>"Dog", "description"=>"doggy breath"}}
В этот момент данные из файла YAML загружаются в хеш. Выполните итерацию по каждой паре хэш-ключ / значение:
data.each do |(k, v)|
descriptions = v['description'].split
keys = descriptions.each_with_object([]) { |o, m| m << "key#{(m.size + 1)}" }
hash = keys.each_with_object({}) { |o, m| m[o] = descriptions.shift }
data[k]['info'] = hash
end
Вот что мы получили:
data # => {"cat"=>{"name"=>"Cat", "description"=>"catlike reflexes rules", "info"=>{"key1"=>"catlike", "key2"=>"reflexes", "key3"=>"rules"}}, "dog"=>{"name"=>"Dog", "description"=>"doggy breath", "info"=>{"key1"=>"doggy", "key2"=>"breath"}}}
И как бы это выглядело, если бы выводился:
puts data.to_yaml
# >> ---
# >> cat:
# >> name: Cat
# >> description: catlike reflexes rules
# >> info:
# >> key1: catlike
# >> key2: reflexes
# >> key3: rules
# >> dog:
# >> name: Dog
# >> description: doggy breath
# >> info:
# >> key1: doggy
# >> key2: breath
each_with_object
похож на inject
но немного чище для использования, потому что это не требует возврата объекта, в который мы накапливаем.