Ruby 1.9 const_defined? («Timeout») renvoie true lorsque Timeout n'est pas dans la liste des constantes

StackOverflow https://stackoverflow.com/questions/5395587

  •  28-10-2019
  •  | 
  •  

Question

J'essaye de mettre à jour Puppet pour utiliser Ruby 1.9 et j'ai des problèmes avec les constantes.const_defined? ("Timeout") renvoie true même si: Timeout n'est pas dans la liste des constantes.Cela ne se produit pas sur Ruby 1.8.7.Des idées pourquoi?

[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
Était-ce utile?

La solution

Le comportement de const_defined? dans Ruby 1.9 peut être rendu identique à Ruby 1.8 en définissant le nouveau paramètre inherit sur false.

mod.const_defined?(sym, inherit=true)

Voici un exemple pour illustrer les différents comportements.

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

Sous Ruby 1.9.2, le résultat de l'exécution de ceci est:

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>'

Donc, même si const_defined? reconnaît que Timeout est défini dans la portée supérieure en tant que classe, remove_const est uniquement autorisé à supprimer les constantes dans la portée de Foo.

Dans Ruby 1.8.7, le résultat est:

The constant I got was Timeout
nil

Donc, const_get regarde les portées des ancêtres comme dans Ruby 1.9.2, mais const_defined? pas, ce qui empêche remove_const d'être appelé.

Ruby 1.9.2 peut être fait pour se comporter comme 1.8.7 comme ceci:

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

Cependant, ce n'est plus rétrocompatible avec Ruby 1.8 depuis const_defined? n'a pas de deuxième paramètre en 1.8. Pour contourner cela, j'ai créé la méthode suivante qui peut être appelée au lieu de const_defined? et utilisé dans les deux versions de Ruby.

def is_constant_defined?(const)
  if ::RUBY_VERSION =~ /1.9/
    const_defined?(const, false)
  else
    const_defined?(const)
  end
end

Cela a résolu ce problème de mise à niveau de Ruby 1.9. Ce n'est peut-être pas la meilleure solution à long terme, et le vrai problème est qu'il existe une classe appelée Timeout chez topscope ET parfois une constante appelée Timeout dans d'autres classes qui doit être vérifiée, mais ce changement rapproche le code de son exécution. Ruby 1.9.

Autres conseils

Je ne peux pas dire avec certitude ce qui se passe.

Cependant, le RDoc pour const_defined? et constants est différent dans 1.8.7, alors qu'il est assez similaire dans 1.9.

Dans 1.8.7 , const_defined? dit:

Renvoie true si une constante avec le nom donné est définie par mod.

et constants dit

Renvoie un tableau des noms des constantes accessibles dans mod. Cela inclut les noms des constantes dans tous les modules inclus (exemple au début de la section).

Cependant, dans 1.9 , const_defined? dit

Renvoie true si une constante avec le nom donné est définie par mod, ou ses ancêtres si inherit n'est pas false. [par défaut, inherit est vrai]

et constants dit

Renvoie un tableau des noms des constantes accessibles dans mod. Cela inclut les noms des constantes dans tous les modules inclus (exemple au début de la section), sauf si le paramètre all est défini sur false. [par défaut, all est vrai]

Il semble donc que le comportement des deux méthodes soit cohérent dans 1.9, mais pas cohérent dans 1.8.7. Mais je peux me tromper.

Cela étant dit, je suggère ce qui suit:

  • Créez un exemple d'utilisation de const_defined? et constants, de préférence n'impliquant pas Timeout, et jouez avec jusqu'à ce que vous soyez sûr de comprendre ce que font les deux méthodes, sous 1.8 et 1.9.
  • Déterminez où appartient la constante Timeout. Vérifiez également si IRB ou le débogueur peut entraîner la définition de Timeout alors qu'il était précédemment indéfini, et s'il est chargé par défaut par une version de Ruby mais pas par l'autre.

Je suis également tombé sur http://redmine.ruby-lang.org/issues/1915 lors de la recherche sur google pour const_defined? 1.8 1.9. Je ne sais pas si c'est pertinent ou non.

J'espère que cela aide - je ne suis pas sûr cependant!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top