<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Gray Soft / Tags / Configuration</title>
  <id>tag:graysoftinc.com,2014-03-20:/tags/Configuration</id>
  <updated>2014-04-11T14:49:50Z</updated>
  <link rel="self" href="http://graysoftinc.com/tags/Configuration/feed.xml"/>
  <link rel="alternate" href="http://graysoftinc.com/tags/Configuration"/>
  <author>
    <name>James Edward Gray II</name>
  </author>
  <entry>
    <title>The One Method Config</title>
    <link rel="alternate" href="http://graysoftinc.com/ruby-voodoo/the-one-method-config"/>
    <id>tag:graysoftinc.com,2008-06-25:/posts/53</id>
    <updated>2014-04-11T14:49:50Z</updated>
    <summary>Here's a simple bit of Ruby magic for trivial configuration code.</summary>
    <content type="html">&lt;p&gt;I've used this technique a couple of times now for dirt-simple configurations.  The idea is to provide a trivial way to read and write configuration values with just a single method.  Let me show you what I mean:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Configurable&lt;/span&gt;
  &lt;span class="kp"&gt;module_function&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;new_config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt;
      &lt;span class="vi"&gt;@config&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;merge!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Configurable&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt;                    &lt;span class="c1"&gt;# =&amp;gt; {}&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:b&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;                    &lt;span class="c1"&gt;# =&amp;gt; {:a=&amp;gt;1, :b=&amp;gt;2}&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:a&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;                &lt;span class="c1"&gt;# =&amp;gt; 1&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:a&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;                    &lt;span class="c1"&gt;# =&amp;gt; {:a=&amp;gt;-1, :b=&amp;gt;2, :c=&amp;gt;3}&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;                    &lt;span class="c1"&gt;# =&amp;gt; {}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There's no deep magic here, obviously.  The method has two function:  read and write for the configuration.  Read is handled with what I like refer to as Ruby's "caching operator" (&lt;code&gt;||=&lt;/code&gt;).  The first time that line is triggered, it will cache an empty &lt;code&gt;Hash&lt;/code&gt; in the variable.  Thereafter, the same call is just a cache hit to get the same &lt;code&gt;Hash&lt;/code&gt; back.&lt;/p&gt;

&lt;p&gt;We could stop there, of course.  Access to the &lt;code&gt;Hash&lt;/code&gt; allows us to use any methods we need on it.  However, one more nicety really pays off, in my opinion.  Give an optional argument and, when it's available, use it as a shortcut for one of the write methods.  In this case, I chose &lt;code&gt;merge!()&lt;/code&gt; just because it's a well rounded tool for adding and/or editing multiple &lt;code&gt;Hash&lt;/code&gt; entries at once.&lt;/p&gt;

&lt;p&gt;The examples show how this plays out.  Note that I mix both styles of the method calls with some standard &lt;code&gt;Hash&lt;/code&gt; tools (&lt;code&gt;[]&lt;/code&gt; and &lt;code&gt;clear()&lt;/code&gt;).  I feel like that gives a whole lot of cool interface with barely any effort.&lt;/p&gt;

&lt;p&gt;One more example, just to get your brain spinning in other directions:&lt;/p&gt;

&lt;div class="highlight highlight-ruby"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Sortable&lt;/span&gt;
  &lt;span class="kp"&gt;module_function&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sortable_fields&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty?&lt;/span&gt;
      &lt;span class="vi"&gt;@sortable_fields&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;sortable_fields&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Sortable&lt;/span&gt;

&lt;span class="n"&gt;sortable_fields&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; []&lt;/span&gt;

&lt;span class="n"&gt;sortable_fields&lt;/span&gt; &lt;span class="ss"&gt;:a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:c&lt;/span&gt;
&lt;span class="n"&gt;sortable_fields&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; [:a, :b, :c]&lt;/span&gt;

&lt;span class="n"&gt;sortable_fields&lt;/span&gt; &lt;span class="sx"&gt;%w[d e f]&lt;/span&gt;
&lt;span class="n"&gt;sortable_fields&lt;/span&gt;  &lt;span class="c1"&gt;# =&amp;gt; [:a, :b, :c, "d", "e", "f"]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This method wraps an &lt;code&gt;Array&lt;/code&gt; instead of a &lt;code&gt;Hash&lt;/code&gt;, as you can seen.  With that there's one other trick I sometimes like to throw in that should be called something like "slurp-&lt;code&gt;flatten()&lt;/code&gt;-splat."  By taking any number of arguments, calling &lt;code&gt;flatten()&lt;/code&gt; to avoid worrying about whether the caller used an &lt;code&gt;Array&lt;/code&gt; (say for the convenient syntax used in the examples), and splitting the fields back out, we again get a smooth interface out of minimal code.&lt;/p&gt;

&lt;p&gt;As I said earlier there's no deep magic here, but don't underestimate how nice the simple tricks can be in the right circumstances.  Of course, purists who strongly hold to the "a method should only do one thing" philosophy will need to comfort themselves to sleep by repeating, "It just manages configuration!"&lt;/p&gt;</content>
    <author>
      <name>James Edward Gray II</name>
    </author>
  </entry>
</feed>
