¿Cómo redefinir una constante de Ruby sin previo aviso?
constants redefine (4)
A menos que los valores de las constantes sean bastante extraños (es decir, si tiene constantes configuradas en nil
o false
), la mejor opción sería usar el operador de asignación condicional: Tau ||= 2*Pi
Esto establecerá Tau en 2π si es nil
, false
o indefinido, y de lo contrario lo dejará solo.
Estoy ejecutando un código de Ruby que detecta un archivo de Ruby cada vez que cambia su fecha. En el archivo, tengo definiciones constantes, como
Tau = 2 * Pi
y, por supuesto, hacen que el intérprete muestre la advertencia de "constante ya inicializada" no deseada cada vez, así que me gustaría tener las siguientes funciones:
def_if_not_defined(:Tau, 2 * Pi)
redef_without_warning(:Tau, 2 * Pi)
Podría evitar la advertencia al escribir todas mis definiciones constantes como esta:
Tau = 2 * Pi unless defined?(Tau)
pero es poco elegante y un poco húmedo (no DRY ).
¿Hay una mejor manera de def_if_not_defined
? ¿Y cómo redef_without_warning
?
-
Solución gracias a Steve:
class Object
def def_if_not_defined(const, value)
mod = self.is_a?(Module) ? self : self.class
mod.const_set(const, value) unless mod.const_defined?(const)
end
def redef_without_warning(const, value)
mod = self.is_a?(Module) ? self : self.class
mod.send(:remove_const, const) if mod.const_defined?(const)
mod.const_set(const, value)
end
end
A = 1
redef_without_warning :A, 2
fail ''unit test'' unless A == 2
module M
B = 10
redef_without_warning :B, 20
end
fail ''unit test'' unless M::B == 20
-
Esta pregunta es vieja. El código anterior solo es necesario para Ruby 1.8. En Ruby 1.9, la respuesta de P3t3rU5 no produce ninguna advertencia y simplemente es mejor.
El siguiente módulo puede hacer lo que quieras. Si no puede proporcionar algunos consejos a su solución
module RemovableConstants
def def_if_not_defined(const, value)
self.class.const_set(const, value) unless self.class.const_defined?(const)
end
def redef_without_warning(const, value)
self.class.send(:remove_const, const) if self.class.const_defined?(const)
self.class.const_set(const, value)
end
end
Y como ejemplo de usarlo.
class A
include RemovableConstants
def initialize
def_if_not_defined("Foo", "ABC")
def_if_not_defined("Bar", "DEF")
end
def show_constants
puts "Foo is #{Foo}"
puts "Bar is #{Bar}"
end
def reload
redef_without_warning("Foo", "GHI")
redef_without_warning("Bar", "JKL")
end
end
a = A.new
a.show_constants
a.reload
a.show_constants
Da la siguiente salida
Foo is ABC
Bar is DEF
Foo is GHI
Bar is JKL
Perdóname si he roto algún tabú de rubí aquí, ya que todavía me estoy preguntando algo sobre la estructura del Módulo: Clase: Eigenclass dentro de Ruby
Otro enfoque, usando $ VERBOSE, para suprimir las advertencias, se discute aquí: http://mentalized.net/journal/2010/04/02/suppress_warnings_from_ruby/
Si desea redefinir un valor, entonces no use constantes, use una variable global en su lugar ($ tau = 2 * Pi), pero eso tampoco es una buena práctica. Debería convertirla en una variable de instancia de una clase adecuada.
Para el otro caso, Tau = 2 * Pi unless defined?(Tau)
es perfectamente correcto y la más legible, por lo tanto, la solución más elegante.