Domanda

Sono nuovo in Ruby, quindi ho qualche difficoltà a comprendere questo strano problema di eccezioni che sto riscontrando.Sto utilizzando la gemma ruby-aaws per accedere ad Amazon ECS: http://www.caliban.org/ruby/ruby-aws/.Questo definisce una classe 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

Ciò significa che se ricevi un codice di errore simile AWS.InvalidParameterValue, questo produrrà (nella sua variabile di eccezione) una nuova classe Amazon::AWS::Error::InvalidParameterValue che è una sottoclasse di StandardError.

Ora ecco dove diventa strano.Ho un codice che assomiglia a questo:

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

Ora se do_aws_stuff lancia a NameError, il mio blocco di salvataggio viene attivato.Sembra che Amazon::AWS::Error non sia la superclasse dell'errore generato - immagino che, dato che è un modulo, tutto ne sia una sottoclasse?Certamente se lo faccio:

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

Dice true, che trovo confuso, soprattutto considerando questo:

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

Cosa sta succedendo e come dovrei separare gli errori AWS da altri tipi di errori?Dovrei fare qualcosa del tipo:

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

Sembra eccezionalmente strano.Anche gli errori lanciati non appartengono alla classe AWSError: vengono sollevati in questo modo:

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

Quindi le eccezioni che sto cercando rescue from sono i tipi di eccezione generati che ereditano solo da StandardError.

Per fare chiarezza avrei due domande:

  1. Perché NameError, un'eccezione incorporata in Ruby, a kind_of?(Amazon::AWS::Error), che è un modulo?
    Risposta: avevo detto include Amazon::AWS::Error nella parte superiore del mio file, pensando che fosse una specie di importazione Java o inclusione C++.Ciò che in realtà ha fatto è stato aggiungere tutto ciò che è definito in Amazon::AWS::Error (presente e futuro) alla classe Kernel implicita, che è un antenato di ogni classe.Questo significa nulla passerebbe kind_of?(Amazon::AWS::Error).

  2. Come posso distinguere al meglio le eccezioni create dinamicamente in Amazon::AWS::Error da altre eccezioni casuali provenienti da altrove?

È stato utile?

Soluzione

Ok, provo ad aiutarti qui:

Innanzitutto un modulo non è una classe, ti consente di mescolare i comportamenti in una classe.secondo vedere il seguente esempio:

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]

tipo?ti dice che sì, Error possiede tutto il comportamento di A::B::Error (il che è normale poiché include A::B::Error) tuttavia non include tutto il comportamento di A::B e quindi non lo è del tipo A::B.(anatra digitando)

Ora ci sono ottime possibilità che ruby-aws riapra una delle superclassi di NameError e includa Amazon::AWS:Error al suo interno.(rattoppo della scimmia)

Puoi scoprire a livello di programmazione dove il modulo è incluso nella gerarchia con quanto segue:

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)

Per quanto riguarda la tua seconda domanda, non riesco a vedere niente di meglio di

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

(modifica: il codice sopra non funziona così com'è:name include il prefisso del modulo che non è il caso degli array di costanti.Dovresti assolutamente contattare il manutentore della libreria, la classe AWSError mi sembra più una classe factory :/)

Non ho Ruby-aws qui e il sito Caliban è bloccato dal firewall dell'azienda, quindi non posso testare molto ulteriormente.

Per quanto riguarda l'inclusione:questa potrebbe essere la cosa che fa il patching della scimmia sulla gerarchia StandardError.Non ne sono più sicuro, ma molto probabilmente farlo alla radice di un file al di fuori di ogni contesto include il modulo su Object o sulla metaclasse Object.(questo è ciò che accadrebbe in IRB, dove il contesto predefinito è Oggetto, non sono sicuro in un file)

dal piccone sui moduli :

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.

(modifica: non riesco a commentare utilizzando questo browser:/ yay per le piattaforme bloccate)

Altri suggerimenti

Beh, da quello che posso dire:

Class.new( StandardError )

Sta creando una nuova classe con StandardError come classe base, quindi non sarà affatto un Amazon::AWS::Error.È semplicemente definito in quel modulo, motivo per cui è probabilmente un kind_of?Amazon::AWS::Errore.Probabilmente non è una specie_di?Amazon::AWS perché forse i moduli non si annidano per scopi di kind_of??

Mi dispiace, non conosco molto bene i moduli in Ruby, ma sicuramente la classe base sarà StandardError.

AGGIORNAMENTO:A proposito, dai documenti Ruby:

obj.kind_of?(class) => vero o falso

Restituisce vero se class è la classe di obj o se class è una delle superclassi di obj o dei moduli inclusi in obj.

Volevo solo intervenire:Sono d'accordo che si tratta di un bug nel codice lib.Probabilmente dovrebbe leggere:

      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

Un problema che stai riscontrando è questo Amazon::AWS::Error::AWSError non è in realtà un'eccezione.Quando raise viene chiamato, controlla se il primo parametro risponde al exception metodo e utilizzerà invece il risultato di quello.Tutto ciò che è una sottoclasse di Exception tornerà da solo quando exception si chiama così puoi fare cose del tipo raise Exception.new("Something is wrong").

In questo caso, AWSError ha exception impostato come lettore di attributi che definisce il valore all'inizializzazione in qualcosa di simile Amazon::AWS::Error::SOME_ERROR.Ciò significa che quando chiami raise Amazon::AWS::Error::AWSError.new(SOME_XML) Ruby finisce per chiamare Amazon::AWS::Error::AWSError.new(SOME_XML).exception che restituirà un'istanza di Amazon::AWS::Error::SOME_ERROR.Come è stato sottolineato da uno degli altri intervistati, questa classe è una sottoclasse diretta di StandardError invece di essere una sottoclasse di un errore comune di Amazon.Fino a quando questo problema non verrà risolto, la soluzione di Jean è probabilmente la soluzione migliore.

Spero che questo abbia contribuito a spiegare meglio cosa sta realmente accadendo dietro le quinte.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top