2011-03-22 23 views
1

我試圖升級Puppet以使用Ruby 1.9並遇到常量出現問題。 const_defined?(「Timeout」)返回true,即使:Timeout不在常量列表中。這在Ruby 1.8.7上不會發生。任何想法爲什麼?Ruby 1.9 const_defined?(「Timeout」)當超時不在常量列表中時返回true

[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 
+0

如果你想讓人們閱讀代碼示例,你可能希望在第128行的單獨行中有第129行。 – 2011-03-22 22:14:57

+1

是的,我沒有注意到格式化有多糟糕。感謝您告訴我,我修復了它。 – mmrobins 2011-03-22 22:55:17

回答

2

const_defined的行爲?通過將新的繼承參數設置爲false,可以使Ruby 1.9與Ruby 1.8中的相同。

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 

下紅寶石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

我無法確定發生了什麼事。

但是,const_defined?constants的RDoc在1.8.7中有所不同,而在1.9中則相當相似。

1.8.7const_defined?說:

返回true如果給定名稱的常數由國防部定義。

constants

返回國防部訪問的常數的名稱的數組。 這包括任何包含模塊中常量的名稱(例如開始部分)。

然而,在1.9const_defined?如果具有給定名稱的常數由國防部定義,或者它的祖先如果繼承是不假說

返回true。 [默認inherit爲真]

constants

返回國防部訪問的常數的名稱的數組。這包括任何包含的模塊中的常量名稱(例如開始部分),除非all參數設置爲false。 [默認情況下,all爲真]

所以看起來這兩種方法的行爲在1.9中一致,但在1.8.7中不一致。但我可能是錯的。

話雖這麼說,我建議如下:

  • 創建使用const_defined?constants,最好不涉及Timeout的玩具例子,玩它,直到你確信你明白這兩個方法在1.8和1.9下都有效。
  • 計算出常數所屬的Timeout。同時檢查IRB或調試器是否可能導致Timeout在之前未定義時被定義,以及它是否由一個Ruby版本默認加載,而不是另一個版本。

我也遇到了http://redmine.ruby-lang.org/issues/1915當谷歌搜索const_defined? 1.8 1.9。我不確定它是否相關。

我希望這可以幫助 - 雖然我不確定!

相關問題