Ruby Ausnahme Vererbung mit dynamisch generierten Klassen
-
09-06-2019 - |
Frage
Ich bin neu in Ruby, also, ich habe einige Schwierigkeiten zu verstehen, diese seltsame Ausnahme problem, das ich habe.Ich bin mit dem ruby-aaws Juwel, um Zugriff auf Amazon ECS: http://www.caliban.org/ruby/ruby-aws/.Dies definiert eine Klasse von Amazon::AWS:Fehler:
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
Dies bedeutet, dass, wenn Sie einen Fehlercode wie AWS.InvalidParameterValue
, daraus wird sich (in seiner Ausnahme-variable) eine neue Klasse Amazon::AWS::Error::InvalidParameterValue
was ist eine Unterklasse von StandardError
.
Nun, hier wird es komisch.Ich habe einige code, der wie folgt aussieht:
begin
do_aws_stuff
rescue Amazon::AWS::Error => error
puts "Got an AWS error"
end
Nun, wenn do_aws_stuff
wirft ein NameError
, meine rescue-block wird ausgelöst.Es scheint, dass Amazon::AWS::Fehler ist nicht die Oberklasse des generierten Fehler, - ich denke, da es ein Modul alles, was eine Unterklasse von es?Sicherlich, wenn ich tun:
irb(main):007:0> NameError.new.kind_of?(Amazon::AWS::Error)
=> true
Es sagt true
, finde ich verwirrend, zumal diese:
irb(main):009:0> NameError.new.kind_of?(Amazon::AWS)
=> false
Was ist Los, und wie soll ich den separaten AWS-Fehler aus andere Art von Fehler?Sollte ich etwas tun wie:
begin
do_aws_stuff
rescue => error
if error.class.to_s =~ /^Amazon::AWS::Error/
puts "Got an AWS error"
else
raise error
end
end
Das scheint außergewöhnlich kitschige.Die Fehler, die ausgelöst werden, sind nicht Klasse AWSError entweder sind Sie aufgewachsen, wie diese:
error = Amazon::AWS::Error::AWSError.new( xml )
raise error.exception
Also die Ausnahmen, ich bin auf der Suche, um rescue
sind die generierten exception-Typen, die nur Erben von StandardError.
Um zu klären, ich habe zwei Fragen:
Warum ist NameError, ein Ruby-Baujahr Ausnahme
kind_of?(Amazon::AWS::Error)
, was ist ein Modul?
Antwort: Ich hatte gesagtinclude Amazon::AWS::Error
an der Spitze meiner Datei, dachte, es war wie eine Art von import Java oder C++ gehören.Was ist das eigentlich Tat, war fügen Sie alles, was definiertAmazon::AWS::Error
(Gegenwart und Zukunft) auf die implizite Kernel-Klasse ist ein Vorfahr von jeder Klasse.Dies bedeutet, dass alles passkind_of?(Amazon::AWS::Error)
.Wie kann ich am besten unterscheiden, die dynamisch erstellten Ausnahmen
Amazon::AWS::Error
aus zufälligen andere Ausnahmen von anderswo?
Lösung
Ok, ich werde versuchen, hier zu helfen :
Zuerst ein Modul ist keine Klasse, es ermöglicht Sie zu mischen Verhalten in einer Klasse.zweite siehe das folgende Beispiel :
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?sagt Sie ja, Fehler macht besitzen Alle von A::B::Error Verhalten (das ist normal, denn es enthält A::B::Error) jedoch nicht alle das Verhalten von A::B und ist daher nicht der A::B Art.(duck typing)
Jetzt gibt es eine sehr gute chance, dass ruby-aws-öffnet eine der Oberklasse NameError und enthält Amazon::AWS:Fehler drin.(monkey-patching)
Finden Sie ein Programm, in dem das Modul enthalten ist, in der Hierarchie mit den folgenden :
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)
Bezüglich deiner zweiten Frage kann ich nicht sehen, nichts besser als
begin
#do AWS error prone stuff
rescue Exception => e
if Amazon::AWS::Error.constants.include?(e.class.name)
#awsError
else
whatever
end
end
(Bearbeiten -- obigen code nicht funktioniert ist :name enthält-Modul-Präfix, das ist nicht der Fall, der die Konstanten-arrays.Sie sollten auf jeden Fall Kontakt mit der lib Betreuer der AWSError Klasse sieht eher aus wie eine factory-Klasse zu mir :/ )
Ich habe keine ruby-aws-hier caliban und die Seite ist blockiert durch firewall des Unternehmens, so kann ich nicht testen, viel weiter.
In Bezug auf die enthalten :das könnte der Sache zu tun die monkey-patching auf der Standardfehler Hierarchie.Ich bin mir nicht mehr sicher, aber wahrscheinlich tun Sie es im Stammverzeichnis eine Datei außerhalb jeder Kontext ist darunter das Modul auf einem Objekt oder über das Objekt metaclass.(dies ist, was passieren würde, in IRB, wo die Standard-Kontext-Objekt, nicht sicher in einer Datei)
aus der Spitzhacke auf Module :
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.
(Bearbeiten -- ich kann nicht scheinen, um einen Kommentar abgeben zu können mit dieser browser -: / yay für locked-in-Plattformen)
Andere Tipps
Naja, was ich sagen kann:
Class.new( StandardError )
Ist die Schaffung einer neuen Klasse mit Standardfehler als Basisklasse, so ist es nicht zu Amazon::AWS::Fehler überhaupt.Es ist nur definiert, das Modul, die ist wahrscheinlich, warum es ist ein kind_of?Amazon::AWS::Error.Es ist wahrscheinlich nicht eine kind_of?Amazon::AWS-vielleicht, weil die Module nicht nest für Zwecke der kind_of??
Tut mir Leid, ich weiß nicht, Module sehr gut in Ruby, aber auf jeden Fall die Basisklasse wird StandardError.
UPDATE:Durch die Art und Weise, aus der ruby-docs:
obj.kind_of?(Klasse) => wahr oder falsch
Gibt true zurück, wenn die Klasse die Klasse von obj, oder wenn eine Klasse eines der Oberklassen des obj oder Module, die in obj.
Wollte nur mal erwähnen:Ich würde Zustimmen, dass dies ein bug in der lib-code.Es sollte wohl Lesen:
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
Ein Problem, Sie laufen in ist, dass Amazon::AWS::Error::AWSError
ist nicht wirklich eine Ausnahme.Wenn raise
aufgerufen wird, schaut, um zu sehen, wenn der erste parameter reagiert auf die exception
Methode und verwenden Sie das Ergebnis, dass statt.Alles, was eine Unterklasse von Exception
zurückkehren wird, selbst wenn exception
heißt also, Sie können Dinge tun, wie raise Exception.new("Something is wrong")
.
In diesem Fall, AWSError
hat exception
als Attribut-Leser, die es definiert den Wert bei der Initialisierung um so etwas wie Amazon::AWS::Error::SOME_ERROR
.Dies bedeutet, dass, wenn Sie anrufen raise Amazon::AWS::Error::AWSError.new(SOME_XML)
Ruby endet Aufruf Amazon::AWS::Error::AWSError.new(SOME_XML).exception
die gibt eine Instanz von Amazon::AWS::Error::SOME_ERROR
.Wie gezeigt, durch eine der anderen Responder, diese Klasse ist eine direkte Unterklasse von StandardError
anstatt eine Unterklasse einer gemeinsamen Amazon-Fehler.Bis dies behoben, Jean-Lösung ist wahrscheinlich Ihre beste Wette.
Ich hoffe, geholfen zu erklären, was tatsächlich passiert hinter den kulissen.