Ruby 1.9 const_defined? ("Timeout") restituisce vero quando timeout non nell'elenco delle costanti
Domanda
Sto cercando di aggiornare il burattino per usare Ruby 1.9 e correre nei guai con le costanti. const_defined? ("timeout") sta tornando vero anche se: il timeout non è nell'elenco delle costanti. Questo non accade su Ruby 1.8.7. Qualche idea perché?
[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
Soluzione
Il comportamento di const_defined? In Ruby 1.9 può essere realizzato per essere lo stesso di Ruby 1.8 impostando il nuovo parametro ereditario su False.
mod.const_defined?(sym, inherit=true)
Ecco un esempio per illustrare il comportamento diverso.
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
Sotto Ruby 1.9.2 L'output dall'esecuzione di questo è:
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>'
Quindi anche se const_defined? Riconosce che il timeout è definito al primo posto come classe, Rimod_Const è consentito rimuovere le costanti nell'ambito di FOO.
In Ruby 1.8.7 l'uscita è:
The constant I got was Timeout
nil
Quindi const_get guarda gli ambiti dell'antenato proprio come in Ruby 1.9.2, ma const_defined? Non lo fa, che impedisce di essere chiamato Rimoy_Const.
Ruby 1.9.2 può essere fatto per comportarsi come 1.8.7 come così:
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
Tuttavia, questo non è ora compatibile con Ruby 1.8 da Const_Defined? non ha un secondo parametro in 1.8. Per aggirare questo ho realizzato il seguente metodo che può essere chiamato al posto di const_defined? e utilizzata in entrambe le versione di Ruby.
def is_constant_defined?(const)
if ::RUBY_VERSION =~ /1.9/
const_defined?(const, false)
else
const_defined?(const)
end
end
Ciò ha risolto questo particolare problema di aggiornamento di Ruby 1.9. Potrebbe non essere la migliore soluzione a lungo termine, e il vero problema è che esiste una classe chiamata timeout a topscope e talvolta una costante chiamata timeout in altre classi che devono essere controllate, ma questa modifica avvicina il codice a correre Ruby 1.9.
Altri suggerimenti
Non posso dire con certezza cosa stia succedendo.
Tuttavia, il RDOC per const_defined?
e constants
è diverso in 1.8.7, mentre è abbastanza simile in 1.9.
In 1.8.7, const_defined?
dice:
Restituisce vero se una costante con il nome dato è definita da mod.
e constants
dice
Restituisce un array dei nomi delle costanti accessibili in mod. Ciò include i nomi delle costanti in tutti i moduli inclusi (esempio all'inizio della sezione).
Tuttavia, in 1.9, const_defined?
dice
Restituisce vero se una costante con il nome dato è definita da mod o i suoi antenati se eredità non è falso. [Per impostazione predefinita,
inherit
è vero
e constants
dice
Restituisce un array dei nomi delle costanti accessibili in mod. Ciò include i nomi delle costanti in qualsiasi moduli inclusi (esempio all'inizio della sezione), a meno che tutto il parametro non sia impostato su False. [Per impostazione predefinita,
all
è vero
Quindi sembra che il comportamento dei due metodi sia coerente in 1.9, ma non coerente in 1.8.7. Ma potrei sbagliarmi.
Detto questo, suggerirei quanto segue:
- Crea un esempio giocattolo di utilizzo
const_defined?
econstants
, preferibilmente non coinvolgereTimeout
, e gioca con esso finché non sei sicuro di capire cosa fanno i due metodi, sia sotto 1,8 che 1.9. - Affronta dove il
Timeout
costante appartiene a. Controlla anche se IRB o il debugger possono far definire il timeout quando in precedenza non era definito e se viene caricato per impostazione predefinita da una versione di Ruby ma non dall'altra.
Mi sono anche imbattuto in http://redmine.ruby-lang.org/issues/1915 quando si googla per const_defined? 1.8 1.9
. Non sono sicuro che sia rilevante o no.
Spero che questo aiuti - non ne sono sicuro però!