我是Ruby的新手,所以我在理解我遇到的这个奇怪的异常问题时遇到了一些麻烦.我正在使用ruby-aaws gem访问Amazon ECS:http://www.caliban.org/ruby/ruby-aws/.这定义了一个类Amazon :: 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
,我的救援区块就会被触发.似乎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.
澄清一下,我有两个问题:
为什么NameError是一个内置异常的Ruby kind_of?(Amazon::AWS::Error)
,它是一个模块?
答:我曾include Amazon::AWS::Error
在文件的顶部说过,认为它有点像Java导入或C++包含.这实际上做的是将Amazon::AWS::Error
(现在和将来)定义的所有内容添加到隐式内核类中,后者是每个类的祖先.这意味着一切都会过去kind_of?(Amazon::AWS::Error)
.
如何才能最好地区分动态创建的异常Amazon::AWS::Error
与其他地方的随机异常?
Jean.. 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]
的种类?告诉你是的,错误确实拥有All A :: B :: Error行为(这是正常的,因为它包含A :: B :: Error)但是它不包括A :: B的所有行为,因此不是A :: B种类.(鸭子打字)
现在很有可能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
(编辑 - 上面的代码不能正常工作:name包含模块前缀,这不是常量数组的情况.你应该联系lib维护者,AWSError类看起来更像是工厂类:/)
我这里没有ruby-aws,并且校准站点被公司的防火墙阻止,所以我无法进一步测试.
关于include:可能是在StandardError层次结构上进行猴子修补的事情.我不确定,但最有可能在每个上下文之外的文件的根目录下执行它包括Object上的模块或Object元类.(这是在IRB中会发生的情况,其中默认上下文是Object,在文件中不确定)
来自模块上的镐:
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 for locked in platforms)
好的,我会尽力帮助:
首先,模块不是类,它允许您在类中混合行为.第二个看到以下示例:
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]
的种类?告诉你是的,错误确实拥有All A :: B :: Error行为(这是正常的,因为它包含A :: B :: Error)但是它不包括A :: B的所有行为,因此不是A :: B种类.(鸭子打字)
现在很有可能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
(编辑 - 上面的代码不能正常工作:name包含模块前缀,这不是常量数组的情况.你应该联系lib维护者,AWSError类看起来更像是工厂类:/)
我这里没有ruby-aws,并且校准站点被公司的防火墙阻止,所以我无法进一步测试.
关于include:可能是在StandardError层次结构上进行猴子修补的事情.我不确定,但最有可能在每个上下文之外的文件的根目录下执行它包括Object上的模块或Object元类.(这是在IRB中会发生的情况,其中默认上下文是Object,在文件中不确定)
来自模块上的镐:
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 for locked in platforms)