2010-06-11 11 views
5

Hace mucho tiempo que sabía que las "constantes" en Ruby (es decir, los nombres de las variables que están en mayúscula) no son realmente constante. Al igual que otros lenguajes de programación, una referencia a un objeto es lo único almacenado en la variable/constante. (Barra lateral: Ruby tiene la posibilidad de "congelar" los objetos referenciados para que no se modifiquen, que hasta donde yo sé, no es una capacidad ofrecida en muchos otros idiomas.)¿Lanzar excepción al volver a asignar una constante en Ruby?

Así que esta es mi pregunta: cuando vuelvas asignar un valor a una constante, se obtiene una advertencia de este modo:

>> FOO = 'bar' 
=> "bar" 
>> FOO = 'baz' 
(irb):2: warning: already initialized constant FOO 
=> "baz" 

¿hay una manera de forzar Ruby a lanzar una excepción en lugar de imprimir una advertencia? Es difícil descubrir por qué las reasignaciones ocurren a veces.

Respuesta

5

Mire this question para ver cómo es posible en algunos casos tratar las advertencias como errores.

De lo contrario, supongo que tendría que escribir un método personalizado para asignar constantes y elevar la excepción si ya está asignada.

Si sabe que una reasignación pasa a una constante específica, también puede agregar una verificación de cordura justo antes de la asignación.

+0

Gracias por señalar la otra pregunta: no hubiera pensado en usar 'Kernel.warn' para eso. Sin embargo, no parece que la reasignación constante lo use. –

+0

Realmente no lo intenté; pero puedo imaginar que las asignaciones constantes podrían ser parte del lenguaje en sí y así manejarlas en el código C. En ese caso, sería aún más difícil conectar con eso, y mucho menos plantear una excepción de Ruby. – averell

3

No se puede interceptar directamente, no.

Si realmente necesito hacer esto, puedo pensar en un truco muy sucio, sin embargo. Podría redirigir el error estándar IO a un objeto IO personalizado. El método write podría verificar lo que se está escribiendo; si contiene "warning: already initialized constant", entonces levanta, de lo contrario reenvía la llamada al error estándar write.

+0

Esto realmente funcionaría. * Muy * enfoque creativo, sin embargo;) – averell

+0

En realidad, eso es básicamente lo que dice la gran respuesta que señala ... Debimos haber publicado casi al mismo tiempo, porque no lo había leído cuando publiqué. –

0

Si la constante es dentro de una clase o de un módulo, entonces se podría freeze la clase o módulo:

# Normal scenario 
$VERBOSE = true 
class Foo 
    BAR = 1 
end 

Foo::BAR = 2 # warning: already initialized constant BAR 
# Using freeze 
Foo.freeze 
Foo::BAR = 3 
RuntimeError: can't modify frozen Class 
    from (irb):8 
    from /Users/agrimm/.rbenv/versions/1.9.3-p194/bin/irb:12:in `<main>' 

para su escenario, se puede congelar Object, pero que suena un poco de miedo.

Cuestiones relacionadas