He intentado configurar un sistema mediante el cual puedo generar una serie de clases de Ruby similares, distinguidas por un parámetro entero, que guardo en una variable de clase de la clase relevante, algo parecido a las plantillas de C++.Clases definidas dinámicamente que comparten datos de forma incorrecta: error o error de codificación.
Sin embargo, la referencia (y, por lo tanto, la creación) de una nueva versión de la clase con plantilla sobrescribe los parámetros guardados en las versiones anteriores, y no sé por qué.
He aquí un ejemplo mínimo
class Object
def self.const_missing(name)
if name =~ /^Templ(\d+)$/
return make_templ $1.to_i
else
raise NameError.new("uninitialised constant #{name}")
end
end
private
def make_templ(base)
# Make sure we don't define twice
if Object.const_defined? "Templ#{base}"
return Object.const_get "Templ#{base}"
else
# Define a stub class
Object.class_eval "class Templ#{base}; end"
# Open the class and define the actual things we need.
Object.const_get("Templ#{base}").class_exec(base) do |in_base|
@@base = in_base
def initialize
puts "Inited with base == #{@@base}"
end
end
Object.const_get("Templ#{base}")
end
end
end
irb(main):002:0> Templ1.new
Inited with base == 1
=> #<Templ1:0x26c11c8>
irb(main):003:0> Templ2.new
Inited with base == 2
=> #<Templ2:0x20a8370>
irb(main):004:0> Templ1.new
Inited with base == 2
=> #<Templ1:0x261d908>
¿He encontrado un fallo en mi Ruby (Ruby 1.9.2p290 (2011-07-09) [i386-mingw32]), o tiene simplemente codificado algo mal?
Bueno, dediqué 45 minutos tratando de resolver esto, y supuse que algo andaba mal con las encuadernaciones variables porque estás ejecutando un bloque dentro de la clase 'Object'. Sin embargo, no me puedo atribuir la respuesta porque finalmente encontré la explicación como se sospecha aquí: http://stackoverflow.com/questions/10109925/ruby-unexpected-results-from-class-exec-when-defining-class- variable . Su solución es convertir ese bloque en una cadena y evaluarlo para que se compile en el contexto correcto. – Casper
@Casper cuando la respuesta es "usar evaluación de cadena en lugar de evaluación de bloque", generalmente es hora de buscar una mejor respuesta. La evaluación de cadenas es peligrosa y frágil, a veces es lo que necesita, pero estimo que más del 95% del tiempo lo veo utilizado. Hay una forma menos peligrosa disponible. – dbenhur