deserializar un objeto de Yaml no utiliza el método initialize
porque en general no hay correspondencia entre las variables de instancia de objetos (que es lo que almacena la serialización Yaml predeterminada) y los parámetros a initialize
.
Como un ejemplo, considere un objeto con una initialize
que tiene este aspecto (sin otras variables de instancia):
def initialize(param_one, param_two)
@a_variable = some_calculation(param_one, param_two)
end
Ahora, cuando se deserializa una instancia de este, el procesador Yaml tiene un valor para @a_variable
, pero el método initialize
requiere dos parámetros, por lo que no puede llamarlo. Incluso si el número de variables de instancia coincide con el número de parámetros a initialize
, no es necesariamente el caso de que se correspondan, e incluso si lo hicieron, el procesador no sabe el orden en que deben pasar a initialize
.
El proceso predeterminado para serializar y deserializar un objeto Ruby en Yaml es escribir todas las variables de instancia (con sus nombres) durante la serialización, luego al deserializar asignar una nueva instancia de la clase y simplemente establecer las mismas variables de instancia en este nueva instancia.
Por supuesto, a veces necesita más control de este proceso. Si está utilizando el procesador Psych Yaml (que es el predeterminado en Ruby 1.9.3), entonces debe implementar los métodos encode_with
(para la serialización) o init_with
(para la deserialización) según corresponda.
Para la serialización, Psych llamará al método encode_with
de un objeto si está presente, pasando un coder
object. Este objeto te permite especificar cómo se debe representar el objeto en Yaml, normalmente lo tratas como un hash.
Para la deserialización, Psych llamará al método init_with
si está presente en su objeto en lugar de utilizar el procedimiento predeterminado descrito anteriormente, pasando de nuevo un objeto coder
. Esta vez, el coder
contendrá la información sobre la representación de los objetos en Yaml.
Tenga en cuenta que no necesita proporcionar ambos métodos, solo puede proporcionar uno si lo desea. Si proporciona ambos, el objeto coder
que obtenga pasado en init_with
será esencialmente el mismo que pasó a encode_with
después de que se haya ejecutado ese método.
Como ejemplo, considere un objeto que tiene algunas variables de instancia que se calculan a partir de otras (tal vez como una optimización para evitar un cálculo grande), pero no se debe serializar en Yaml.
class Foo
def initialize(first, second)
@first = first
@second = second
@calculated = expensive_calculation(@first, @second)
end
def encode_with(coder)
# @calculated shouldn’t be serialized, so we just add the other two.
# We could provide different names to use in the Yaml here if we
# wanted (as long as the same names are used in init_with).
coder['first'] = @first
coder['second'] = @second
end
def init_with(coder)
# The Yaml only contains values for @first and @second, we need to
# recalculate @calculated so the object is valid.
@first = coder['first']
@second = coder['second']
@calculated = expensive_calculation(@first, @second)
end
# The expensive calculation
def expensive_calculation(a, b)
...
end
end
Al volcar una instancia de esta clase para Yaml, que se verá algo como esto, sin el valor calculated
:
--- !ruby/object:Foo
first: 1
second: 2
Al cargar este Yaml de nuevo en Rubí, el objeto creado se tener la variable de instancia @calculated
establecida.
Si usted quería podía llamada initialize
desde dentro init_with
, pero yo creo que sería mejor mantener la separación clara entre la inicialización de un nueva instancia de la clase, y deserializar un ejemplo existente de Yaml . Recomendaría extraer la lógica común en métodos que se pueden llamar desde ambos en su lugar,
Posible duplicado: http: // stackoverflow.com/questions/1823386/calling-initialize-when-loading-an-object-serialized-with-yaml –
Esa publicación es útil, sin embargo, no resuelve por completo mi problema. La secuencia YAML que estoy analizando es más compleja que un solo objeto, son muchos objetos, algunos de los cuales están compuestos por otros. – clementine
Lo siento, solo lo intento. Tal vez esto sea más útil: para averiguar por qué _ 'YAML :: load' does _not_ call' initialize', compruebe la fuente. : P O tal vez podemos esperar un respondedor que sepa más de los detalles. Intenté 'pone d.class == c.class' en tu script y encontré que era verdadero. Entonces +1 en tu pregunta. –