2012-05-17 11 views

risposta

-2

Si consiglia di aggiungere un metodo personalizzato to_yaml nella classe che costruisce il formato yaml specifico desiderato.

So che to_json accetta parametri per dirgli quali attributi serializzare, ma non riesco a trovare lo stesso per to_yaml.

Ecco la fonte reale per to_yaml:

# File activerecord/lib/active_record/base.rb, line 653 

    def to_yaml(opts = {}) #:nodoc: 
    if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck? 
     super 
    else 
     coder = {} 
     encode_with(coder) 
     YAML.quick_emit(self, opts) do |out| 
     out.map(taguri, to_yaml_style) do |map| 
      coder.each { |k, v| map.add(k, v) } 
     end 
     end 
    end 
    end 

modo che appaia come ci può essere l'occasione per impostare opts in modo che include specifiche coppie chiave/valore nel YAML.

8

Dopo una quantità eccessiva di ricerca mi sono imbattuto in questo:

class Point 
    def to_yaml_properties 
    ["@x", "@y"] 
    end 
end 

Questo metodo viene utilizzato per selezionare le proprietà che YAML serializzarli. C'è un approccio più potente che coinvolge emettitori personalizzati (in Psicologia), ma non so cosa sia.

Questa soluzione funziona solo in Ruby 1.8; in Ruby 1.9, to_yaml è passato a utilizzare Psych, per cui la risposta di Matt utilizzando encode_with è la soluzione appropriata.

22

In Ruby 1.9, to_yaml_properties is deprecated; se si sta utilizzando Ruby 1.9, un metodo a prova più futuro sarebbe quella di utilizzare encode_with:

class Point 
    def encode_with coder 
    coder['x'] = @x 
    coder['y'] = @y 
    end 
end 

In questo caso questo è tutto ciò che serve, come il valore predefinito è di impostare la variabile di istanza corrispondente del nuovo oggetto al valore appropriato durante il caricamento da Yaml, ma nei casi più comple si potrebbe usare init_with:

def init_with coder 
    @x = coder['x'] 
    @y = coder['y'] 
end 
+0

FYI: Se si sovrascrive '# init_with' per un ActiveRecord :: base' sottoclasse', ricordarsi di tornare 'self', altrimenti ogni volta che si crea un'istanza di un modello lo farà ritorno nil. – siannopollo

1

Se volete tutti i campi, ma pochi, si potrebbe fare questo

def encode_with(coder) 
    vars = instance_variables.map{|x| x.to_s} 
    vars = vars - ['@unwanted_field1', '@unwanted_field2'] 

    vars.each do |var| 
    var_val = eval(var) 
    coder[var.gsub('@', '')] = var_val 
    end 
end 

Questo ti impedisce di dover gestire manualmente l'elenco. Testato su Ruby 1.9

1

Se avete un sacco di variabili di istanza, è possibile utilizzare una versione breve come questo

def encode_with(coder) 
    %w[ x y a b c d e f g ].each { |v| coder[ v ] = instance_variable_get "@#{v}" } 
end 
0

Si consiglia di utilizzare #encode_with perché #to_yaml_properties è deprecato:

def encode_with(coder) 
    # remove @unwanted and @other_unwanted variable from the dump 
    (instance_variables - [:@unwanted, :@other_unwanted]).each do |var| 
    var = var.to_s      # convert symbol to string 
    coder[var.gsub('@', '')] = eval(var) # set key and value in coder hash 
    end 
end 

oppure potresti preferirlo se eval è troppo pericoloso e devi solo filtrare una variante var. Tutti gli altri Vars bisogno di avere una funzione di accesso:

attr_accessor :keep_this, :unwanted 

def encode_with(coder) 
    # reject @unwanted var, all others need to have an accessor 
    instance_variables.reject{|x|x==:@unwanted}.map(&:to_s).each do |var| 
    coder[var[1..-1]] = send(var[1..-1]) 
    end 
end 
+0

Aggiungi alcuni commenti alla tua risposta. – HDJEMAI

Problemi correlati