Ruby 1.9 const_defined? ("Timeout") возвращает true, если Timeout отсутствует в списке констант - PullRequest
1 голос
/ 22 марта 2011

Я пытаюсь обновить Puppet для использования Ruby 1.9 и сталкиваюсь с проблемами с константами. const_defined? ("Timeout") возвращает true, даже если: Timeout отсутствует в списке констант. Этого не происходит на Ruby 1.8.7. Есть идеи почему?

[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

Ответы [ 2 ]

2 голосов
/ 25 марта 2011

Поведение const_defined? в Ruby 1.9 можно сделать так же, как в Ruby 1.8, установив для нового параметра наследования значение false.

mod.const_defined?(sym, inherit=true)

Вот пример, иллюстрирующий другое поведение.

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

В Ruby 1.9.2 вывод из работы это:

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

Так, хотя const_defined? признает, что Timeout определен в верхней области видимости как класс, remove_const разрешает удалять только константы в области видимости Foo.

В Ruby 1.8.7 вывод:

The constant I got was Timeout
nil

Итак, const_get смотрит на области предков так же, как в Ruby 1.9.2, но const_defined? нет, что препятствует вызову remove_const.

Ruby 1.9.2 можно заставить вести себя как 1.8.7, вот так:

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

Однако теперь это не обратно совместимо с Ruby 1.8, так как const_defined? не имеет второго параметра в 1.8. Чтобы обойти это, я сделал следующий метод, который можно вызывать вместо const_defined? и используется в любой версии Ruby.

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

Это решило проблему обновления Ruby 1.9. Возможно, это не лучшее долгосрочное решение, и реальная проблема заключается в том, что в topscope есть класс с именем Timeout И иногда константа с именем Timeout в других классах, которую необходимо проверить, но это изменение делает код намного ближе к выполнению на Ruby 1.9.

1 голос
/ 23 марта 2011

Не могу точно сказать, что происходит.

Однако RDoc для const_defined? и constants отличается в 1.8.7, тогда как в 1.9 он довольно похож.

В 1.8.7 , const_defined? говорит:

Возвращает true, если константа с данным именем определена модом.

и constants говорит

Возвращает массив имен констант, доступных в моде. Сюда входят имена констант в любых включенных модулях (пример в начале раздела).

Однако в 1,9 , const_defined? говорит

Возвращает true, если константа с заданным именем определена модом, или его предки, если наследование не ложно.[по умолчанию inherit равно true]

и constants говорит

Возвращает массив имен констант, доступных в моде.Это включает в себя имена констант во всех включенных модулях (например, в начале раздела), если только для параметра all не установлено значение false.[по умолчанию all имеет значение true]

Таким образом, похоже, что поведение двух методов согласовано в 1.9, но не согласовано в 1.8.7.Но я могу ошибаться.

При этом я бы предложил следующее:

  • Создайте игрушечный пример использования const_defined? и constants, желательно без участия Timeout, и поэкспериментируйте с этим, пока не убедитесь, что вы понимаете, что делают оба метода, как при 1,8, так и при 1,9.
  • Определите, где принадлежит константа Timeout.Также проверьте, может ли IRB или отладчик вызывать определение Timeout, если он ранее был неопределенным, и загружается ли он по умолчанию одной версией Ruby, но не другой.

Я также сталкивался http://redmine.ruby -lang.org / Issues / 1915 при поиске в Google для const_defined? 1.8 1.9.Я не уверен, актуально это или нет.

Надеюсь, это поможет - хотя я не уверен!

...