3

私はRubyを初めて使用するため、この奇妙な例外の問題を理解するのに苦労しています。私はruby-aawsgemを使用してAmazonECSにアクセスしています:http://www.caliban.org/ruby/ruby-aws/。これにより、クラスAmazon :: AWS:Error:が定義されます。

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と、レスキューブロックがトリガーされます。Amazon :: AWS :: Errorは、生成されたエラーのスーパークラスではないようです-モジュールなので、すべてがそのサブクラスだと思いますか?確かに私がそうするなら:

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

それは非常にぎこちないようです。スローされるエラーもクラスAWSErrorではありません-次のように発生します:

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

したがって、私が探している例外rescueは、StandardErrorからのみ継承する生成された例外タイプです。

明確にするために、2つの質問があります。

  1. Rubyに組み込まれている例外であるNameErrorがkind_of?(Amazon::AWS::Error)モジュールであるのはなぜですか?
    回答:include Amazon::AWS::Errorファイルの先頭で、JavaインポートやC++インクルードのようなものだと思っていました。これが実際に行ったことは、Amazon::AWS::Error(現在および将来)で定義されたすべてのものを、すべてのクラスの祖先である暗黙のKernelクラスに追加することでした。これは、何でも合格することを意味しkind_of?(Amazon::AWS::Error)ます。

  2. Amazon::AWS::Error動的に作成された例外を他の場所からのランダムな他の例外と最もよく区別するにはどうすればよいですか?

4

4 に答える 4

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]

すこし?はい、エラーはすべてのA :: B :: Error動作(A :: B :: Errorが含まれているため正常です)を持っていますが、A :: Bからのすべての動作が含まれていないため、そうではありません。 A::Bの種類の。(ダックタイピング)

これで、ruby-awsがNameErrorのスーパークラスの1つを再開し、そこに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)

あなたの2番目の質問に関して、私はこれ以上何も見えません

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

(編集-上記のコードはそのままでは機能しません:名前には定数配列の場合ではないモジュールプレフィックスが含まれています。AWSErrorクラスは私にはファクトリクラスのように見えます:/)

私はここにルビーを持っていません、そしてキャリバンサイトは会社のファイアウォールによってブロックされているので、私はそれ以上テストすることができません。

インクルードに関して:それはStandardError階層でモンキーパッチを実行することかもしれません。もうわかりませんが、すべてのコンテキストの外部でファイルのルートでそれを行うことは、ObjectまたはObjectメタクラスにモジュールを含めることである可能性があります。(これは、デフォルトのコンテキストがオブジェクトであるIRBで発生することであり、ファイル内では不明です)

モジュールのつるはしから:

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.

(編集-このブラウザを使用してコメントすることはできないようです:/プラットフォームにロックされている場合はイェーイ)

于 2008-09-16T08:00:17.450 に答える
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
于 2008-09-16T11:54:52.517 に答える
1

さて、私が言えることから:

Class.new( StandardError )

StandardErrorを基本クラスとして新しいクラスを作成しているため、Amazon :: AWS::Errorにはなりません。それはそのモジュールで定義されているだけです、それはおそらくそれがkind_ofである理由ですか?Amazon ::AWS::エラー。それはおそらくkind_ofではありませんか?Amazon :: AWSは、おそらくモジュールがkind_ofの目的でネストしないためですか??

申し訳ありませんが、Rubyのモジュールについてはよくわかりませんが、基本クラスは間違いなくStandardErrorになります。

更新:ちなみに、ruby docsから

obj.kind_of?(class)=>trueまたはfalse

classがobjのクラスである場合、またはclassがobjまたはobjに含まれるモジュールのスーパークラスの1つである場合、trueを返します。

于 2008-09-16T07:40:51.817 に答える
0

あなたが直面している問題の 1 つAmazon::AWS::Error::AWSErrorは、実際には例外ではないということです。が呼び出されると、最初のパラメーターがメソッドraiseに応答するかどうかを確認し、代わりにその結果を使用します。exceptionのサブクラスであるものは、が呼び出されるとExceptionそれ自体を返すexceptionので、 のようなことができますraise Exception.new("Something is wrong")

この場合、AWSErrorexception初期化時に のような値に定義する属性リーダーとして設定されています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。他のレスポンダーの 1 人が指摘したように、このクラスはStandardError一般的な Amazon エラーのサブクラスではなく、直接のサブクラスです。これが修正されるまでは、Jean のソリューションがおそらく最善の策です。

舞台裏で実際に何が起こっているかを説明するのに役立つことを願っています.

于 2009-10-05T00:39:53.927 に答える