首页 > 解决方案 > 使用 Ruby 替换 YAML 文件中的兄弟值

问题描述

我有一个包含数百家商店的 yaml 文件。这是一个例子:

- store_number: "1"
  title_tag: "Title tag for store 1"
  meta_description: "Description of store 1"
  store_details: "Details of store 1"
  find_us:
- store_number: "2"
  title_tag: "Title tag for store 2"
  meta_description: "Description of store 2"
  store_details: "Details of store 2"
  find_us:

我需要遍历其中的每一个,比较商店编号,如果匹配,则向find_us键添加一个值。

我已经能够使用这个搜索文件:

stores_file = YAML.load_file('_data/stores.yml')
stores_file.select do |store|
  if store['store_number'] == '1'
    puts store
  end
end

这按预期打印:

{"store_number"=>"1", "title_tag"=>"Title tag for store 1", "meta_description"=>"Description of store 1", "store_details"=>"Details of store 1", "find_us"=>nil}

我有两个问题,我不知道如何找到兄弟姐妹(find_us在这种情况下),我不知道如何写入find_us密钥。

标签: ruby

解决方案


Use YAML::Store

With just a little refactoring, you can essentially treat your YAML file as a transactional flat-file database using YAML::Store from the Ruby Standard Library. In order to iterate, though, you will probably need to ensure you have a single root in your YAML data store, rather than an array of hashes as you appear to have now. For example, given:

# _data/stores.yml

---
stores:
  - store_number: "1"
    title_tag: "Title tag for store 1"
    meta_description: "Description of store 1"
    store_details: "Details of store 1"
    find_us:
  - store_number: "2"
    title_tag: "Title tag for store 2"
    meta_description: "Description of store 2"
    store_details: "Details of store 2"
    find_us:
require 'yaml/store'

@db = YAML::Store.new '_data/stores.yml'

def update_find_us_for store_number, value
  # coerce arguments to String objects
  store_number, value = [store_number, value].map &:to_s
 
  # completed transactions write the results back to the
  # YAML data store for you
  @db.transaction do
    @db['stores'].each do |store|
      store['find_us'] = value if store['store_number'] == store_number
    end
  end
end

update_find_us_for 1, 'foo'

Validate Expected Results

Validate in IRB

If you ran the code above in irb, you can validate that you made the changes you expected with pp _.first, which should print:

{"store_number"=>"1",
 "title_tag"=>"Title tag for store 1",
 "meta_description"=>"Description of store 1",
 "store_details"=>"Details of store 1",
 "find_us"=>"foo"}

Validate Programmatically

You can get at the changed data through instance variables, too. For example:

@db.instance_variable_get(:@table)['stores'].first.fetch 'find_us'
#=> "foo"

Validate at Shell Prompt

If you'd rather validate the stores.yml file directly, then from the Bash shell:

grep -A4 "store_number: '1'" _data/stores.yml 
- store_number: '1'
  title_tag: Title tag for store 1
  meta_description: Description of store 1
  store_details: Details of store 1
  find_us: foo

推荐阅读