Ruby 1.9 const_definido?(“Timeout”) devuelve verdadero cuando el tiempo de espera no está en la lista de constantes
Pregunta
Estoy intentando actualizar Puppet para usar Ruby 1.9 y tengo problemas con las constantes.const_definido?("Timeout") devuelve verdadero aunque :Timeout no esté en la lista de constantes.Esto no sucede en Ruby 1.8.7.¿Alguna idea de por qué?
[128, 137] in /Users/matthewrobinson/work/puppet/lib/puppet/util/classgen.rb
128 def handleclassconst(klass, name, options)
129 const = genconst_string(name, options)
130
131 require 'ruby-debug';
132 debugger if const == "Timeout"=>
133 if const_defined?(const)
134 if options[:overwrite]
135 Puppet.info "Redefining #{name} in #{self}"
136 remove_const(const)
137 else
(rdb:1) const
=> "Timeout"
(rdb:1) const_defined?(const)
=> true
(rdb:1) constants.grep /Timeout/
=> []
(rdb:1) constants
=> [:Ensure, :ParameterName, :Auth_type, :Allow_root, :Authenticate_user, :Auth_class, :Comment, :Group, :K_of_n, :Mechanisms, :Rule, :Session_owner, :Shared, :MetaParamNoop, :MetaParamSchedule, :MetaParamAudit, :MetaParamCheck, :MetaParamLoglevel, :MetaParamAlias, :MetaParamTag, :RelationshipMetaparam, :MetaParamRequire, :MetaParamSubscribe, :MetaParamBefore, :MetaParamNotify, :MetaParamStage, :Component, :Macauthorization, :Expirer, :ClassMethods, :InstanceMethods, :ExecutionStub, :POSIX, :Errors, :MethodHelper, :ClassGen, :Docs, :Execution, :Tagging, :Log, :Logging, :Package, :Warnings, :Cacher, :Autoload, :LoadedFile, :Settings, :Feature, :SUIDManager, :RunMode, :CommandLine, :InstanceLoader, :Pson, :Metric, :LogPaths, :ProviderFeatures, :InlineDocs, :FileLocking, :Storage, :Checksums]
(rdb:1) constants.grep /Path/
=> [:LogPaths]
(rdb:1) self
=> Puppet::Type::Macauthorization
Solución
El comportamiento de const_defined? En Ruby 1.9 se puede hacer que sea lo mismo que en Ruby 1.8 estableciendo el nuevo parámetro de herencia en falso.
mod.const_defined?(sym, inherit=true)
Aquí hay un ejemplo para ilustrar el comportamiento diferente.
module Foo
def self.bar
puts "The constant I got was #{const_get("Timeout")}"
if const_defined?("Timeout")
puts "I found #{Timeout}!"
remove_const("Timeout")
puts "Timeout is now #{Timeout}"
end
end
end
class Timeout
end
puts Foo.bar
Bajo Ruby 1.9.2 La salida de la ejecución es:
The constant I got was Timeout
I found Timeout!
19_test.rb:6:in `remove_const': constant Foo::Timeout not defined (NameError)
from 19_test.rb:6:in `bar'
from 19_test.rb:13:in `<main>'
Entonces, aunque const_defined? Reconoce que el tiempo de espera se define en el alcance superior como clase, Remove_Const solo se permite eliminar las constantes en el alcance de Foo.
En Ruby 1.8.7 la salida es:
The constant I got was Timeout
nil
Entonces, const_get mira los alcances del antepasado como en Ruby 1.9.2, pero const_defined? no lo hace, lo que evita que se llame remove_const.
Se puede hacer que Ruby 1.9.2 se comporte como 1.8.7 como así:
module Foo
def self.bar
puts "The constant I got was #{const_get("Timeout")}"
if const_defined?("Timeout", false)
puts "I found #{Timeout}!"
remove_const("Timeout")
puts "Timeout is now #{Timeout}"
end
end
end
class Timeout
end
puts Foo.bar
Sin embargo, esto ahora no es compatible con el retroceso con Ruby 1.8 desde const_defined? No tiene un segundo parámetro en 1.8. Para evitar esto, hice el siguiente método que se puede llamar en lugar de const_defined? y usado en cualquier versión de Ruby.
def is_constant_defined?(const)
if ::RUBY_VERSION =~ /1.9/
const_defined?(const, false)
else
const_defined?(const)
end
end
Esto resolvió este problema particular de actualización de Ruby 1.9. Puede que no sea la mejor solución a largo plazo, y el verdadero problema es que hay una clase llamada Tiempo de espera en TopScope y, a veces, una constante llamada Tiempo de espera en otras clases que debe verificarse, pero este cambio se acerca mucho más a Ruby 1.9.
Otros consejos
No puedo decir con seguridad qué está pasando.
Sin embargo, el RDoc para const_defined?
y constants
es diferente en 1.8.7, mientras que es bastante similar en 1.9.
En 1.8.7, const_defined?
dice:
Devuelve verdadero si mod define una constante con el nombre de pila.
y constants
dice
Devuelve una matriz de los nombres de las constantes accesibles en mod. Esto incluye los nombres de las constantes en cualquier módulo incluido (ejemplo al inicio de la sección).
Sin embargo, en 1.9, const_defined?
dice
Devuelve verdadero si mod define una constante con el nombre de pila, o sus ancestros si heredar no es falso.[por defecto,
inherit
es verdad]
y constants
dice
Devuelve una matriz de los nombres de las constantes accesibles en mod.Esto incluye los nombres de las constantes en cualquier módulo incluido (ejemplo al inicio de la sección), a menos que el parámetro all esté establecido en falso.[por defecto,
all
es verdad]
Entonces parece que el comportamiento de los dos métodos es consistente en 1.9, pero no consistente en 1.8.7.Pero podría estar equivocado.
Dicho esto, sugeriría lo siguiente:
- Crea un ejemplo de uso de un juguete
const_defined?
yconstants
, preferiblemente sin involucrarTimeout
, y juegue con él hasta que esté seguro de que comprende lo que hacen los dos métodos, tanto en 1.8 como en 1.9. - Calcula dónde está
Timeout
pertenece a la constante.También verifique si IRB o el depurador pueden hacer que el tiempo de espera se defina cuando anteriormente no estaba definido, y si una versión de Ruby lo carga de forma predeterminada pero no la otra.
yo también me encontré http://redmine.ruby-lang.org/issues/1915 al buscar en Google const_defined? 1.8 1.9
.No estoy seguro si es relevante o no.
Espero que esto ayude, ¡aunque no estoy seguro!