2008-09-16 38 views
3

我是新來的Ruby,所以我有一些無法理解我在這個奇怪的異常問題。我正在使用ruby-aaws gem訪問Amazon ECS:http://www.caliban.org/ruby/ruby-aws/。這定義一個類亞馬遜的AWS :::錯誤:紅寶石例外的繼承與動態生成的類

module Amazon 
    module AWS 
    # All dynamically generated exceptions occur within this namespace. 
    # 
    module Error 
     # An exception generator class. 
     # 
     class AWSError 
     attr_reader :exception 

     def initialize(xml) 
      err_class = xml.elements['Code'].text.sub(/^AWS.*\./, '') 
      err_msg = xml.elements['Message'].text 

      unless Amazon::AWS::Error.const_defined?(err_class) 
      Amazon::AWS::Error.const_set(err_class, 
        Class.new(StandardError)) 
      end 

      ex_class = Amazon::AWS::Error.const_get(err_class) 
      @exception = ex_class.new(err_msg) 
     end 
     end 
    end 
    end 
end 

這意味着,如果你得到一個錯誤代碼像AWS.InvalidParameterValue,這將產生(在它的異常變量)一類新的Amazon::AWS::Error::InvalidParameterValue這是StandardError一個子類。

現在這裏的地方會很奇怪。我有一些代碼,看起來像這樣:

begin 
    do_aws_stuff 
rescue Amazon::AWS::Error => error 
    puts "Got an AWS error" 
end 

現在,如果do_aws_stuff拋出一個NameError,我的救援塊被觸發。看來,亞馬遜:: AWS ::錯誤不是生成的錯誤的超類 - 我想因爲它是一個模塊,一切都是它的一個子類?當然,如果我做的:

irb(main):007:0> NameError.new.kind_of?(Amazon::AWS::Error) 
=> true 

它說true,我覺得這混亂的,特別是考慮到這一點:

irb(main):009:0> NameError.new.kind_of?(Amazon::AWS) 
=> false 

這是怎麼回事,怎麼我應該從其他類型的分離出來AWS的錯誤錯誤?我應該這樣做:

begin 
    do_aws_stuff 
rescue => error 
    if error.class.to_s =~ /^Amazon::AWS::Error/ 
    puts "Got an AWS error" 
    else 
    raise error 
    end 
end 

這似乎格外junky。拋出的錯誤是不是類AWSError要麼 - 他們提出這樣的:

error = Amazon::AWS::Error::AWSError.new(xml) 
raise error.exception 

所以我期待rescue例外是從生成的異常類型,只有從StandardError的繼承。

爲了澄清,我有兩個問題:

  1. 爲什麼NameError,一個Ruby內置的例外,一個kind_of?(Amazon::AWS::Error),這是一個模塊?
    答:我曾在我的文件的開頭說:include Amazon::AWS::Error,認爲它是一種類似於Java進口或C++包括。實際上做的是將Amazon::AWS::Error(現在和將來)中定義的所有內容添加到隱式Kernel類,這是每個類的祖先。這意味着什麼將通過kind_of?(Amazon::AWS::Error)

  2. 我怎樣才能最好的從隨機其他異常從別處區分Amazon::AWS::Error動態創建的異常?

+0

由於Amazon :: AWS :: Error類型似乎與您在問題頂部提供的源代碼無關,因此很難理解您的問題。粘貼錯誤,也許? – 2008-09-16 07:32:57

+0

糟糕,我忘了「AWS」模塊。我剪掉了文件中很多不相關的部分,並且必須忽略它。所以我們有一個亞馬遜模塊,一個AWS模塊,一個錯誤模塊,然後是一個AWSError類,它在Amazon :: AWS :: Error模塊中設置常量。 – bhollis 2008-09-16 07:48:02

回答

5

好吧,我會盡力幫助這裏:

第一模塊是不是一個類,它可以讓你在混合行爲一類。第二看下面的例子:

module A 
    module B 
    module Error 
     def foobar 
     puts "foo" 
     end 
    end 
    end 
end 

class StandardError 
    include A::B::Error 
end 

StandardError.new.kind_of?(A::B::Error) 
StandardError.new.kind_of?(A::B) 
StandardError.included_modules #=> [A::B::Error,Kernel] 

kind_of?告訴你,是的,錯誤確實擁有所有A :: B ::錯誤行爲(這是正常的,因爲它包括A :: B ::錯誤),但它不包括來自A :: B的所有行爲,因此不是A :: B類。 (duck typing)

現在ruby-aws很有可能重新打開NameError的超類之一,並在其中包含Amazon :: AWS:Error。 (猴修補)

你可以找到編程其中模塊包括在具有以下層次:

class Class 
    def has_module?(module_ref) 
    if self.included_modules.include?(module_ref) and not self.superclass.included_modules.include?(module_ref)      
     puts self.name+" has module "+ module_ref.name   
    else 
     self.superclass.nil? ? false : self.superclass.has_module?(module_ref) 
    end   
    end 
end 
StandardError.has_module?(A::B::Error) 
NameError.has_module?(A::B::Error) 

關於你提到的第二個問題,我看不到任何東西比

begin 
#do AWS error prone stuff 
rescue Exception => e 
    if Amazon::AWS::Error.constants.include?(e.class.name) 
    #awsError 
    else 
    whatever 
    end 
end 

(編輯 - 上面的代碼不起作用:名稱包含模塊前綴,而不是常量數組的情況。您應該聯繫lib維護者,AWSError類看起來更像工廠類對我來說:/)

我在這裏沒有ruby-aws,並且caliban站點被公司的防火牆阻止,所以我無法進一步測試。

關於包括:這可能是在StandardError層次結構上進行猴子修補的事情。我不再確定,但最有可能在每個上下文之外的文件根目錄下包含Object或Object元類上的模塊。 (這是IRB,在默認情況下爲對象,不知道在一個文件中會發生什麼)

pickaxe on modules

A couple of points about the include statement before we go on. First, it has nothing to do with files. C programmers use a preprocessor directive called #include to insert the contents of one file into another during compilation. The Ruby include statement simply makes a reference to a named module. If that module is in a separate file, you must use require to drag that file in before using include.

(編輯 - 我似乎無法到能夠評論使用這個瀏覽器:/ yay鎖定平臺)

1

好,從我可以告訴:

Class.new(StandardError) 

是創建具有StandardError的一個新類的基類,所以它不打算成爲一個亞馬遜AWS :: ::錯誤所有。它只是在該模塊中定義的,這可能是爲什麼它是kind_of?亞馬遜AWS :: ::錯誤。這可能不是一種善意?亞馬遜:: AWS,因爲可能模塊不會爲了kind_of而嵌套? ?

對不起,我不太瞭解Ruby中的模塊,但絕大多數基類都將是StandardError。

UPDATE:順便說一下,from the ruby docs

obj.kind_of?(class) => true or false

Returns true if class is the class of obj, or if class is one of the superclasses of obj or modules included in obj.

+0

是的,我知道基類是`StandardError`。是什麼驅使我堅持是`NameError.new.kind_of?(Amazon :: AWS :: Error)`是真的。爲什麼會這樣? – bhollis 2008-09-16 07:45:01

+0

看看我的更新...可能解釋它;-) – 2008-09-16 07:46:14

1

只是想編鐘:我會同意這是一個在lib代碼中的錯誤。它可能應該閱讀:

你正在運行到
 unless Amazon::AWS::Error.const_defined?(err_class) 
     kls = Class.new(StandardError) 
     Amazon::AWS::Error.const_set(err_class, kls) 
     kls.include Amazon::AWS::Error 
     end 
0

一個問題是,Amazon::AWS::Error::AWSError實際上不是一個例外。調用raise時,它會查看第一個參數是否響應exception方法,並將使用該方法的結果。當調用exception時,任何屬於Exception的子類的東西都會自行返回,因此您可以執行諸如raise Exception.new("Something is wrong")之類的操作。

在這種情況下,AWSError已將exception設置爲屬性讀取器,它將初始化時的值定義爲Amazon::AWS::Error::SOME_ERROR。這意味着當您撥打raise Amazon::AWS::Error::AWSError.new(SOME_XML)時,Ruby最終會調用Amazon::AWS::Error::AWSError.new(SOME_XML).exception,這將返回Amazon::AWS::Error::SOME_ERROR的實例。正如其他響應者之一所指出的,該類是StandardError的直接子類,而不是常見的Amazon錯誤的子類。在糾正這個問題之前,Jean的解決方案可能是你最好的選擇。

我希望能幫助解釋更多幕後實際發生的事情。