<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Gray Soft / Tags / Documentation</title>
  <id>tag:graysoftinc.com,2014-03-20:/tags/Documentation</id>
  <updated>2014-04-11T15:01:50Z</updated>
  <link rel="self" href="http://graysoftinc.com/tags/Documentation/feed.xml"/>
  <link rel="alternate" href="http://graysoftinc.com/tags/Documentation"/>
  <author>
    <name>James Edward Gray II</name>
  </author>
  <entry>
    <title>Summoning Error Classes As Needed</title>
    <link rel="alternate" href="http://graysoftinc.com/ruby-voodoo/summoning-error-classes-as-needed"/>
    <id>tag:graysoftinc.com,2008-06-26:/posts/54</id>
    <updated>2014-04-11T15:01:50Z</updated>
    <summary>Tired of maintaining a lengthy list of error types?  Me too.</summary>
    <content type="html">&lt;p&gt;In the past, I've written a lot of code like this:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeThing&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeError&lt;/span&gt;       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AnotherError&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;YetAnotherError&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# some methods that can raise the above errors...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I have a new strategy I've been using for code like this and it has really been working out well.  Here is how I do the same thing today:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SmarterThing&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;const_missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# :nodoc:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;error_name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_s&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/Error\z/&lt;/span&gt;
      &lt;span class="nb"&gt;const_set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Class&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="k"&gt;super&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# error raising methods here...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let's discuss how this works.  The &lt;code&gt;const_missing()&lt;/code&gt; method is a hook in Ruby, much like the beloved &lt;code&gt;method_missing()&lt;/code&gt;.  Note that &lt;code&gt;const_missing()&lt;/code&gt; is a class method though, instead of an instance method.  When a constant is used and Ruby can't find it, a call to the hook will be triggered.&lt;/p&gt;

&lt;p&gt;In this version, I just check to see if the constant name ends in &lt;code&gt;Error&lt;/code&gt;.  If it does, I summon an &lt;code&gt;Exception&lt;/code&gt; subclass on the fly.  Other calls to this hook are forwarded on to Ruby's default error raising implementation via &lt;code&gt;super&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The building of the &lt;code&gt;Exception&lt;/code&gt; subclass has a few interesting points of note.  First, we see that we can build a &lt;code&gt;Class&lt;/code&gt; object as we do any other with a simple call to &lt;code&gt;new()&lt;/code&gt;.  Beyond that, we can pass &lt;code&gt;new()&lt;/code&gt; a parent Class we would like to inherit from.  So if you would prefer to inherit from &lt;code&gt;StandardError&lt;/code&gt;, you can just change the reference here.  Finally, &lt;code&gt;const_set()&lt;/code&gt; assigns the new &lt;code&gt;Class&lt;/code&gt; to the constant name referenced and returns it.  This means that future references for the same constant will not go through this hook and will receive the same &lt;code&gt;Class&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That's the how, but let's talk a little about the why.&lt;/p&gt;

&lt;p&gt;When I showed this trick to a friend, he complained that these summoned errors are not easily RDoced.  That's true, but I've actually found this is improving my documentation instead of hurting it.&lt;/p&gt;

&lt;p&gt;Raise your hand if you tend to click on all the errors listed in the API documentation and read about those.  Yeah, I don't either.  With those gone (and note that I explicitly disabled RDoc for my hack), I just add details about the &lt;code&gt;Exception&lt;/code&gt;s a method can raise to the RDoc of that method.  The end result of all this is that the documentation has moved to a place where it is helpful to me and thus I actually read it.&lt;/p&gt;

&lt;p&gt;A final bonus of this technique is that it even works if you are dynamically generating error names in some code, say with &lt;code&gt;const_get()&lt;/code&gt;.&lt;/p&gt;</content>
    <author>
      <name>James Edward Gray II</name>
    </author>
  </entry>
</feed>
