Per esempio,Come posso controllare quali campi per serializzare con YAML
class Point
attr_accessor :x, :y, :pointer_to_something_huge
end
voglio solo serializzare x e y e lasciare tutto il resto come nullo.
Per esempio,Come posso controllare quali campi per serializzare con YAML
class Point
attr_accessor :x, :y, :pointer_to_something_huge
end
voglio solo serializzare x e y e lasciare tutto il resto come nullo.
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.
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.
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
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
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
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
Aggiungi alcuni commenti alla tua risposta. – HDJEMAI
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