2013-02-06 9 views
6

Sto generando una configurazione per il mio servizio in attributi chef. Tuttavia, a un certo punto, ho bisogno di trasformare l'attributo mash in un semplice hash rubino. Questo funzionava bene in Chef 10:chef 11: un modo per trasformare gli attributi in un hash rubino?

node.myapp.config.to_hash 

Tuttavia, a partire da Chef 11, questo non funziona. Solo il livello principale dell'attributo viene convertito in un hash, con i valori nidificati che rimangono oggetti mash immutabili. modificandole porta a errori come questo:

Chef :: Eccezioni :: ImmutableAttributeModification ---------------------------- -------------------- Gli attributi dei nodi sono di sola lettura quando non si specifica il livello di precedenza da impostare. Per impostare un codice di utilizzo dell'attributo come `node.default [ "chiave"] = "valore"'

Ho provato un sacco di modi per aggirare questo problema che non funzionano:

node.myapp.config.dup.to_hash 
JSON.parse(node.myapp.config.to_json) 

jSON parsing hack, che sembra che dovrebbe grande lavoro, si traduce in:

JSON::ParserError 
unexpected token at '"#<Chef::Node::Attribute:0x000000020eee88>"' 

c'è un modo effettivo affidabile, a corto di tra cui una funzione di parsing annidata in ogni libro di cucina, per convertire gli attributi ad una semplice , ordinario, vai od un vecchio hash rubino?

+1

Perché avete bisogno di hash? –

+0

non ne ho bisogno - potrei smettere ogni volta che voglio! ma seriamente, sto costruendo un file di configurazione con molti attributi disparati, e ho bisogno di modificarli prima di scriverli nel file di configurazione. è molto utile convertire gli attributi in un hash, mutarli e quindi usare l'hash. –

risposta

7

dopo un clamoroso mancanza di risposte sia qui che sulla mailing list Opscode cuoco, ho finito per usare il seguente trucco:

class Chef 
    class Node 
    class ImmutableMash 
     def to_hash 
     h = {} 
     self.each do |k,v| 
      if v.respond_to?('to_hash') 
      h[k] = v.to_hash 
      else 
      h[k] = v 
      end 
     end 
     return h 
     end 
    end 
    end 
end 

ho messo questo nelle librerie dir nel mio libro di cucina; ora posso usare attribute.to_hash sia in chef 10 (che ha già funzionato correttamente e che non è influenzato da questa patch di scimmia) sia nello chef 11. Ho anche segnalato questo come un bug per l'opscode:

se non si t voglia di scimmia-patch il tuo chef, parlare su questo problema: http://tickets.opscode.com/browse/CHEF-3857

+0

BTW non funziona se l'hash contiene array – David

+1

Aggiornato con una versione che sembra funzionare con gli array. – David

+0

Non ho potuto accettare la modifica suggerita da David, quindi ne ho tratto un esempio: https: //gist.github.com/igor47/5997028; non ho dovuto superare il problema degli array annidati, ma sarebbe sicuramente un problema. –

-1

La risposta di cui sopra è un po 'inutile. Si può solo fare questo:

json = node[:whatever][:whatever].to_hash.to_json 
JSON.parse(json) 
+0

questo non è vero; poiché 'to_hash' è superficiale, finirai con gli oggetti' ImmutableMash' come valori. la funzione 'to_json' non sa come gestire questo tipo di oggetto e baruffa. questo è il punto centrale di questa domanda. –

2

Ho avuto lo stesso problema e dopo molto l'hacking intorno arrivato fino a questo:

json_string = node[:attr_tree].inspect.gsub(/\=\>/,':') 
my_hash = JSON.parse(json_string, {:symbolize_names => true}) 

ispezionare fa il parsing profonda che manca dagli altri metodi di lavoro proposti e io finire con un hash che posso modificare e passare in giro secondo necessità.

+0

Per un 1-liner, '' 'JSON.parse (hash.to_json, symbolize_names: true)' ''. Abbastanza malvagio, ma molto più facile da gestire rispetto a soluzioni più complesse. – Afforess

1

spero io non sono troppo in ritardo alla festa, ma la fusione l'oggetto nodo con un hash vuoto ha fatto per me:

chef (12.6.0)> {}.merge(node).class 
=> Hash 
Problemi correlati