Как вывести отсортированный хеш в шаблоне ruby - PullRequest
7 голосов
/ 16 марта 2012

Я создаю файл конфигурации для одного из наших встроенных приложений. По сути, это файл JSON. У меня много проблем с тем, чтобы puppet / ruby ​​1.8 каждый раз выводил hash / json одинаково.

Я сейчас использую

<%= require "json"; JSON.pretty_generate data %>

Но при выводе удобочитаемого контента каждый раз он не гарантирует один и тот же порядок. Это означает, что марионетка будет отправлять уведомления об изменениях для одних и тех же данных.

Я тоже пробовал

<%= require "json"; JSON.pretty_generate Hash[*data.sort.flatten] %>

Который будет генерировать одни и те же данные / заказ каждый раз. Проблема возникает, когда данные имеют вложенный массив.

data => { beanstalkd => [ "server1", ] }

становится

"beanstalkd": "server1",

вместо

"beanstalkd": ["server1"],

Я боролся с этим уже несколько дней, поэтому хотел бы помочь

Ответы [ 2 ]

3 голосов
/ 13 апреля 2015

Так как хэши в Ruby упорядочены , а вопрос помечен , вот метод, который будет рекурсивно сортировать хэш (без влияния на порядок массивов):

def sort_hash(h)
  {}.tap do |h2|
    h.sort.each do |k,v|
      h2[k] = v.is_a?(Hash) ? sort_hash(v) : v
    end
  end
end

h = {a:9, d:[3,1,2], c:{b:17, a:42}, b:2 }
p sort_hash(h)
#=> {:a=>9, :b=>2, :c=>{:a=>42, :b=>17}, :d=>[3, 1, 2]}

require 'json'
puts sort_hash(h).to_json
#=> {"a":9,"b":2,"c":{"a":42,"b":17},"d":[3,1,2]}

Обратите внимание, что это приведет к катастрофическим сбоям, если в вашем хэше есть ключи, которые невозможно сравнить. (Если ваши данные поступают из JSON, это не так, поскольку все ключи будут строками.)

0 голосов
/ 16 марта 2012

Хеш - это неупорядоченная структура данных. В некоторых языках (например, ruby) есть упорядоченная версия хэша, но в большинстве случаев в большинстве языков не следует полагаться на какой-либо определенный порядок в хэше.

Если порядок важен для вас, вы должны использовать массив. Итак, ваш хэш

{a: 1, b: 2}

становится этим

[{a: 1}, {b: 2}]

Я думаю, это не вызывает слишком много изменений в вашем коде.

Обходной путь в вашей ситуации

Попробуйте это:

data = {beanstalkId: ['server1'], ccc: 2, aaa: 3}

data2 = data.keys.sort.map {|k| [k, data[k]]}

puts Hash[data2]
#=> {:aaa=>3, :beanstalkId=>["server1"], :ccc=>2}
...