2009-06-11 8 views
5

Tengo una pregunta curiosa. Si tengo una clase de ruby ​​y luego agrego dinámicamente métodos de clase, variables de clase, etc. a ella durante la ejecución, ¿hay alguna forma de que guarde la definición de clase alterada para que la próxima vez que inicie mi aplicación pueda usarla de nuevo?Guardar clases dinámicas de rubí

Respuesta

1

Simplemente ordenar el objeto (como han dicho otros) no funcionará. Veamos un ejemplo. Considere esta clase:

class Extras 
    attr_accessor :contents 
    def test 
    puts "This instance of Extras is OK. Contents is: " + @contents.to_s 
    end 

    def add_method(name) 
    self.class.send :define_method, name.to_sym do 
     puts "Called " + name.to_s 
    end 
    end 
end 

Ahora vamos a escribir un programa que crea una instancia, agrega un método a él y lo guarda en el disco:

require 'extras' 

fresh = Extras.new 
fresh.contents = 314 
fresh.test # outputs "This instance of Extras is OK. Contents is: 314" 
fresh.add_method(:foo) 
fresh.foo # outputs "Called foo" 

serial = Marshal.dump(fresh) 
file = File.new "dumpedExample", 'w' 
file.write serial 

por lo que podemos llamar el método normal 'prueba' y el método dinámico 'foo'. Veamos lo que sucede si se escribe un programa que carga la instancia del ejemplo que se guarda en el disco:

require 'extras' 

file = File.new 'dumpedExample', 'r' 
serial = file.read 

reheated = Marshal.load(serial) 
reheated.test # outputs "This instance of Extras is OK. Contents is 314" 
reheated.foo # throws a NoMethodError exception 

por lo que podemos ver que mientras la instancia (incluyendo los valores de las variables miembro) se guardó el método dinámico no estaba.

Desde el punto de vista del diseño, es probable que sea mejor colocar todo el código agregado en un módulo y cargarlo nuevamente en la clase la próxima vez que ejecute el programa. Sin embargo, necesitaríamos un buen ejemplo de cómo puede usarlo para saber realmente esto.

Si necesita información adicional para volver a crear los métodos, haga que el módulo los guarde como variables de miembro. Implemente included en el módulo y haga que busque estas variables miembro cuando se incluye en la clase.

-1

Estás editando la clase sobre la marcha, y quieres guardar eso? Podría intentar usar el módulo Marshal, le permitirá guardar objetos en un archivo y leerlos en la memoria de forma dinámica.

4

No hay manera integrada para realizar esta acción. Marshal no puede guardar métodos. Si estos métodos y variables se generan de forma sistemática, puede guardar los datos necesarios para que la clase los vuelva a crear. Por ejemplo, si tiene un método make_special_method(purpose, value) que define estos métodos, cree una matriz de los argumentos que necesita pasar a estos métodos y léala cuando desee reconstituir el estado de la clase.

2

Dependiendo de qué signifique exactamente, hay un par de formas de hacerlo.

El caso más simple es aquella en la que ha añadido variables o métodos de una clase ya existente, como en este ejemplo:

class String 
    def rot13 
    return self.tr('a-z', 'n-za-m') 
    end 
end 

Aquí hemos añadido el método rot13 a la clase String. Tan pronto como se ejecute este código, cada String en todas partes de su programa podrá # rot13. Por lo tanto, si tiene algún código que necesita cadenas con capacidad rot13, solo debe asegurarse de que el código anterior se ejecute antes que el código en cuestión, p. poniendo el código rot13 en un archivo en algún lugar y requiriéndolo(). ¡Muy fácil!

Pero tal vez que ha añadido una variable de clase a una clase, y desea preservar no sólo su existencia sino su valor, como en:

class String 
    @@number_of_tr_calls_made = 0 
    # Fix up #tr so that it increments @@number_of_tr_calls_made 
end 

Ahora bien, si desea guardar el valor de @ @number_of_tr_calls_made, puede hacerlo de la misma forma que lo haría con cualquier otro valor de Ruby serializable: a través de la biblioteca de Marshal. ¡También es fácil!

Pero algo en la forma en que formul la pregunta me hace sospechar que estás haciendo algo como esto:

greeting = "Hello" 
class <<greeting 
    def rot13 
    return self.tr('a-z', 'n-za-m') 
    end 
end 
encrypted_greeting = greeting.rot13 

Esto es muy diferente de lo que hicimos en el primer ejemplo. Esa pieza de código le dio a cada Cadena de tu programa el poder de descomponerse13. Este código otorga esa potencia solo al objeto al que se hace referencia con el nombre 'saludo'. Internamente, Ruby hace esto creando una subclase de Singleton anónima de String, añadiéndole el método rot13 y cambiando la clase de saludo a esa subclase anónima.

El problema aquí es que Singletons no puede ser Marshal (para ver por qué, trate de averiguar cómo mantener el invariante de Singleton cuando cualquier llamada a Marshal.load puede generar copias de objetos Singleton existentes). Ahora, el saludo tiene un Singleton en su jerarquía de herencia, por lo que si desea guardarlo y cargarlo, se le aplicará una manguera. Haga una subclase en su lugar:

class HighlySecurableString < String 
    def rot13 
    return self.tr('a-z', 'n-za-m') 
    end 
end 
greeting = HighlySecurableString.new("hello") 
+0

Creo que el asker se estaba refiriendo a los métodos agregados a una clase durante la ejecución. Es decir. métodos metaprogramados. Pude haber entendido mal. – toholio