Note that there are some explanatory texts on larger screens.

plurals
  1. PORuby exception inheritance with dynamically generated classes
    text
    copied!<p>I'm new to Ruby, so I'm having some trouble understanding this weird exception problem I'm having. I'm using the ruby-aaws gem to access Amazon ECS: <a href="http://www.caliban.org/ruby/ruby-aws/" rel="nofollow noreferrer">http://www.caliban.org/ruby/ruby-aws/</a>. This defines a class Amazon::AWS:Error:</p> <pre><code>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 </code></pre> <p>This means that if you get an errorcode like <code>AWS.InvalidParameterValue</code>, this will produce (in its exception variable) a new class <code>Amazon::AWS::Error::InvalidParameterValue</code> which is a subclass of <code>StandardError</code>.</p> <p>Now here's where it gets weird. I have some code that looks like this:</p> <pre><code>begin do_aws_stuff rescue Amazon::AWS::Error =&gt; error puts "Got an AWS error" end </code></pre> <p>Now, if <code>do_aws_stuff</code> throws a <code>NameError</code>, my rescue block gets triggered. It seems that Amazon::AWS::Error isn't the superclass of the generated error - I guess since it's a module everything is a subclass of it? Certainly if I do:</p> <pre><code>irb(main):007:0&gt; NameError.new.kind_of?(Amazon::AWS::Error) =&gt; true </code></pre> <p>It says <code>true</code>, which I find confusing, especially given this:</p> <pre><code>irb(main):009:0&gt; NameError.new.kind_of?(Amazon::AWS) =&gt; false </code></pre> <p>What's going on, and how am I supposed to separate out AWS errors from other type of errors? Should I do something like:</p> <pre><code>begin do_aws_stuff rescue =&gt; error if error.class.to_s =~ /^Amazon::AWS::Error/ puts "Got an AWS error" else raise error end end </code></pre> <p>That seems exceptionally janky. The errors thrown aren't class AWSError either - they're raised like this:</p> <pre><code>error = Amazon::AWS::Error::AWSError.new( xml ) raise error.exception </code></pre> <p>So the exceptions I'm looking to <code>rescue</code> from are the generated exception types that only inherit from StandardError.</p> <p>To clarify, I have two questions:</p> <ol> <li><p>Why is NameError, a Ruby built in exception, a <code>kind_of?(Amazon::AWS::Error)</code>, which is a module?<br> <strong>Answer:</strong> I had said <code>include Amazon::AWS::Error</code> at the top of my file, thinking it was kind of like a Java import or C++ include. What this actually did was add everything defined in <code>Amazon::AWS::Error</code> (present and future) to the implicit Kernel class, which is an ancestor of every class. This means <strong>anything</strong> would pass <code>kind_of?(Amazon::AWS::Error)</code>.</p></li> <li><p>How can I best distinguish the dynamically-created exceptions in <code>Amazon::AWS::Error</code> from random other exceptions from elsewhere?</p></li> </ol>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload