Ruby exception inheritance with dynamically generated classes

I am new to Ruby, so I am having trouble understanding this strange exception problem that I am experiencing. I use the ruby-aaws gem to access Amazon ECS: http://www.caliban.org/ruby/ruby-aws/ . This defines the Amazon :: AWS class: 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

This means that if you get an error code, for example AWS.InvalidParameterValue, it will lead (in its exception variable) to a new class Amazon::AWS::Error::InvalidParameterValue, which is a subclass StandardError.

Now that is getting weird. I have a code that looks like this:

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 from, , StandardError.

, :

  • NameError, Ruby , kind_of?(Amazon::AWS::Error), ?
    : include Amazon::AWS::Error , , Java ++. , , , Amazon::AWS::Error ( ) Kernel, . , - kind_of?(Amazon::AWS::Error).

  • Amazon::AWS::Error ?

+3
4

, :

, . . :

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:: Error ( , A:: B:: Error), A:: B , , A:: B. ( )

, ruby-aws NameError Amazon:: AWS: . ( )

, :

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

(edit - : name , . AWSError, factory:/)

ruby-aws, caliban , .

: , StandardError. , , , , Object Object. ( , IRB, - Object, )

pickaxe :

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 )

+5

, :

Class.new( StandardError )

StandardError , Amazon:: AWS:: Error . , , , ? Amazon:: AWS:: . , , ? Amazon:: AWS, , , kind_of?

, Ruby, StandardError.

UPDATE: , :

obj.kind_of? (class) = > true false

true, obj, obj , obj.

+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
+1

, , , Amazon::AWS::Error::AWSError . raise, , exception . , exception, , exception, , raise Exception.new("Something is wrong").

In this case, it AWSErrorhas exception, configured as an attribute reader, which defines the value for initialization somehow Amazon::AWS::Error::SOME_ERROR. This means that when invoked, raise Amazon::AWS::Error::AWSError.new(SOME_XML)Ruby terminates the invocation Amazon::AWS::Error::AWSError.new(SOME_XML).exceptionthat returns the instance Amazon::AWS::Error::SOME_ERROR. As one of the other respondents noted, this class is a direct subclass, StandardErrorrather than being a subclass of the common Amazon error. Until this is fixed, Jean's decision is likely to be your best bet.

I hope this helps explain more of what is actually happening behind the scenes.

0
source

Source: https://habr.com/ru/post/1696933/


All Articles