<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Naildrivin' &#10106;]]></title>
  <link href="http://www.naildrivin5.com/atom.xml" rel="self"/>
  <link href="http://www.naildrivin5.com/"/>
  <updated>2012-05-16T15:30:49-04:00</updated>
  <id>http://www.naildrivin5.com/</id>
  <author>
    <name><![CDATA[David Bryant Copeland]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Lookup tables with lambdas]]></title>
    <link href="http://www.naildrivin5.com/blog/2012/05/16/lookup-tables-with-lambdas.html"/>
    <updated>2012-05-16T10:34:00-04:00</updated>
    <id>http://www.naildrivin5.com/blog/2012/05/16/lookup-tables-with-lambdas</id>
    <content type="html"><![CDATA[<p>Yesterday, I tweeted:</p>

<blockquote class="twitter-tweet"><p>x = Hash.new { |_,_|lambda {}}.tap { |hash|hash[:key] = lambda {}}x[attr].callFilthy?I kinda like it</p>&mdash; ❺➠ David Copeland (@davetron5000) <a href="https://twitter.com/davetron5000/status/202520727239409664" data-datetime="2012-05-15T22:07:58+00:00">May 15, 2012</a></blockquote>


<script src="http://www.naildrivin5.com//platform.twitter.com/widgets.js" charset="utf-8"></script>


<p>This may seem crazy, but it&#8217;s a really just an enhanced use of what Steve McConnell, in &#8220;Code Complete&#8221;, describes as
<em>Table-Driven Methods</em>.  Let&#8217;s see what that has to do with my crazy <code>Hash</code> construct.</p>

<!-- more -->


<p>If you haven&#8217;t read <a href="http://www.amazon.com/Code-Complete-Practical-Handbook-Construction/dp/0735619670">&#8220;Code Complete&#8221;</a>, and you are a relatively inexperienced developer, I highly recommend it.  My
version has a lot of Pascal in it, and I think the latest might use Visual Basic (!), but it doesn&#8217;t matter.  There&#8217;s a lot of
useful gems in there.</p>

<p>One of them is &#8220;Table-Driven Methods&#8221;, which he describes as</p>

<blockquote><p>a scheme that allows you to look up information in a table rather than using logic statements to figure it out</p></blockquote>

<p>In the simplest form, you&#8217;d replace a <code>case</code> statement with a table lookup.  Consider this method that determines, based on the
type of credit card, what countries that card can be used in:</p>

<figure class='code'><figcaption><span>Complex case statement</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">countries_usable_in</span>
</span><span class='line'>  <span class="k">case</span> <span class="nb">self</span><span class="o">.</span><span class="n">card_type</span>
</span><span class='line'>    <span class="k">when</span> <span class="s1">&#39;discover&#39;</span>
</span><span class='line'>      <span class="o">[</span><span class="s1">&#39;US&#39;</span><span class="o">]</span>
</span><span class='line'>    <span class="k">when</span> <span class="s1">&#39;maestro&#39;</span>
</span><span class='line'>      <span class="o">[</span><span class="s1">&#39;UK&#39;</span><span class="o">]</span>
</span><span class='line'>    <span class="k">when</span> <span class="s1">&#39;visa&#39;</span>
</span><span class='line'>      <span class="o">[</span><span class="s1">&#39;US&#39;</span><span class="p">,</span><span class="s1">&#39;UK&#39;</span><span class="p">,</span><span class="s1">&#39;IE&#39;</span><span class="o">]</span>
</span><span class='line'>    <span class="k">when</span> <span class="s1">&#39;master_card&#39;</span>
</span><span class='line'>      <span class="o">[</span><span class="s1">&#39;US&#39;</span><span class="p">,</span><span class="s1">&#39;UK&#39;</span><span class="p">,</span><span class="s1">&#39;IE&#39;</span><span class="o">]</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>This could be easily replaced by:</p>

<figure class='code'><figcaption><span>Table-driven method</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">CARD_TYPE_COUNTRIES</span> <span class="o">=</span> <span class="p">{</span>
</span><span class='line'>  <span class="s1">&#39;discover&#39;</span>    <span class="o">=&gt;</span> <span class="o">[</span><span class="s1">&#39;US&#39;</span><span class="o">]</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;maestro&#39;</span>     <span class="o">=&gt;</span> <span class="o">[</span><span class="s1">&#39;UK&#39;</span><span class="o">]</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;visa&#39;</span>        <span class="o">=&gt;</span> <span class="o">[</span><span class="s1">&#39;US&#39;</span><span class="p">,</span><span class="s1">&#39;UK&#39;</span><span class="p">,</span><span class="s1">&#39;ZA&#39;</span><span class="o">]</span><span class="p">,</span>
</span><span class='line'>  <span class="s1">&#39;master_card&#39;</span> <span class="o">=&gt;</span> <span class="o">[</span><span class="s1">&#39;US&#39;</span><span class="p">,</span><span class="s1">&#39;UK&#39;</span><span class="p">,</span><span class="s1">&#39;ZA&#39;</span><span class="o">]</span><span class="p">,</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">def</span> <span class="nf">countries_usable_in</span>
</span><span class='line'>  <span class="no">CARD_TYPE_COUNTRIES</span><span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">card_type</span><span class="o">]</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>This is much less complex, both from a formal perspective, and from a general &#8220;what&#8217;s going on here?&#8221; perspective.  We replace a
bunch of conditionals with a simple mapping.  Enhancing this code is simple: we just add a new entry to the <code>CARD_TYPE_COUNTRIES</code>
<code>Hash</code> and we&#8217;re on our way.</p>

<p>This has a couple of problems with it.  You&#8217;ll notice that both &#8220;visa&#8221; and &#8220;master_card&#8221; map to the same list.  What we really
want is to treat &#8220;discover&#8221; and &#8220;maestro&#8221; as special, and then for any other card type, return our default list of US, UK, and
South Africa.</p>

<p>Ruby&#8217;s <code>Hash</code> constructor can be given a block that returns the value to use when a key is missing, so that would seem to be
useful:</p>

<figure class='code'><figcaption><span>Hash special constructor</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">hash</span> <span class="o">=</span> <span class="no">Hash</span><span class="o">.</span><span class="n">new</span> <span class="p">{</span> <span class="o">|</span><span class="n">key</span><span class="p">,</span><span class="n">value</span><span class="o">|</span>
</span><span class='line'>  <span class="s2">&quot;FOO&quot;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'><span class="nb">hash</span><span class="o">[</span><span class="ss">:blah</span><span class="o">]</span> <span class="c1"># =&gt; &quot;FOO&quot;</span>
</span><span class='line'><span class="nb">hash</span><span class="o">[</span><span class="ss">:blah</span><span class="o">]</span> <span class="o">=</span> <span class="s2">&quot;BAR&quot;</span>
</span><span class='line'><span class="nb">hash</span><span class="o">[</span><span class="ss">:blah</span><span class="o">]</span> <span class="c1"># =&gt; &quot;BAR&quot;</span>
</span><span class='line'><span class="nb">hash</span><span class="o">[</span><span class="ss">:crud</span><span class="o">]</span> <span class="c1"># =&gt; &quot;FOO&quot;</span>
</span></code></pre></td></tr></table></div></figure>


<p>Of course, this makes it a bit awkward to populate our <code>Hash</code> with the lookup table, because we lose the literal syntax.  We can
deal with <em>this</em> by using <code>tap</code>, which passes the object called on it to the block passed to it, executes the block, throws away
the block&#8217;s return value and returns the object on which we called <code>tap</code>.  Whoa.  Let&#8217;s look at an example.</p>

<figure class='code'><figcaption><span>Using Hash special constructor and pre-populating it with values</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">CARD_TYPE_COUNTRIES</span> <span class="o">=</span> <span class="no">Hash</span><span class="o">.</span><span class="n">new</span> <span class="p">{</span> <span class="o">|</span><span class="n">key</span><span class="p">,</span><span class="n">value</span><span class="o">|</span>
</span><span class='line'>  <span class="o">[</span><span class="s1">&#39;US&#39;</span><span class="p">,</span><span class="s1">&#39;UK&#39;</span><span class="p">,</span><span class="s1">&#39;IE&#39;</span><span class="o">]</span>
</span><span class='line'><span class="p">}</span><span class="o">.</span><span class="n">tap</span> <span class="p">{</span> <span class="o">|</span><span class="n">new_hash</span><span class="o">|</span>
</span><span class='line'>  <span class="n">new_hash</span><span class="o">[</span><span class="s1">&#39;discover&#39;</span><span class="o">]</span> <span class="o">=</span> <span class="o">[</span><span class="s1">&#39;US&#39;</span><span class="o">]</span>
</span><span class='line'>  <span class="n">new_hash</span><span class="o">[</span><span class="s1">&#39;maestro&#39;</span><span class="o">]</span>  <span class="o">=</span> <span class="o">[</span><span class="s1">&#39;UK&#39;</span><span class="o">]</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>Now, when we call <code>CARD_TYPE_COUNTRIES['visa']</code>, this uses the block we gave to the constructor, but
<code>CARD_TYPE_COUNTRIES['maestro']</code> simply returns the literal array we assigned in <code>tap</code>.</p>

<p>So far so good.  Now, suppose we have a new requirement to add American Express.  Suppose that American Express isn&#8217;t supported in African countries, but works everywhere else.  Since we don&#8217;t want to hard-code what countries are in Africa, we&#8217;ll need to consult the database.</p>

<figure class='code'><figcaption><span>Yucky implementation</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">countries_usable_in</span>
</span><span class='line'>  <span class="n">countries</span> <span class="o">=</span> <span class="no">CARD_TYPE_COUNTRIES</span><span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">card_type</span><span class="o">]</span>
</span><span class='line'>  <span class="k">if</span> <span class="nb">self</span><span class="o">.</span><span class="n">card_type</span> <span class="o">==</span> <span class="s1">&#39;american_express&#39;</span>
</span><span class='line'>    <span class="n">countries</span> <span class="o">-</span> <span class="no">Continent</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s2">&quot;Africa&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">countries</span>
</span><span class='line'>  <span class="k">else</span>
</span><span class='line'>    <span class="n">countries</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>We&#8217;ve re-introduced those pesky control structures we were trying to remove.  Why can&#8217;t we do this?</p>

<figure class='code'><figcaption><span>Putting database calls into our constant initialization</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">DEFAULT_COUNTRIES</span> <span class="o">=</span> <span class="o">[</span><span class="s1">&#39;US&#39;</span><span class="p">,</span><span class="s1">&#39;UK&#39;</span><span class="p">,</span><span class="s1">&#39;IE&#39;</span><span class="o">]</span>
</span><span class='line'><span class="no">CARD_TYPE_COUNTRIES</span> <span class="o">=</span> <span class="no">Hash</span><span class="o">.</span><span class="n">new</span> <span class="p">{</span> <span class="o">|</span><span class="n">key</span><span class="p">,</span><span class="n">value</span><span class="o">|</span>
</span><span class='line'>  <span class="no">DEFAULT_COUNTRIES</span>
</span><span class='line'><span class="p">}</span><span class="o">.</span><span class="n">tap</span> <span class="p">{</span> <span class="o">|</span><span class="n">new_hash</span><span class="o">|</span>
</span><span class='line'>  <span class="n">new_hash</span><span class="o">[</span><span class="s1">&#39;discover&#39;</span><span class="o">]</span>         <span class="o">=</span> <span class="o">[</span><span class="s1">&#39;US&#39;</span><span class="o">]</span>
</span><span class='line'>  <span class="n">new_hash</span><span class="o">[</span><span class="s1">&#39;maestro&#39;</span><span class="o">]</span>          <span class="o">=</span> <span class="o">[</span><span class="s1">&#39;UK&#39;</span><span class="o">]</span>
</span><span class='line'>  <span class="n">new_hash</span><span class="o">[</span><span class="s1">&#39;american_express&#39;</span><span class="o">]</span> <span class="o">=</span> <span class="no">DEFAULT_COUNTRIES</span> <span class="o">-</span> <span class="no">Continent</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s2">&quot;Africa&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">countries</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>This has two problems:</p>

<ul>
<li>The database query is only run on app startup, so any changes won&#8217;t affect things until we restart (imagine our <code>COUNTRIES</code> table only having countries we support and not <em>all</em> countries; we want to add new countries without an app restart)</li>
<li>We are running a database query inside a class definition and we don&#8217;t necessarily have a guarantee that the database connection is even established at that point.</li>
</ul>


<p>What we need is a lookup table that calculates its results on demand.  Ruby has a structure for that: <code>lambda</code></p>

<figure class='code'><figcaption><span>Lookup table that calculates results on demand</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">DEFAULT_COUNTRIES</span> <span class="o">=</span> <span class="o">[</span><span class="s1">&#39;US&#39;</span><span class="p">,</span><span class="s1">&#39;UK&#39;</span><span class="p">,</span><span class="s1">&#39;IE&#39;</span><span class="o">]</span>
</span><span class='line'><span class="no">CARD_TYPE_COUNTRIES</span> <span class="o">=</span> <span class="no">Hash</span><span class="o">.</span><span class="n">new</span> <span class="p">{</span> <span class="o">|</span><span class="n">key</span><span class="p">,</span><span class="n">value</span><span class="o">|</span>
</span><span class='line'>  <span class="no">DEFAULT_COUNTRIES</span>
</span><span class='line'><span class="p">}</span><span class="o">.</span><span class="n">tap</span> <span class="p">{</span> <span class="o">|</span><span class="n">new_hash</span><span class="o">|</span>
</span><span class='line'>  <span class="n">new_hash</span><span class="o">[</span><span class="s1">&#39;discover&#39;</span><span class="o">]</span>         <span class="o">=</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="o">[</span><span class="s1">&#39;US&#39;</span><span class="o">]</span> <span class="p">}</span>
</span><span class='line'>  <span class="n">new_hash</span><span class="o">[</span><span class="s1">&#39;maestro&#39;</span><span class="o">]</span>          <span class="o">=</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="o">[</span><span class="s1">&#39;UK&#39;</span><span class="o">]</span> <span class="p">}</span>
</span><span class='line'>  <span class="n">new_hash</span><span class="o">[</span><span class="s1">&#39;american_express&#39;</span><span class="o">]</span> <span class="o">=</span> <span class="nb">lambda</span> <span class="p">{</span>
</span><span class='line'>    <span class="no">DEFAULT_COUNTRIES</span> <span class="o">-</span> <span class="no">Continent</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s2">&quot;Africa&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">countries</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="k">def</span> <span class="nf">countries_usable_in</span>
</span><span class='line'>  <span class="no">CARD_TYPE_COUNTRIES</span><span class="o">[</span><span class="nb">self</span><span class="o">.</span><span class="n">card_type</span><span class="o">].</span><span class="n">call</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>I find this to be a pretty clean solution.  We have all the benefits of a table-driven approach, but only need to specify special
cases (thanks to our default block), and have the ability to calcualte our results on demand, based on the current state of the system (thanks to using lambdas and static values).  Not too bad.</p>

<p>Let&#8217;s take this concept even further.  We often write code using an <code>if..elsif..else..end</code> structure that essentially tries
various conditions to find one that holds, and returns a value based on that condition.</p>

<p>As an example, we&#8217;ll switch domains to my favorite: <a href="http://www.pragprog.com/titles/dccar">command line apps</a>.  Suppose I need to determine the size of the user&#8217;s terminal so I can properly format output.  My algorithm will be:</p>

<ul>
<li>If the environment variable <code>COLUMNS</code> is a number, use that</li>
<li>Otherwise, if the command <code>tput</code> exists, run <code>tput lines</code> and return its output</li>
<li>Otherwise, if the command <code>stty</code> exists, run <code>stty size</code> and parse its output for the value</li>
<li>Otherwise, return a sensible default.</li>
</ul>


<p>How does this apply to our lookup table?  Essentially we want a table of conditions and, for the first one that holds, perform
the calculation to figure out the size.  For the sake of clarity, we&#8217;ll assume some helper methods, which gives us this code:</p>

<figure class='code'><figcaption><span>Good ole if/elsif/else</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">terminal_columns</span>
</span><span class='line'>  <span class="k">if</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;COLUMNS&#39;</span><span class="o">]</span> <span class="o">=~</span> <span class="sr">/^\s+$/</span>
</span><span class='line'>    <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;COLUMNS&#39;</span><span class="o">]</span>
</span><span class='line'>  <span class="k">elsif</span> <span class="n">command_exists?</span><span class="p">(</span><span class="s2">&quot;tput&quot;</span><span class="p">)</span>
</span><span class='line'>    <span class="sb">`tput lines`</span><span class="o">.</span><span class="n">chomp</span><span class="o">.</span><span class="n">to_i</span>
</span><span class='line'>  <span class="k">elsif</span> <span class="n">command_exists?</span><span class="p">(</span><span class="s2">&quot;stty&quot;</span><span class="p">)</span>
</span><span class='line'>    <span class="n">parse_stty</span>
</span><span class='line'>  <span class="k">else</span>
</span><span class='line'>    <span class="no">DEFAULT_COLUMNS</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>This is a pretty complex routine.  What if we need to add Windows support?  Another <code>elsif</code>.  Lets use our newfound lookup table
powers, but instead of using a static key for lookup, we&#8217;ll use a dynamic one, based on our conditions:</p>

<figure class='code'><figcaption><span>Ordered lookup</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">TERMINAL_SIZES</span> <span class="o">=</span> <span class="o">[</span>
</span><span class='line'>  <span class="p">{</span> <span class="ss">:test</span> <span class="o">=&gt;</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;COLUMNS&#39;</span><span class="o">]</span> <span class="o">=~</span> <span class="sr">/^\s+$/</span> <span class="p">},</span> <span class="ss">:val</span> <span class="o">=&gt;</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;COLUMNS&#39;</span><span class="o">]</span> <span class="p">},</span>
</span><span class='line'>  <span class="p">{</span> <span class="ss">:test</span> <span class="o">=&gt;</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="n">command_exists?</span><span class="p">(</span><span class="s2">&quot;tput&quot;</span><span class="p">)</span> <span class="p">},</span>   <span class="ss">:val</span> <span class="o">=&gt;</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="sb">`tput lines`</span><span class="o">.</span><span class="n">chomp</span><span class="o">.</span><span class="n">to_i</span> <span class="p">},</span>
</span><span class='line'>  <span class="p">{</span> <span class="ss">:test</span> <span class="o">=&gt;</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="n">command_exists?</span><span class="p">(</span><span class="s2">&quot;stty&quot;</span><span class="p">)</span> <span class="p">},</span>   <span class="ss">:val</span> <span class="o">=&gt;</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="n">parse_stty</span> <span class="p">},</span>
</span><span class='line'>  <span class="p">{</span> <span class="ss">:test</span> <span class="o">=&gt;</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="kp">true</span> <span class="p">},</span>                      <span class="ss">:val</span> <span class="o">=&gt;</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="no">DEFAULT_COLUMNS</span> <span class="p">},</span>
</span><span class='line'><span class="o">]</span>
</span></code></pre></td></tr></table></div></figure>


<p>Note that we&#8217;re using an array to keep things ordered, but we&#8217;re using an <code>Array</code> of <code>Hash</code> so that our client code will be
fairly readable (we&#8217;ll see that in a second).</p>

<p>Recall that we want the first expression that returns true, and to return the value associated with that expression.  This is a
one-liner, thanks to Ruby&#8217;s aweomse collections:</p>

<figure class='code'><figcaption><span>Holy functional programming, Batman!</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">terminal_columns</span>
</span><span class='line'>  <span class="no">TERMINAL_SIZES</span><span class="o">.</span><span class="n">find</span> <span class="p">{</span> <span class="o">|</span><span class="n">size</span><span class="o">|</span> <span class="n">size</span><span class="o">[</span><span class="ss">:test</span><span class="o">].</span><span class="n">call</span> <span class="p">}</span><span class="o">.</span><span class="n">first</span><span class="o">[</span><span class="ss">:val</span><span class="o">].</span><span class="n">call</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Not bad.</p>

<p>Now, if you come across something like this, but didn&#8217;t derive it as we have done here, is it really better?  I would argue that
it is, especially if you are comfortable with the general concept of table-driven algorithms.  In the case of our credit card
example, you can see a clear mapping between special cases and the results.  For the terminal lines example here, we again have a
clean mapping between test and result, and it&#8217;s not muddied up amongst control structures.</p>

<p>These tables are also more easily changed: new cases can be added to our credit card type table, and we can easily re-order our
terminal size calculation if we decide on a better strategy.</p>

<p>If you find yourself writing an <code>elsif</code> or a <code>case</code> statement; consider using a table-driven method.  Ruby provides excellent
tools to make this easy to do for any use case.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[† What Makes and Awesome Command-Line App?]]></title>
    <link href="http://www.naildrivin5.com/blog/2012/05/02/what-makes-and-awesome-command-line-app.html"/>
    <updated>2012-05-02T09:40:00-04:00</updated>
    <id>http://www.naildrivin5.com/blog/2012/05/02/what-makes-and-awesome-command-line-app</id>
    <content type="html"><![CDATA[<p>I wrote an article in the latest <a href="http://pragprog.com/magazines/2012-05/content">PragPub magazine</a> called <a href="http://pragprog.com/magazines/2012-05/what-makes-an-awesome-commandline-application">What Makes an Awesome Command-line Application?</a>.  Check it out!  If you want a more code-focused and detailed version, see <a href="http://www.naildrivin5.com/blog/2012/04/01/the-nine-facets-of-an-awesome-command-line-app.html">The Nine Facets of an Awesome Command-Line App</a> and, of course, <a href="http://www.pragprog.com/titles/dccar">my book</a>.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[&#10106;&#10144; Five Months of eBook Sales]]></title>
    <link href="http://www.naildrivin5.com/blog/2012/04/24/five-months-of-ebook-sales.html"/>
    <updated>2012-04-24T10:00:00-04:00</updated>
    <id>http://www.naildrivin5.com/blog/2012/04/24/five-months-of-ebook-sales</id>
    <content type="html"><![CDATA[<p>I really enjoyed reading <a href="http://www.twitter.com/jstorimer">Jesse Storimer&#8217;s</a> recent post, <a href="http://jstorimer.com/2012/04/20/4-months-of-ebook-sales.html">4 Months of ebook Sales</a>, about the sales of his book <a href="http://workingwithunixprocesses.com/">&#8220;Working with Unix Processes&#8221;</a>.  His feelings echo my own regarding my book, <a href="http://pragprog.com/titles/dccar/">&#8220;Build Awesome Command-Line Applications in Ruby&#8221;</a>:</p>

<blockquote><p>I&#8217;m ecstatic with the results so far, but I have no idea how they compare.</p><footer><strong>Jesse Storimer,</strong> <cite><a href='http://jstorimer.com/2012/04/20/4-months-of-ebook-sales.html'>jstorimer.com/2012/04/20/&hellip;</a></cite></footer></blockquote>


<p>Our books complement each other quite well, and came out around the same time.  He wrote his largely on his own, going the self-publishing route, while I wrote mine with the <a href="http://pragprog.com/">Pragmatic Programmers</a>.  I thought I&#8217;d write a similar piece from my experience going the &#8220;traditional&#8221; route.</p>

<!-- more -->


<h3>Beginning</h3>

<p>I wrote an initial draft of &#8220;Build Awesome Command-Line Applications in Ruby&#8221; over November 2010, as part of <a href="http://forums.pragprog.com/forums/235">PragProWriMo</a>.  I
wrote almost every day, and had about 170 pages of Markdown written at the end.  I hadn&#8217;t thought too far ahead, but in January of 2011, I decided to submit it to the Prags and see if they were interested.</p>

<p>To my surprise and excitement they decided to go forward with it!  I had no idea what to expect, but figured that since I had a good 75% of a &#8220;real&#8221; book done, it shouldn&#8217;t be too much more work for me to finish up the first draft and clean it up.  Boy was I wrong.</p>

<p>I spent the next 11 months on the book, reaching &#8220;done&#8221; by February of this year.  That may seem like a long time (it certainly did to me).  The reason it took &#8220;so long&#8221; was entirely due to working with a publisher and editor, but I don&#8217;t mean that as a negative.  It actually <em>needed</em> to take that long, and the book I shipped was markedly better than anything I would&#8217;ve done on my own.</p>

<h3>Developing</h3>

<p>The Prags don&#8217;t just take your manuscript, spell-check it and ship it.  They assign a <em>development editor</em> to each book.  I had no idea what this was; I thought editors fixed spelling and grammar mistakes.  Instead, John Osborn, my editor, provided deep and insightful feedback on every aspect of the book.  Did the sections flow together?  Are the titles consistent? Did the examples make sense?  Of course, I had created plenty of passive voice, subject/verb disagreement and other &#8220;advanced grammar mishaps&#8221; to keep John quite busy.</p>

<p>Identifying these issues in your own work is hard.  It&#8217;s also just not possible to get real, usable feedback on your work.
Friends and colleagues just won&#8217;t give you the brutal, honest feedback you sometimes need.  It had been a long time since I&#8217;ve
been given this sort of feedback, and it hurt a bit (at first) to read comments like these:</p>

<ul>
<li>&#8220;The overall premise of the book is not immediately clear.&#8221;</li>
<li>&#8220;The audience level remains unclear.&#8221;</li>
<li>&#8220;After a while&#8230;it just gets wearing. Why should I bother to read yet one more example when I know that I’ll be told this was the wrong way to do it?&#8221;</li>
</ul>


<p>These came after John and I had spent a lot of time working my initial manuscript into something publishable, and had gotten a
lot of positive feedback from the tech reviewers.  Based on the publisher feedback, we were looking at an almost total rewrite, and I wasn&#8217;t too happy about it.  But, I really believed in the book and wasn&#8217;t about to quit now, so I trusted the publishers.  Recognizing their experience, I treated this as a learning opportunity.  So we persevered.</p>

<h3>Persevering</h3>

<p>Three chapters later, it was so clear to me that I had been wrong that I couldn&#8217;t believe I had felt otherwise.   And, I never would&#8217;ve gotten there without such honest feedback and a literal <em>team</em> of professionals<sup id='fnref:1'><a href='#fn:1' rel='footnote'>1</a></sup> working to make my book
as good as it could be.  In the end, the book bears little resemblance to what I had produced during PragProWriMo, and, while I
probably could&#8217;ve gotten that into a &#8220;sellable&#8221; shape, it would not have been nearly as good.</p>

<p>So, a total of 15 months of work, including an almost total rewrite, all on my own time, with no money up front.  Was it worth
it? Absolutely. But, how has it been selling?</p>

<p>On the one hand, I&#8217;m not sure.  I don&#8217;t know how many copies of my book will &#8220;pay for&#8221; the development costs, or how many will
make the publishers &#8220;happy&#8221; with the result (I&#8217;ve put off asking in case the answer is &#8220;way more than you&#8217;ve sold&#8221;).  I do know that I&#8217;ve sold more than I thought I would, and although I&#8217;d love to sell
more, I&#8217;m really happy with how it&#8217;s done.</p>

<h3>Performing</h3>

<p>As of this post, I&#8217;ve sold around 3,000 copies from the Pragmatic Programmers online store<sup id='fnref:2'><a href='#fn:2' rel='footnote'>2</a></sup>.  I don&#8217;t yet know how many I&#8217;ve sold from other channels such as Amazon or Barnes &amp; Noble &#8211; hopefully a lot &#8211; but sales from the Prags&#8217; store alone feels like more than I was expecting.</p>

<p>Of course, I don&#8217;t make as much per book as Jesse does<sup id='fnref:3'><a href='#fn:3' rel='footnote'>3</a></sup>; that team I mentioned doesn&#8217;t come free.  But, being featured on the Pragmatic Programmers&#8217; website is unbeatable promotion.  This certainly drove a lot of sales.  It&#8217;s my hope that sales are higher than they would&#8217;ve been had the Prags published a version of the book I had originally written, but there&#8217;s no way to know for sure.</p>

<p>Now, I don&#8217;t mean to imply Jesse&#8217;s book is poorly written; it&#8217;s not at all.  Would it be better if it were edited professionally?
I suppose that depends on what you mean?  Would it be better <em>written</em>?  Certainly; most writing improves with editing and revising.
Would it have sold more?  Would it have sold enough to cover the costs and time of editing?  Again, there&#8217;s no way to know.</p>

<p>So where does this leave us?  I know that working with John and the Prags has made me a better writer, but would I be confident enough to &#8220;go it alone&#8221;?   Given my lack of notability, I feel I benefit greatly from having my work published and distributed by the Prags.  Further, knowing my writing style and abilities as I do, my work will be much higher quality with a team of professionals in my corner.</p>

<p>That being said, I&#8217;d still love to try self-publishing at some point, but I&#8217;d really love to read a book by Jesse developed with the Pragmatic Programmers.</p>

<hr />

<div class="footnotes">
    <ol>
        <li id='fn:1'>In addition to John, Dave, and Andy, the Prags employ copy editors, sysadmins, indexers, and probably many others that I don&#8217;t even know about that turn my XML and code into a beautiful book to read on paper as well as every reading device there is. <a href='#fnref:1' rev='footnote'>↩</a></li><li id='fn:2'>The breakdown is about 10% paper/90% electronic, which seems about right. <a href='#fnref:2' rev='footnote'>↩</a></li><li id='fn:3'>It&#8217;s worth pointing out that the Prag&#8217;s contract is <strong>very</strong> generous compared to most other publishers. <a href='#fnref:3' rev='footnote'>↩</a></li>
    </ol>
</div>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Methadone 1.0 with Awesome Tutorial]]></title>
    <link href="http://www.naildrivin5.com/blog/2012/04/11/methadone-1-dot-0-with-awesome-tutorial.html"/>
    <updated>2012-04-11T10:39:00-04:00</updated>
    <id>http://www.naildrivin5.com/blog/2012/04/11/methadone-1-dot-0-with-awesome-tutorial</id>
    <content type="html"><![CDATA[<p><a href="http://www.github.com/davetron5000/methadone">Methadone</a> is the ultimate command-line library for Ruby apps.  All the power of <code>OptionParser</code>, none of the verbosity, with a smattering of tools to help you write amazing apps right from the get-go.  In seconds, you have a fully functioning skeleton of an app, with integration and unit test coverage, documentation, and in-line help.  I created most of it while writing [my book][clibook], and have been feverishly polishing it since the book came out.</p>

<p>Today is its first official release at 1.0.  Woot!</p>

<p><img class="right" src="http://www.naildrivin5.com/images/methadone_tutorial.jpg" title="'Cover for the Methadone Tutorial iBook'" ></p>

<p>I&#8217;ve also released a tutorial as an &#8220;enhanced&#8221; iBook, <a href="http://itunes.apple.com/us/book/kick-bash-habit-ruby-methadone/id515825242?ls=1">available now</a> from the iBookstore as a free download.  This isn&#8217;t just a big ream of code and text, but a step-by-step walkthrough, with screencasts, on how to use Methadone, along with some detailed discussion on some of Methadone&#8217;s more useful features.  It&#8217;s all presented beautifully as a &#8220;textbook&#8221;-style iBook that looks great on an iPad 1 and stunning on the new iPad, thanks to iBooks Author and the retina display.</p>

<p>Read the tutorial, <a href="http://rdoc.info/github/davetron5000/methadone/master/frames">read the RDoc</a>, install the library, and feel free to <a href="http://www.github.com/davetron5000/methadone/issues">submit patches</a>.</p>

<hr />
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[I heartily endorse Ruby off Rails]]></title>
    <link href="http://www.naildrivin5.com/blog/2012/04/05/i-heartily-endorse-ruby-off-rails.html"/>
    <updated>2012-04-05T12:35:00-04:00</updated>
    <id>http://www.naildrivin5.com/blog/2012/04/05/i-heartily-endorse-ruby-off-rails</id>
    <content type="html"><![CDATA[<p><a href="http://jessewolgamott.com/">Jesse Wolgamott</a> has launched a training course called <a href="https://rubyoffrails.com/">Ruby Off Rails</a>, which is geared toward helping existing programmers learn Ruby first, and <em>not</em> Rails.</p>

<p>I heartily endorse this and highly recommend this approach if you want to &#8220;get into Rails&#8221;.</p>

<!-- more -->


<p>When I first heard about Rails, I bought a copy of <a href="http://pragprog.com/book/rails4/agile-web-development-with-rails">Agile Web Development with Rails</a> and was instantly confused as to what I was looking at.  What were all those <code>@</code> signs for?  Why are there pipes after the <code>do</code> keyword?  Where were all these methods coming from?</p>

<p>The answer was: Learn you a Ruby.</p>

<p>I am not the type programmer to just copy/paste code I don&#8217;t understand.  I don&#8217;t like &#8220;magic<sup id='fnref:1'><a href='#fn:1' rel='footnote'>1</a></sup>&#8221;.  I want to know, or at least have an inkling of, how the tools I&#8217;m using work.  And there&#8217;s no hope in understanding Rails without understanding Ruby.</p>

<p>I sold the book, and, using a Ruby book available on <a href="http://www.safaribooksonline.com/">Safari</a>, started to learn Ruby the language.  I ignored Rails, and didn&#8217;t even think about it.  Instead, all of the <a href="http://www.awesomecommandlineapps.com">command line apps</a> that I would historically write in Perl, I wrote in Ruby.  I wrote a <em>lot</em> of Perl in Ruby at first<sup id='fnref:2'><a href='#fn:2' rel='footnote'>2</a></sup>.</p>

<p>Eventually, I figured out how the language worked and, when it came time to do some serious Rails programming, I wasn&#8217;t surprised by much.  I mostly just had to learn to navigate the documentation.  Even when I didn&#8217;t know how something worked, I could usually have a guess, and I was usually right.  When I wasn&#8217;t, I learned something new about Ruby.</p>

<p>It probably wouldn&#8217;t have taken so long if I&#8217;d taken a more focused approach like what Ruby Off Rails is doing (and, LivingSocial&#8217;s <a href="http://hungryacademy.com/">Hungry Academy</a> as well, which starts with just Ruby before moving to Rails).</p>

<p>If you&#8217;re tired of slinging Java/C#/PHP, but can&#8217;t seem to get focused to learn Rails or Ruby, Ruby Off Rails seems like a good way to go.  It&#8217;s not very expensive, and it&#8217;s geared around writing code, not learning API documentation.</p>

<hr />

<div class="footnotes">
    <ol>
        <li id='fn:1'>I consider <em>magic</em> in programming to be something that <strong>you</strong> don&#8217;t understand.  Everything is knowable <a href='#fnref:1' rev='footnote'>↩</a></li><li id='fn:2'>I think the <strong>main</strong> reason I came to Ruby instead of Python was because Ruby had the <code>=~</code> operator and Python didn&#8217;t, and that irritated me, because it&#8217;s so awersomely helfpul <a href='#fnref:2' rev='footnote'>↩</a></li>
    </ol>
</div>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A Protocol for Code Reviews]]></title>
    <link href="http://www.naildrivin5.com/blog/2012/04/02/a-protocol-for-code-reviews.html"/>
    <updated>2012-04-02T20:30:00-04:00</updated>
    <id>http://www.naildrivin5.com/blog/2012/04/02/a-protocol-for-code-reviews</id>
    <content type="html"><![CDATA[<blockquote><p>Anyone have a (formal / step-by-step) protocol for code reviews?</p><footer><strong>Jeff Casimir, The Twitters,</strong> <cite><a href='https://twitter.com/j3/status/186961864234770433'>twitter.com/j3/status/&hellip;</a></cite></footer></blockquote>


<p>Yes, I do.  At <a href="http://www.heyitsopower.com">Opower</a>, we were pretty serious about code reviews.  We didn&#8217;t review every commit, but we did review a lot, and, after a while, fell into a pretty decent routine.  This is an adaptation of that that I think is pretty decent.</p>

<!-- more -->


<h2>Prepare</h2>

<p>The code authors should send out the diff, either as a pull request, or whatever the equivalent is in the tool of choice.  This should include:</p>

<ul>
<li>What the purpose of the change is</li>
<li>Links to any supporting tickets, documentation, etc.</li>
<li>A Place To Start</li>
</ul>


<p>With all that, the reviewers should get an email, inviting them to review the code.  This is important, because you need to identify the people whose feedback you want.  Don&#8217;t just email <code>people_who_installed_ruby@theuniverse.com</code>; email people who either <em>should</em> see your change, or whose feedback you want.</p>

<h3>A Place to Start?</h3>

<p>Depending on the complexity of the change, this could be the name of the class/method where one should start reading, or a full-blown design document explaining the approach and structure of the change.  The point is that the reviewers have <em>no clue</em> how your code works, and need somewhere to get going.</p>

<h2>Asynchronous Review</h2>

<p>This is &#8220;review by online tool&#8221;, e.g. Github Pull Requests.  To make this work, you <em>must</em> have a tool that allows per-line commenting and discussion.  The reviewers will start at the Place to Start, review the code, and comment on things.  Reviewers should comment on anything they see fit, and they should follow <a href="http://twitter.com/#!/wilw/statuses/5966220832">Wheaton&#8217;s Rule</a>: Don&#8217;t be a dick.  The review<strong>ee</strong> promises not to take anything personally.  This can be hard to do, especially if you are new to the team, or inexperienced.  I&#8217;d recommend that for first-time employees, skip this and go to the <em>Synchronous Review</em> as it can be less intimidating.</p>

<h3>Responding to comments</h3>

<p>The reviewee should absolutely respond to comments.  I would expect comments to be one of these three responses:</p>

<ul>
<li>You are right, I will change that.</li>
<li>You are wrong, because of <em>some explanation</em>, and perhaps I&#8217;ll drop some comments or better-name my variables before I push this to make it clear.</li>
<li>I&#8217;m confused, can you elaborate?</li>
</ul>


<h3>Uploading changes</h3>

<p>As important as it is that your review tool allow per-line comments, it&#8217;s equally important that your review tool allow new changes to be added to the review <em>without blowing away the comments</em>.  Reviewers should be able to tell that you&#8217;ve made changes based on their feedback and see if it makes sense</p>

<h3>Stylistic Comments</h3>

<p>Early reviews at Opower wasted an inordinate amount of time on stylistic things.  We eventually adopted a house style and our reviews moved on to important things.  You are not a special butterfly and you are not a snowflake who can only express him or herself through your clever variable names and indenting style.  Follow the house style, or at least the style of the code you are in so you can <em>get better feedback on your code</em> instead of arguing about where commas should go.</p>

<h2>Synchronous Review</h2>

<p>If there are too many &#8220;I&#8217;m confused&#8221; comments, or the overall design/approach of the solution seems undesirable, it can greatly help if you hold a meeting with the interested parties to talk out the issues in the review, rather than creating an endless stream of comments in the review tool.</p>

<p>This review should be attended <em>only</em> by those with an interest in the outcome.  It should be timeboxed to hopefully 30 minutes, but not more than an hour, and the end result should be a &#8220;todo&#8221; list for the reviewee to correct the issues.  The ability to project the code on the screen is a plus, and the code authors best know how to navigate their codebase.  Senior developers have a responsibility to school them on this during the review.  It&#8217;s the only way you&#8217;ll learn. The issues would be of the form:</p>

<ul>
<li>Code author didn&#8217;t understand the problem, and a larger rework is indicated</li>
<li>Reviewers didn&#8217;t understand the solution, and, after explaining, the author either reworks the code to be more understandable, or provides documentation to clear things up</li>
</ul>


<h2>Completion</h2>

<p>When the code is done to the satisfaction of those involved, the final commit should contain a link to the review in the review tool. This is crucial for future archaeologists  that might want to know what&#8217;s going on; seeing the discussion can be helpful.</p>

<h2>Doing this with Github</h2>

<p>Github&#8217;s pull requests are less than ideal for this, depending on how you work.  Primarily, a reviewer wants to see the diff between the current system and how the system would look with the new code applied.  Last I checked, this view in Github doesn&#8217;t allow per-line commenting, making it almost useless.</p>

<p>What I&#8217;d recommend is to squash the commit onto a branch specifically for the review (e.g. <code>reviews/TICKETNUM-DESCRIPTION</code>).  When the code author needs to add changes in response to the review, just add those diffs to the branch.  When everything is done, squash all <em>that</em>, and merge it.  One diff, one thing to deal with and understand.</p>

<p>If you really want the sausage-making to be part of mainline history, then merge your changes plus one additional change representing all changes you made based on the review, with the message being a link to the review branch in Github.</p>

<h2>Doing this with Crucible</h2>

<p><a href="http://www.atlassian.com/software/crucible/overview">Crucible</a> was tailor-made for this, and all you need to do is choose changesets and have at it.  You can add diffs as needed, and the commenting system is rich.  Crucible is not as polished and slick as Github, but it works great.</p>

<h2>Conclusion</h2>

<p>This may sound like a lot, but it&#8217;s <em>really</em> lightweight, once you start doing it, and it&#8217;s way better than zillions of emails or
long, horrible meetings.  Just try it.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[The Nine Facets of an Awesome Command-Line App]]></title>
    <link href="http://www.naildrivin5.com/blog/2012/04/01/the-nine-facets-of-an-awesome-command-line-app.html"/>
    <updated>2012-04-01T11:51:00-04:00</updated>
    <id>http://www.naildrivin5.com/blog/2012/04/01/the-nine-facets-of-an-awesome-command-line-app</id>
    <content type="html"><![CDATA[<p>When creating the outline for <a href="http://bit.ly/cli-hl-blog-post">my book</a> (now officially published and in print!), I decided to organize it around the
nine facets of an awesome command-line app.  <a href="http://www.awesomecommandlineapps.com">Each chapter</a> focuses on one of these facets.  They state that an awesome
command-line app should:</p>

<ul>
<li>have a clear and concise purpose</li>
<li>be easy to use</li>
<li>be helpful</li>
<li>play well with others</li>
<li>delight casual users</li>
<li>make configuration easy for advanced users</li>
<li>install and distribute painlessly</li>
<li>be well-tested and as bug free as possible</li>
<li>be easy to maintain</li>
</ul>


<p>In this post, I&#8217;ll illustrate each of these facets (along with a test of the tenth chapter on color and formatting), via a code
walkthrough of a simple command-line app I created for work.</p>

<!-- more -->


<p>LivingSocial (where I <a href="http://www.livingsocial.com">work</a>) processes thousands of credit card transactions per day, across a highly distributed, asynchronous system.  When things go wrong, the log files are the first place I look to find answers.  This means that <code>grep</code> is my go-to tool for analysis.  Even though <code>grep</code> can highlight search terms in output, with long and complex log lines, it can be hard to pick out just what I&#8217;m looking for.  I needed a tool to just highlight text, but not actually &#8220;grep out&#8221; non-matching lines.</p>

<h2>To the command-line!</h2>

<p>So, in just a few short hours, <a href="https://github.com/davetron5000/hl">hl</a> was born.  I wrote it using TDD, and, even though it&#8217;s barely 100 lines of code, it hits all the notes of an awesome command-line app (if I do say so myself :).  Let&#8217;s go through all nine of our &#8220;facets of an awesome command-line app&#8221; and see what the fuss is about.</p>

<h2>Have a Clear &amp; Concise Purpose</h2>

<p>The best way to have a clear &amp; concise purpose is to do one thing, and one thing only.  <code>hl</code> highlights search terms in any output to assist with visual scanning of output.  It doesn&#8217;t highlight multiple terms, and it doesn&#8217;t remove non-matching lines.  It just highlights terms.  One thing, and one thing only.</p>

<h2>Be Easy to Use</h2>

<p>This is a <em>big</em> topic, but here&#8217;s an example of using <code>hl</code>:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ grep 987876736 my_logs.log | hl credit_card_token</span></code></pre></td></tr></table></div></figure>


<p><code>hl</code> does what it&#8217;s asked, by default, without a lot of fuss, just like any other UNIX command.  It has options, but you never
need to worry about them in most cases.  Of course, if you <em>are</em> curious about those options, that leads to our next facet.</p>

<h2>Be Helpful</h2>

<p><code>hl</code> is based on <a href="https://github.com/davetron5000/methadone">methadone</a>, which is a proxy to <a href="http://ruby-doc.org/stdlib-1.9.3/libdoc/optparse/rdoc/OptionParser.html">OptionParser</a>, which is <em>the</em> tool to use for parsing the command-line in Ruby.  It&#8217;s very powerful, and generates a canonical, documented UI for your app:</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ bin/hl --help
</span><span class='line'>Usage: hl [options] [search_term] [filename]
</span><span class='line'>
</span><span class='line'>Highlight terms in output without grepping out lines
</span><span class='line'>
</span><span class='line'>v1.0.0
</span><span class='line'>
</span><span class='line'>Options:
</span><span class='line'>    -c, --color COLOR                Color to use for highlighting
</span><span class='line'>                                     (red|green|yellow|blue|magenta|cyan|white)
</span><span class='line'>                                     (default: yellow)
</span><span class='line'>    -b, --[no-]bright                Use bright colors
</span><span class='line'>    -n, --[no-]inverse               Inverse highlight
</span><span class='line'>    -u, --[no-]underline             Underline highlight
</span><span class='line'>    -p, --regexp PATTERN             Search term as explicit option
</span><span class='line'>    -i, --[no-]ignore-case           Ignore case in match
</span><span class='line'>        --version                    Show help/version info
</span><span class='line'>
</span><span class='line'>Default values can be placed in the HL_OPTS environment variable</span></code></pre></td></tr></table></div></figure>


<p>Note how much <code>OptionParser</code> gives us:</p>

<ul>
<li>Ability to describe our app, its version, and basic invocation syntax</li>
<li>Nicely formatted list of options and descriptions</li>
<li>Ability to accept &#8220;negatable&#8221; options (we&#8217;ll talk about that in a second)</li>
</ul>


<p>Further, I&#8217;ve gone to the trouble to make sure that <code>--color</code> clearly indicates the acceptable values as well as the default.  Finally, I&#8217;ve made sure that all options are available in short-form (for easy typing on the command line) and long-form (for clarity when scripting and configuring our app).</p>

<p>Here&#8217;s the code that makes this happen (if you aren&#8217;t familiar with methadone, the method <code>on</code> behaves almost exactly like the <code>on</code> method in <code>OptionParser</code>):</p>

<figure class='code'><figcaption><span>bin/hl</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1">#!/usr/bin/env ruby</span>
</span><span class='line'>
</span><span class='line'><span class="nb">require</span> <span class="s1">&#39;optparse&#39;</span>
</span><span class='line'><span class="nb">require</span> <span class="s1">&#39;methadone&#39;</span>
</span><span class='line'><span class="nb">require</span> <span class="s1">&#39;hl&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">App</span>
</span><span class='line'>  <span class="kp">include</span> <span class="no">Methadone</span><span class="o">::</span><span class="no">Main</span>
</span><span class='line'>  <span class="kp">include</span> <span class="no">Methadone</span><span class="o">::</span><span class="no">CLILogging</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">main</span> <span class="k">do</span> <span class="o">|</span><span class="n">keyword</span><span class="p">,</span><span class="o">*</span><span class="n">filenames</span><span class="o">|</span>
</span><span class='line'>    <span class="c1"># main logic here</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">description</span> <span class="s2">&quot;Highlight terms in output without grepping out lines&quot;</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">options</span><span class="o">[</span><span class="ss">:color</span><span class="o">]</span> <span class="o">=</span> <span class="s1">&#39;yellow&#39;</span>
</span><span class='line'>  <span class="n">colors</span> <span class="o">=</span> <span class="o">[</span><span class="s1">&#39;red&#39;</span><span class="p">,</span> <span class="s1">&#39;green&#39;</span><span class="p">,</span> <span class="s1">&#39;yellow&#39;</span><span class="p">,</span> <span class="s1">&#39;blue&#39;</span><span class="p">,</span> <span class="s1">&#39;magenta&#39;</span><span class="p">,</span> <span class="s1">&#39;cyan&#39;</span><span class="p">,</span> <span class="s1">&#39;white&#39;</span><span class="o">]</span>
</span><span class='line'>  <span class="n">on</span><span class="p">(</span><span class="s2">&quot;-c COLOR&quot;</span><span class="p">,</span>       <span class="s2">&quot;--color&quot;</span><span class="p">,</span><span class="s2">&quot;Color to use for highlighting&quot;</span><span class="p">,</span><span class="n">colors</span><span class="p">,</span><span class="s2">&quot;(</span><span class="si">#{</span><span class="n">colors</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s1">&#39;|&#39;</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span>
</span><span class='line'>  <span class="n">on</span><span class="p">(</span><span class="s2">&quot;--[no-]bright&quot;</span><span class="p">,</span>     <span class="s2">&quot;-b&quot;</span><span class="p">,</span>  <span class="s2">&quot;Use bright colors&quot;</span><span class="p">)</span>
</span><span class='line'>  <span class="n">on</span><span class="p">(</span><span class="s2">&quot;--[no-]inverse&quot;</span><span class="p">,</span>    <span class="s2">&quot;-n&quot;</span><span class="p">,</span>  <span class="s2">&quot;Inverse highlight&quot;</span><span class="p">)</span>
</span><span class='line'>  <span class="n">on</span><span class="p">(</span><span class="s2">&quot;--[no-]underline&quot;</span><span class="p">,</span>  <span class="s2">&quot;-u&quot;</span><span class="p">,</span>  <span class="s2">&quot;Underline highlight&quot;</span><span class="p">)</span>
</span><span class='line'>  <span class="n">on</span><span class="p">(</span><span class="s2">&quot;--regexp PATTERN&quot;</span><span class="p">,</span>  <span class="s2">&quot;-p&quot;</span><span class="p">,</span>  <span class="s2">&quot;Search term as explicit option&quot;</span><span class="p">)</span>
</span><span class='line'>  <span class="n">on</span><span class="p">(</span><span class="s2">&quot;--[no-]ignore-case&quot;</span><span class="p">,</span><span class="s2">&quot;-i&quot;</span><span class="p">,</span>  <span class="s2">&quot;Ignore case in match&quot;</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">arg</span> <span class="ss">:search_term</span><span class="p">,</span> <span class="ss">:optional</span>
</span><span class='line'>  <span class="n">arg</span> <span class="ss">:filename</span><span class="p">,</span> <span class="ss">:optional</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">version</span> <span class="no">Hl</span><span class="o">::</span><span class="no">VERSION</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">defaults_from_env_var</span> <span class="s1">&#39;HL_OPTS&#39;</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">go!</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Methods like <code>arg</code>, <code>version</code>, and <code>description</code> are helpers from methadone (see the <a href="http://www.naildrivin5.com/blog/2011/12/19/methadone-the-awesome-cli-library.html">intro</a> for more), but note how <em>little</em> code it takes just to make a great and polished UI.</p>

<p>The second part of a helpful app is to include more detailed documentation.  For a command-line app, this is expected to be in the form of a man page.  If you installed <code>hl</code> with RubyGems, try this:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='sh'><span class='line'><span class="nv">$ </span>gem man hl
</span></code></pre></td></tr></table></div></figure>


<p>You should see a nicely formatted man page (which also happens <a href="https://github.com/davetron5000/hl/blob/master/README.md">to be the <code>README</code></a> for the github project)!  Creating a man page is extremely simple thanks to <a href="https://github.com/rtomayko/ronn">ronn</a>.  <code>ronn</code> converts Markdown to troff, the format used by the man system.  Just add this to your Rakefile:</p>

<figure class='code'><figcaption><span>Rakefile Snippet</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s1">&#39;methadone&#39;</span>
</span><span class='line'><span class="nb">require</span> <span class="s1">&#39;fileutils&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="kp">include</span> <span class="no">Methadone</span><span class="o">::</span><span class="no">SH</span>
</span><span class='line'><span class="kp">include</span> <span class="no">FileUtils</span>
</span><span class='line'>
</span><span class='line'><span class="n">task</span> <span class="ss">:man</span> <span class="k">do</span>
</span><span class='line'>  <span class="n">sh</span> <span class="s1">&#39;ronn --markdown --roff man/hl.1.ronn&#39;</span>
</span><span class='line'>  <span class="n">mv</span> <span class="s1">&#39;man/hl.1.markdown&#39;</span><span class="p">,</span><span class="s1">&#39;README.md&#39;</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>And, your gemspec just needs:</p>

<figure class='code'><figcaption><span>Gemspec</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'>  <span class="n">s</span><span class="o">.</span><span class="n">add_development_dependency</span><span class="p">(</span><span class="s1">&#39;ronn&#39;</span><span class="p">)</span>
</span><span class='line'>  <span class="n">s</span><span class="o">.</span><span class="n">add_dependency</span><span class="p">(</span><span class="s1">&#39;gem-man&#39;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>You&#8217;ll also need to include the generated file <code>man/hl.1</code> in your <code>files</code> in your gemspec, but if you&#8217;re using the gemspec created by Bundler, this happens automatically as long as the file is in source control.</p>

<p>That&#8217;s <em>it</em>.   Now your app has a great UI <em>and</em> a man page, and all you had to do was drop a few lines of code and write a short Markdown file (which you&#8217;d write anyway, since you <em>are</em> making a README, right?).</p>

<p>In addition to being helpful to humans, awesome command-line apps should be helpful to other commands.</p>

<h2>Play well with others</h2>

<p>An app that &#8220;plays well with others&#8221; on the command line, basically means that it acts as a <em>filter</em>. Text comes in, gets processed, the processed text goes out.  The expectation is that text from any other &#8220;well playing&#8221; program can be input into our program, and that our program&#8217;s output can be piped into another program as input.</p>

<p>Since the purpose of our app is to add ANSI escape codes to the output for assistance with <em>human</em> visual scanning, we can&#8217;t claim that our <em>output</em> plays well with others; it&#8217;s not designed to.  But, we can still play well with the output from <em>other</em> apps.</p>

<p>We saw that <code>hl</code> was designed to take input from a tool like <code>grep</code>.  <code>hl</code> can also highlight terms from any number of files given to it on the command line.  You can do this transparently in Ruby using the awesome <a href="http://ruby-doc.org/core-1.9.3/ARGF.html">ARGF</a>, however Methadone doesn&#8217;t support ARGF (a sad fact I learned while writing this app, and something <a href="https://github.com/davetron5000/methadone/issues/34">I&#8217;ll address</a> in the near future), so here&#8217;s how did it (a few comments added to indicate what&#8217;s going on):</p>

<figure class='code'><figcaption><span>Treating STDIN and a file list as the same source of data</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># filenames is a possibly empty list of strings</span>
</span><span class='line'><span class="n">files</span> <span class="o">=</span> <span class="k">if</span> <span class="n">filenames</span><span class="o">.</span><span class="n">empty?</span>
</span><span class='line'>          <span class="o">[</span><span class="no">STDIN</span><span class="o">]</span>
</span><span class='line'>        <span class="k">else</span>
</span><span class='line'>          <span class="n">filenames</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">_</span><span class="o">|</span> <span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="n">_</span><span class="p">)</span> <span class="p">}</span>
</span><span class='line'>        <span class="k">end</span>
</span><span class='line'><span class="c1"># files is now an Array of open IO objects</span>
</span><span class='line'><span class="k">begin</span>
</span><span class='line'>  <span class="c1"># highlighting code</span>
</span><span class='line'><span class="k">ensure</span>
</span><span class='line'>  <span class="c1"># we close the files since we didn&#39;t open them in &quot;block&quot; form; closing STDIN is OK to do</span>
</span><span class='line'>  <span class="c1"># since we know our app will soon exit</span>
</span><span class='line'>  <span class="n">files</span> <span class="o">&amp;&amp;</span> <span class="n">files</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="ss">:close</span><span class="p">)</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Again, ARGF handles this transparently, but the point is, we want the standard input and a provided list of files to be treated the same by our program, and this is how I did it.</p>

<p>Since our app is similar in concept to grep, I thought it would be nice if users familiar with grep could be instantly familiar
with <code>hl</code>.</p>

<h2>Delight Casual Users</h2>

<p>This is a &#8220;level up&#8221; from &#8220;being easy to use&#8221;.  The idea behind the term &#8220;delight&#8221; is to provide a level of polish and attention to detail that your users will appreciate if they&#8217;re observant, but hopefully not even notice, because your app &#8220;just works&#8221;.</p>

<p>Since <code>hl</code>, like <code>grep</code>, is used for filtering and examining text files,  I chose my command-line options to match <code>grep</code>&#8217;s where i could.  Initially, I had the short-form of <code>--inverse</code> as <code>-i</code>.  When I later added the ability to do a case-insensitive match, I realized that <code>-i</code> is the option to <code>grep</code> for &#8220;case-insensitive&#8221;.  I quickly changed <code>--inverse</code> to have <code>-n</code> as its short-form, and made <code>-i</code> and <code>--ignore-case</code> the options for case-insensitivity.  These are the same values that <code>grep</code> uses, so a user who might subconciously type <code>hl -i</code> expecting a case-insensitive match will get it.</p>

<p>Further, I allowed the user to specify the search term either as a command-line argument, or as the argument to <code>-p</code> or <code>--regexp</code>, which are the option names <code>grep</code> uses.  It&#8217;s a basic principle of design that things that are the same should be <em>exactly</em> the same, so I used <code>grep</code> as my guide when <code>hl</code> implemented similar features.</p>

<p>Of course, power users love to customize things.</p>

<h2>Make Configuration Easy</h2>

<p>In the book, I talk about using YAML as a configuration format for an <code>.rc</code> file.  This can be very useful for complex apps, but another technique that&#8217;s handy is to allow an environment variable to hold default options.  <code>grep</code> does this via <code>GREP_OPTS</code> and if you were paying attenion, you noticed this line in <code>bin/hl</code>:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'>  <span class="n">defaults_from_env_var</span> <span class="s1">&#39;HL_OPTS&#39;</span>
</span></code></pre></td></tr></table></div></figure>


<p>This tells methadone to look at the environment variable <code>HL_OPTS</code> (as well as the command line) for any options.  These options are placed first in <code>ARGV</code>, essentially like so:</p>

<figure class='code'><figcaption><span>Putting command-line options from the environment into ARGV</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">String</span><span class="p">(</span><span class="no">ENV</span><span class="o">[</span><span class="vi">@env_var</span><span class="o">]</span><span class="p">)</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="sr">/\s+/</span><span class="p">)</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">arg</span><span class="o">|</span>
</span><span class='line'>  <span class="o">::</span><span class="no">ARGV</span><span class="o">.</span><span class="n">unshift</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>(Note the use of <code>String</code> to make sure that <code>nil</code> gets turned into the empty string, saving us an <code>if</code> statement).  Methadone does this before parsing <code>ARGV</code>.  Using <code>unshift</code> means that any options the <em>user</em> specifies will come <em>after</em> those in <code>HL_OPTS</code> and therefore take precendence:</p>

<pre><code>$ export HL_OPTS=--color=cyan
$ grep foo some_log.txt | hl --color=magenta
</code></pre>

<p>This is the same as</p>

<pre><code>$ grep foo some_log.txt | hl --color-cyan --color=magenta
</code></pre>

<p>This is also why I&#8217;ve provided the &#8220;negatable&#8221; forms.  Suppose you generally wanted inverse:</p>

<pre><code>$ export HL_OPTS=--inverse
</code></pre>

<p>If you wanted to run <code>hl</code> <em>without</em> inverse, but there was no negatable option, the only way to turn it off would be to unset the environment variable.  With the negatable forms, it&#8217;s simple:</p>

<pre><code>$ grep foo some_log.txt | hl --no-inverse
</code></pre>

<p>Since the user&#8217;s command-line options take precedence, things work out, but you can still configure your defaults.</p>

<p>Finally, I&#8217;d recommend that you use the long-form options in your configuration.  In other words, if you prefer bright and inverted highlights, do this:</p>

<pre><code>$ export HL_OPTS='--inverse --bright'
</code></pre>

<p>As opposed to</p>

<pre><code>$ export HL_OPTS=-nb
</code></pre>

<p>The second form is more compact, but your configuration is going to be <em>read</em> more than written, and, 6 months from now when you are going through your <code>.bashrc</code>, you&#8217;re going to appreciate seeing things spelled out; you&#8217;ll know instantly what the configuration does and don&#8217;t have to wonder about what <code>-n</code> means.</p>

<h2>Distribute Painlessly</h2>

<p>RubyGems:</p>

<pre><code>$ gem install hl
$ hl --help
</code></pre>

<p>That is all.</p>

<h2>Be well-tested</h2>

<p>I wrote <code>hl</code> entirely using <a href="http://en.wikipedia.org/wiki/Test-driven_development">TDD</a> and entirely using <a href="https://github.com/cucumber/aruba">aruba</a>.  Here&#8217;s a sampling:</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='cucumber'><span class='line'><span class="nf">  </span><span class="k">Scenario:</span><span class="nf"> Highlights with case insensitivity</span>
</span><span class='line'><span class="k">    Given </span><span class="nf">a file named &quot;</span><span class="s">test_file</span><span class="nf">&quot; with the word &quot;</span><span class="s">FOO bar foo</span><span class="nf">&quot; in it</span>
</span><span class='line'><span class="nf">    </span><span class="k">When </span><span class="nf">I successfully run `hl -i foo ../../test_file`</span>
</span><span class='line'><span class="nf">    </span><span class="k">Then </span><span class="nf">the entire contents of &quot;</span><span class="s">test_file</span><span class="nf">&quot; should be output</span>
</span><span class='line'><span class="nf">    </span><span class="k">But </span><span class="nf">the word &quot;</span><span class="s">foo</span><span class="nf">&quot; should be highlighted in yellow</span>
</span><span class='line'><span class="nf">    </span><span class="k">And </span><span class="nf">the word &quot;</span><span class="s">FOO</span><span class="nf">&quot; should be highlighted in yellow</span>
</span></code></pre></td></tr></table></div></figure>


<p>It was very easy to do this, although aruba could use a man page for easier reference.  I had to jump into its source too many times to get reminded of the syntax of the steps it provides.  Aruba also strips out ANSI escape sequences, which made testing <code>hl</code> a bit tricky.  There appears to be an option to <em>prevent</em> this, but I couldn&#8217;t get it to work, so I just used Aruba&#8217;s internal API:</p>

<figure class='code'><figcaption><span>asserting highlighted output</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Then</span><span class="sr"> /^the word &quot;([^&quot;]*)&quot; should be highlighted in (.*$)$/</span> <span class="k">do</span> <span class="o">|</span><span class="n">keyword</span><span class="p">,</span><span class="n">color</span><span class="o">|</span>
</span><span class='line'>  <span class="c1"># #color is provided by rainbow, which we&#39;ll talk about in a bit</span>
</span><span class='line'>  <span class="n">expected</span> <span class="o">=</span> <span class="n">keyword</span><span class="o">.</span><span class="n">color</span><span class="p">(</span><span class="n">color</span><span class="o">.</span><span class="n">to_sym</span><span class="p">)</span>
</span><span class='line'>  <span class="c1"># assert_partial_output and all_stdout are provided by aruba</span>
</span><span class='line'>  <span class="n">assert_partial_output</span><span class="p">(</span><span class="n">expected</span><span class="p">,</span><span class="n">all_stdout</span><span class="p">)</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>I still recommend aruba and cucumber, as it forces you to think about how users will use your app first, not how to implement it.  In fact, my initial implementation was a big hacky mess of stuff inside the <code>main</code> block.  Once the tests were in place, I refactored it to be a lot cleaner.</p>

<h2>Be Easy to Maintain</h2>

<p>As I just mentioned, I was able to use my tests to refactor my code.  As such, the main block of <code>hl</code> is pretty simple:</p>

<figure class='code'><figcaption><span>main block in hl</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">main</span> <span class="k">do</span> <span class="o">|</span><span class="n">keyword</span><span class="p">,</span><span class="o">*</span><span class="n">filenames</span><span class="o">|</span>
</span><span class='line'>  <span class="k">if</span> <span class="n">options</span><span class="o">[</span><span class="ss">:regexp</span><span class="o">]</span>
</span><span class='line'>    <span class="nb">Array</span><span class="p">(</span><span class="n">filenames</span><span class="p">)</span><span class="o">.</span><span class="n">unshift</span><span class="p">(</span><span class="n">keyword</span><span class="p">)</span>
</span><span class='line'>    <span class="n">keyword</span> <span class="o">=</span> <span class="n">options</span><span class="o">[</span><span class="ss">:regexp</span><span class="o">]</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">exit_now!</span> <span class="s1">&#39;search term or --regexp/-p required&#39;</span> <span class="k">if</span> <span class="n">keyword</span><span class="o">.</span><span class="n">nil?</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">keyword</span> <span class="o">=</span> <span class="n">keyword</span><span class="o">.</span><span class="n">dup</span>
</span><span class='line'>  <span class="n">highlighter</span> <span class="o">=</span> <span class="no">Hl</span><span class="o">::</span><span class="no">Highlighter</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>  <span class="nb">puts</span> <span class="n">highlighter</span><span class="o">.</span><span class="n">highlight</span><span class="p">(</span><span class="n">filenames</span><span class="p">,</span><span class="n">keyword</span><span class="p">)</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>This is the sort of logic you want in your <code>main</code> block:</p>

<ul>
<li>Handling the keyword-from-argument and keyword-from-command-line-option case</li>
<li>Simple error checking</li>
<li>Duping the keyword (since it comes in frozen)</li>
<li>Calling our <code>Highlighter</code> class to do the real work</li>
</ul>


<p>We defer all non-UI logic to the <code>Highlighter</code> class.  I decided to make each instance of the class able to highlight any files repeatedly based on a configuration, so the constructor takes in the formatting options, and the method <code>highlight</code> takes the list of filenames and the search term.</p>

<p>The actual highlighting is made possible via lots of list comprehension:</p>

<figure class='code'><figcaption><span>Learn you some list comprehensions</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">files</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">_</span><span class="o">|</span> <span class="n">_</span><span class="o">.</span><span class="n">readlines</span><span class="p">}</span><span class="o">.</span><span class="n">flatten</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">_</span><span class="o">|</span> <span class="n">highlight_matches</span><span class="p">(</span><span class="n">regexp</span><span class="p">,</span><span class="n">_</span><span class="p">)</span> <span class="p">}</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>


<p>If you aren&#8217;t comfortable with this use of chained calls, it can be very powerful.  What this does is:</p>

<ul>
<li>Map each file to an array of its contents as lines.  <code>[foo,bar]</code> becomes <code>[ ['first line of foo\n','second line of foo\n'],['first line of bar\n'],['second line of bar\n']]</code></li>
<li>Flatten that array of arrays to just one list of all lines of all files.  Our example array becomes: <code>[ 'first line of foo\n','second line of foo\n','first line of bar\n','second line of bar\n']</code></li>
<li>map those lines to the lines with the search term highlighted.  Supposing we wanted to highlight the word &#8220;line&#8221;, our array becomes: <code>[ 'first \e[33mline\e[0m of foo\n','second \e[33mline\e[0m of foo\n','first \e[33mline\e[0m of bar\n','second \e[33mline\e[0m of bar\n']</code></li>
<li>join them all together into one big string
<code>"first \e[33mline\e[0m of foo\nsecond \e[33mline\e[0m of foo\nfirst \e[33mline\e[0m of bar\nsecond \e[33mline\e[0m of bar\n"</code></li>
</ul>


<p>Granted, this approach will probably have trouble with extremely large input, but <code>hl</code> was designed to work with the output of <code>grep</code>, so hopefully we won&#8217;t have too much (I&#8217;ve already decided I need it <a href="https://github.com/davetron5000/hl/issues/1">to work with <code>tail</code></a> ).</p>

<h2>Breaking the rules</h2>

<p>Color and formatting <em>are not</em> typically associated with awesome command-line apps; too much of it makes an app hard to use with other apps.  But, the whole purpose of <code>hl</code> is to colorize output, so for that, I used <a href="https://github.com/sickill/rainbow">rainbow</a>, which is a pretty
simple enhancement to <code>String</code> that allows coloring and formatting.  We can see it in action in the <code>highlight_string</code> method of <code>Highlighter</code>:</p>

<figure class='code'><figcaption><span>highlight_string</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">highlight_string</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
</span><span class='line'>  <span class="n">string</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="n">color</span><span class="p">(</span><span class="vi">@options</span><span class="o">[</span><span class="s1">&#39;color&#39;</span><span class="o">].</span><span class="n">to_sym</span><span class="p">)</span>
</span><span class='line'>  <span class="n">string</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="n">inverse</span> <span class="k">if</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:inverse</span><span class="o">]</span>
</span><span class='line'>  <span class="n">string</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="n">bright</span> <span class="k">if</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:bright</span><span class="o">]</span>
</span><span class='line'>  <span class="n">string</span> <span class="o">=</span> <span class="n">string</span><span class="o">.</span><span class="n">underline</span> <span class="k">if</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:underline</span><span class="o">]</span>
</span><span class='line'>  <span class="n">string</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Each method called on <code>string</code> is a method provided by Rainbow.  These methods return a new string with the appropriate ANSI escape codes added.</p>

<h2>In Conclusion</h2>

<p>Hopefully, you&#8217;ve seen that it&#8217;s really <em>not that hard</em> to make an awesome command-line app.  I was able to write <code>hl</code> in just a few hours, using TDD and the end result is a highly polished, well-documented, easily installable and maintainable piece of software that will be a part of my command-line arsenal for quite a while.  You can do this, too.  There&#8217;s a lot more detail and in-depth explanations <a href="http://bit.ly/cli-hl-blog-post">in my book</a>, which you should buy right now :)</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Slides from my Talk on JRuby and Threads]]></title>
    <link href="http://www.naildrivin5.com/blog/2012/03/23/slides-from-my-talk-on-jruby-and-threads.html"/>
    <updated>2012-03-23T11:49:00-04:00</updated>
    <id>http://www.naildrivin5.com/blog/2012/03/23/slides-from-my-talk-on-jruby-and-threads</id>
    <content type="html"><![CDATA[<script src="http://speakerdeck.com/embed/4f6cca6eaa99e4002200aea3.js"></script>


<p><a href="https://github.com/davetron5000/jruby-and-threads-talk">Here&#8217;s a link to download</a> from my talk on JRuby and Threads.</p>

<p>If you just want the &#8220;exercises&#8221;, here they are:</p>

<!-- more -->


<h2>Echo Server</h2>

<ul>
<li>Listen on a port</li>
<li>Respond to each request in a new Thread</li>
<li><strong>Extra Credit</strong>: Record stats on requests in a shared data structure</li>
</ul>


<h2>Connection Pool</h2>

<ul>
<li>Allow N clients to access X shared instances of, say, Redis (where N > X)</li>
<li>Clients &#8220;check out&#8221; a connection and get exclusive access</li>
<li>Clients &#8220;check in&#8221; when done</li>
<li>Instances get re-used</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Trailer for my Book]]></title>
    <link href="http://www.naildrivin5.com/blog/2012/03/19/trailer-for-my-book.html"/>
    <updated>2012-03-19T08:14:00-04:00</updated>
    <id>http://www.naildrivin5.com/blog/2012/03/19/trailer-for-my-book</id>
    <content type="html"><![CDATA[<p>The trailer for <a href="http://pragprog.com/titles/dccar">my book</a>, check it out:</p>

<iframe width="640" height="480" src="http://www.youtube.com/embed/cNkPSCCODdc" frameborder="0" allowfullscreen></iframe>


<p>It&#8217;s a nonsensical journey through the computer, ending on the command-line.  It&#8217;s got drama, special effects, and a stern
soundtrack :)</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Something fun I'm working on]]></title>
    <link href="http://www.naildrivin5.com/blog/2012/02/23/something-fun-im-working-on.html"/>
    <updated>2012-02-23T20:58:00-05:00</updated>
    <id>http://www.naildrivin5.com/blog/2012/02/23/something-fun-im-working-on</id>
    <content type="html"><![CDATA[<p><img class="center" src="http://distilleryimage9.instagram.com/ea3ca4185e8a11e180c9123138016265_7.jpg"></p>
]]></content>
  </entry>
  
</feed>

