Por ejemplo,Cómo puedo controlar qué campos para serializar con YAML
class Point
attr_accessor :x, :y, :pointer_to_something_huge
end
sólo desea realizar una serie X e Y y dejar todo lo demás como nula.
Por ejemplo,Cómo puedo controlar qué campos para serializar con YAML
class Point
attr_accessor :x, :y, :pointer_to_something_huge
end
sólo desea realizar una serie X e Y y dejar todo lo demás como nula.
Recomiendo agregar un método to_yaml
personalizado en su clase que construye el formato yaml específico que desea.
Sé que to_json
acepta parámetros para indicarle qué atributos serializar, pero no puedo encontrar lo mismo para to_yaml
.
Aquí está la fuente real de 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
lo que parece que puede haber una oportunidad para establecer opts
para que incluya pares clave/valor específicos en el yaml.
Después de una cantidad excesiva de búsqueda me encontré con esto:
class Point
def to_yaml_properties
["@x", "@y"]
end
end
Este método se utiliza para seleccionar las propiedades que YAML serializa el procesamiento. Existe un enfoque más poderoso que involucra emisores personalizados (en Psych) pero no sé de qué se trata.
Esta solución solo funciona en Ruby 1.8; en Ruby 1.9, to_yaml
ha cambiado a usar Psych, para lo cual la respuesta de Matt es encode_with
.
En Ruby 1.9, to_yaml_properties
is deprecated; si está usando Ruby 1.9, un método de prueba más futuro sería utilizar encode_with
:
class Point
def encode_with coder
coder['x'] = @x
coder['y'] = @y
end
end
En este caso, eso es todo lo que necesita, como el valor predeterminado es establecer la variable de instancia correspondiente del nuevo objeto a la valor apropiado cuando se carga de Yaml, pero en casos más comple se podría utilizar init_with
:
def init_with coder
@x = coder['x']
@y = coder['y']
end
Si desea que todos los campos, pero unos pocos, que podría hacer esto
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
Esto le impide tener que administrar manualmente la lista. Probado en Ruby 1.9
Si usted tiene un montón de variables de instancia, se puede usar una versión corta como ésta
def encode_with(coder)
%w[ x y a b c d e f g ].each { |v| coder[ v ] = instance_variable_get "@#{v}" }
end
Debe utilizar #encode_with porque #to_yaml_properties está en desuso:
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
o puede preferir esto si eval es demasiado peligroso y solo necesita filtrar una instancia de var. Todos los otros VARs necesitan tener un descriptor de acceso:
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
Agregue algunos comentarios a su respuesta. – HDJEMAI
FYI: Si sobrescribe # '' init_with' para una subclase de ActiveRecord :: base', recuerde que debe volver 'self', de lo contrario cualquier momento se instancia un modelo que lo hará devuelve nil. – siannopollo