Разбор Ruby Array of Hash - PullRequest
       7

Разбор Ruby Array of Hash

0 голосов
/ 30 апреля 2018

У меня есть файл yaml в формате:

parameters:
  - param_name: age
    requires:
    - name
  - param_name: height
    requires:
    - name

Исходя из этого формата, я хотел бы принять хеш ключей и значений и определить, является ли комбинация ключей и значений допустимой. Например, на основе приведенного выше примера, если кто-то отправил хэш со значениями:

{'age' => 15, 'height' => '6ft'}

это будет считаться недействительным, так как имя параметра является обязательным. Таким образом, действительное представление будет выглядеть как

{'age' => 15, 'height' => '6ft', 'name' => 'Abe Lincoln'}.

По сути, я хочу вот что:

Для каждого объекта параметра, если у него есть массив require под ним. Проверьте все параметры param_names для элементов в этом массиве, если таковые отсутствуют, выход.

У меня очень уродливый двойной цикл, который проверяет это, но я хочу ужесточить код. Я думаю, что могу использовать блоки для проверки нужных мне данных. Вот что я придумала до сих пор:

require 'yaml'
requirements = YAML.load_file('./require.yaml')
require_fields = Array.new

requirements['parameters'].each do |param|
  require_fields.concat(param['require']) if param.has_key? 'require'
end

require_fields.each do |requirement|
  found = false
  requirements['parameters'].each do |param|
    if param['param_name'] == requirement
      found = true
    end
  end
  abort "#{requirement} is a required field" unless found
end

Ответы [ 2 ]

0 голосов
/ 01 мая 2018

Я бы пошел с последующими проверками, собирая ошибки и сообщая все сразу:

req = YAML.load 'parameters:
  - param_name: age
    requires:
    - name
  - param_name: height
    requires:
    - name'
input = {'age' => 15, 'height' => '6ft'}

req['parameters'].each_with_object([]) do |req, err|
  next unless input[req['param_name']] # nothing to check
  missed = req['requires'].reject { |param| input[param] }
  errors = missed.map do |param|
    [req['param_name'], param].join(' requires ')
  end
  err.concat(errors)
end
#⇒ ["age requires name", "height requires name"]

Или, цепочка:

req['parameters'].each_with_object(Hash.new { |h, k| h[k] = [] }) do |req, err|
  next unless input[req['param_name']] # nothing to check

  req['requires'].each do |param|
    err[param] << req['param_name'] unless input[param]
  end
end.map do |missing, required|
  "Missing #{missing} parameter, required for: [#{required.join(', ')}]"
end.join(',')
#⇒ "Missing name parameter, required for: [age, height]"
0 голосов
/ 30 апреля 2018

Вы можете убрать это много, если сделаете его более идиоматичным Ruby:

require 'yaml'
requirements = YAML.load_file('./require.yaml')

require_fields = requirements['parameters'].select do |param|
  param.has_key?('require')
end.map do |param|
  param['require']
end

require_fields.each do |requirement|
  found = requirements['parameters'].any? do |param|
    param['param_name'] == requirement
  end

  abort "#{requirement} is a required field" unless found
end

Вы также можете сделать это:

require_fields = requirements['parameters'].map do |param|
  param['require']
end.compact

Там, где это, вероятно, достаточно хорошо, если ваш require является чем-то или nil.

Вы также можете преобразовать этот входной YAML в простую хеш-структуру зависимостей:

dependencies = requirements.map do ||
  [ param['param_name'], param['requires'] ]
end.to_h

Тогда вы можете проверить очень легко:

dependencies.each do |name, requirements|
  found = requirements.find do |required_name|
    !dependencies[required_name]
  end

  abort "#{found} is a required field" unless found
end

Это действительно грубая адаптация вашего кода, но я надеюсь, что он даст вам некоторые идеи.

...