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

  <title><![CDATA[Programblings]]></title>
  <link href="http://www.programblings.com/atom.xml" rel="self"/>
  <link href="http://www.programblings.com/"/>
  <updated>2014-09-17T23:48:44-04:00</updated>
  <id>http://www.programblings.com/</id>
  <author>
    <name><![CDATA[Mathieu Martin]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[LogStash - You don't need to deploy it to use it]]></title>
    <link href="http://www.programblings.com/2014/09/17/logstash-you-dont-need-to-deploy-it-to-use-it/"/>
    <updated>2014-09-17T23:29:00-04:00</updated>
    <id>http://www.programblings.com/2014/09/17/logstash-you-dont-need-to-deploy-it-to-use-it</id>
    <content type="html"><![CDATA[<p>This article is the first out of two. It&#8217;s based on based on the
<a href="http://logstash.net/docs/latest/tutorials/getting-started-with-logstash">LogStash Getting Started Guide</a>.
You should probably read that instead, if you don&#8217;t yet know what LogStash is.
It&#8217;s a more thorough introduction.</p>

<p>My goal with this article is rather to get you set up as fast as possible with
a functioning local LogStash setup. The next post will provide a few pointers
on how to get started parsing logs with LogStash.</p>

<!-- more -->


<h2>Install LogStash and ElasticSearch</h2>

<p>Always make sure you install the exact version of ElasticSearch recommended for
for the version of LogStash you&#8217;re installing. This is because LogStash connects
to ElasticSearch as an ES node, with a direct Java interface. I usually find the
correct ElasticSearch version to use on the
<a href="http://logstash.net/docs/latest/tutorials/getting-started-with-logstash">getting started page</a>.</p>

<p>Install ElasticSearch first, then start it:</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>
</pre></td><td class='code'><pre><code class=''><span class='line'>mkdir ~/logs ; cd ~/logs
</span><span class='line'>curl -O https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.1.1.tar.gz
</span><span class='line'>tar zxvf elasticsearch-1.1.1.tar.gz
</span><span class='line'>cd elasticsearch-1.1.1/
</span><span class='line'>bin/plugin -i elasticsearch/marvel/latest
</span><span class='line'>
</span><span class='line'>bin/elasticsearch</span></code></pre></td></tr></table></div></figure>


<p>In another terminal, install LogStash:</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>
</pre></td><td class='code'><pre><code class=''><span class='line'>cd ~/logs
</span><span class='line'>
</span><span class='line'>curl -O https://download.elasticsearch.org/logstash/logstash/logstash-1.4.2.tar.gz
</span><span class='line'>tar zxvf logstash-1.4.2.tar.gz
</span><span class='line'>cd logstash-1.4.2</span></code></pre></td></tr></table></div></figure>


<p>Make sure you also have Netcat (nc) installed, to easily send files or stdin
to a TCP port.</p>

<p>It may not look like it yet, but you now have everything you need to dive into
your logs!</p>

<h2>Kick the tires</h2>

<p>ElasticSearch is already running. You can take a peek at the status of your
ElasticSearch &#8220;cluster&#8221;, with the Marvel plugin:
<a href="http://localhost:9200/_plugin/marvel/">localhost:9200/_plugin/marvel</a>.</p>

<p>You can poke around a bit, but you&#8217;ll soon notice that there&#8217;s not much there yet,
except for one small &#8220;marvel&#8230;&#8221; index, to store the Marvel UI configs.</p>

<p>Let&#8217;s start LogStash with as little fuss as possible:</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>
</pre></td><td class='code'><pre><code class=''><span class='line'>bin/logstash -e '
</span><span class='line'>input { tcp { port =&gt; 5555 } }
</span><span class='line'>output { elasticsearch { host =&gt; localhost } }
</span><span class='line'>'</span></code></pre></td></tr></table></div></figure>


<p>By which we mean: listen on TCP 5555 and output to a local ElasticSearch.</p>

<p>Let&#8217;s try sending it something. Anything.</p>

<p>echo something  | nc localhost 5555
echo anything   | nc localhost 5555</p>

<p>Note: netcat has the annoying habit of not terminating when it reaches EOF
on OSX. Ctrl-C.</p>

<p>We can see activity in the ElasticSearch terminal. Something happened.
Excellent! If you go back to Marvel, you&#8217;ll see that there&#8217;s now a
<code>logstash.YYYY-MM-dd</code> index. This is where today&#8217;s logs will be stored.</p>

<p>To actually visualize the data, you&#8217;ll need to start one last terminal, to run
the Kibana web interface:</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>
</pre></td><td class='code'><pre><code class=''><span class='line'>cd ~/logs/logstash-1.4.2
</span><span class='line'>bin/logstash web</span></code></pre></td></tr></table></div></figure>


<p>Then open Kibana: <a href="http://localhost:9292/">localhost:9292</a>. You can either
read or ignore the Kibana welcome screen. Towards the bottom right, click the
&#8220;LogStash Dashboard&#8221; link.</p>

<p>We now see a histogram with one bar, showing the moment when you sent dummy events.
If you scroll down, you&#8217;ll see the details of the event.
Click on them to expand the events, and start poking around.</p>

<p><img src="http://www.programblings.com/images/posts/logstash/kibana-details-kick-tires.png" alt="Kibana detail panel" /></p>

<p>So you have a functional local LogStash setup!</p>

<p>I&#8217;ll cover the process of parsing logs in a follow-up post. Until then,
if you want to continue playing with LogStash, you may want to clean the bogus
data you just put in.</p>

<p>For that you&#8217;ll want to use the ElasticSearch REST API:</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'>curl -XDELETE "http://localhost:9200/logstash-`date -u '+%Y.%m.%d'`"</span></code></pre></td></tr></table></div></figure>


<p>Happy exploration!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Sensu Checks to report Metrics]]></title>
    <link href="http://www.programblings.com/2013/11/14/sensu-checks-to-report-metrics/"/>
    <updated>2013-11-14T09:34:00-05:00</updated>
    <id>http://www.programblings.com/2013/11/14/sensu-checks-to-report-metrics</id>
    <content type="html"><![CDATA[<p>Once you understand
<a href="http://www.programblings.com/2013/11/06/creating-a-sensu-check/">the basics of creating a Sensu check</a>,
creating a check that reports metrics is actually pretty simple.
Here&#8217;s the lowdown.</p>

<!-- more -->


<h2>The differences vs a standard check</h2>

<p>Sensu needs to be told that this is a metrics check:</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>
</pre></td><td class='code'><pre><code class='json'><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="nt">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;metric&quot;</span><span class="p">,</span> <span class="err">//</span> <span class="err">&lt;-</span> <span class="err">Boom</span>
</span><span class='line'>  <span class="nt">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;disk-usage-metrics.rb&quot;</span><span class="p">,</span>
</span><span class='line'>  <span class="err">//</span> <span class="err">...</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>The exit status (ok, warning, critical) can still be monitored by Sensu,
so no change there. Although my understanding is that most metrics checks
simply take care of the metrics aspect and aren&#8217;t built for alerting with
critical and warning statuses.</p>

<p>The textual output is expected to be in Graphite format.
Most of the time it&#8217;s spread over multiple lines, to output multiple data points:</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>
</pre></td><td class='code'><pre><code class='json'><span class='line'><span class="err">lolcathost.disk_usage.lolcats.used</span>   <span class="mi">9000000</span>    <span class="mi">1383246228</span>
</span><span class='line'><span class="err">lolcathost.disk_usage.lolcats.avail</span>   <span class="mi">9000</span>    <span class="mi">1383246228</span>
</span><span class='line'><span class="err">lolcathost.disk_usage.lolcats.used_percentage</span>   <span class="mi">99</span>    <span class="mi">1383246228</span>
</span><span class='line'><span class="err">lolcathost.disk_usage.root.used</span>   <span class="mi">42</span>    <span class="mi">1383246229</span>
</span><span class='line'><span class="err">...</span>
</span></code></pre></td></tr></table></div></figure>


<p>The Graphite format is pretty simple: a path of words separated by dots,
a numeric value and an optional timestamp
(defaults to the time of reception if not supplied).</p>

<h2>Ruby is nicer</h2>

<p>Once again, you can use the <code>sensu-plugin</code> gem to get a few things handled
automatically for you. Here&#8217;s the basics for building a metrics check.</p>

<ul>
<li>You inherit from <code>Sensu::Plugin::Metric::CLI::Graphite</code></li>
<li>You still implement <code>run()</code>.</li>
<li>You still describe configurations with <code>option</code> and access them with <code>config[]</code>.</li>
<li>You output each stat with <code>output(name, value, timestamp)</code>.</li>
<li>You need to at least end with <code>ok()</code>, you can also use the other exit helpers if you want.</li>
</ul>


<p>Here&#8217;s
<a href="https://github.com/sensu/sensu-community-plugins/blob/master/plugins/system/disk-usage-metrics.rb">disk-usage-metrics.rb</a>
as an example:</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>
<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>
</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;rubygems&#39;</span> <span class="k">if</span> <span class="no">RUBY_VERSION</span> <span class="o">&lt;</span> <span class="s1">&#39;1.9.0&#39;</span>
</span><span class='line'><span class="nb">require</span> <span class="s1">&#39;sensu-plugin/metric/cli&#39;</span>
</span><span class='line'><span class="nb">require</span> <span class="s1">&#39;socket&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">DiskGraphite</span> <span class="o">&lt;</span> <span class="no">Sensu</span><span class="o">::</span><span class="no">Plugin</span><span class="o">::</span><span class="no">Metric</span><span class="o">::</span><span class="no">CLI</span><span class="o">::</span><span class="no">Graphite</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">option</span> <span class="ss">:scheme</span><span class="p">,</span>
</span><span class='line'>    <span class="ss">:description</span> <span class="o">=&gt;</span> <span class="s2">&quot;Metric naming scheme, text to prepend to metric&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="ss">:short</span> <span class="o">=&gt;</span> <span class="s2">&quot;-s SCHEME&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="ss">:long</span> <span class="o">=&gt;</span> <span class="s2">&quot;--scheme SCHEME&quot;</span><span class="p">,</span>
</span><span class='line'>    <span class="ss">:default</span> <span class="o">=&gt;</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="no">Socket</span><span class="o">.</span><span class="n">gethostname</span><span class="si">}</span><span class="s2">.disk_usage&quot;</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">run</span>
</span><span class='line'>    <span class="c1"># http://www.kernel.org/doc/Documentation/iostats.txt</span>
</span><span class='line'>    <span class="n">metrics</span> <span class="o">=</span> <span class="o">[</span>
</span><span class='line'>      <span class="s1">&#39;reads&#39;</span><span class="p">,</span> <span class="s1">&#39;readsMerged&#39;</span><span class="p">,</span> <span class="s1">&#39;sectorsRead&#39;</span><span class="p">,</span> <span class="s1">&#39;readTime&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="s1">&#39;writes&#39;</span><span class="p">,</span> <span class="s1">&#39;writesMerged&#39;</span><span class="p">,</span> <span class="s1">&#39;sectorsWritten&#39;</span><span class="p">,</span> <span class="s1">&#39;writeTime&#39;</span><span class="p">,</span>
</span><span class='line'>      <span class="s1">&#39;ioInProgress&#39;</span><span class="p">,</span> <span class="s1">&#39;ioTime&#39;</span><span class="p">,</span> <span class="s1">&#39;ioTimeWeighted&#39;</span>
</span><span class='line'>    <span class="o">]</span>
</span><span class='line'>
</span><span class='line'>    <span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s2">&quot;/proc/diskstats&quot;</span><span class="p">,</span> <span class="s2">&quot;r&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">each_line</span> <span class="k">do</span> <span class="o">|</span><span class="n">line</span><span class="o">|</span>
</span><span class='line'>      <span class="n">stats</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="sr">/\s+/</span><span class="p">)</span>
</span><span class='line'>      <span class="n">_major</span><span class="p">,</span> <span class="n">_minor</span><span class="p">,</span> <span class="n">dev</span> <span class="o">=</span> <span class="n">stats</span><span class="o">.</span><span class="n">shift</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
</span><span class='line'>      <span class="k">next</span> <span class="k">if</span> <span class="n">stats</span> <span class="o">==</span> <span class="o">[</span><span class="s1">&#39;0&#39;</span><span class="o">].</span><span class="n">cycle</span><span class="o">.</span><span class="n">take</span><span class="p">(</span><span class="n">stats</span><span class="o">.</span><span class="n">size</span><span class="p">)</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">metrics</span><span class="o">.</span><span class="n">size</span><span class="o">.</span><span class="n">times</span> <span class="p">{</span> <span class="o">|</span><span class="n">i</span><span class="o">|</span> <span class="n">output</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">config</span><span class="o">[</span><span class="ss">:scheme</span><span class="o">]</span><span class="si">}</span><span class="s2">.</span><span class="si">#{</span><span class="n">dev</span><span class="si">}</span><span class="s2">.</span><span class="si">#{</span><span class="n">metrics</span><span class="o">[</span><span class="n">i</span><span class="o">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">stats</span><span class="o">[</span><span class="n">i</span><span class="o">]</span> <span class="p">}</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">ok</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>


<h2>Conventions</h2>

<p>A few conventions have evolved in the sensu-community-plugins.</p>

<p>Most standard checks are named <code>check-xxx</code> and most metrics checks are named
<code>xxx-metrics</code>.</p>

<p>A more interesting convention has also evolved, around the metrics checks.
If you look back at the disk-usage-metrics.rb code up there,
you&#8217;ll notice the <code>--scheme</code> option defaults to hostname + plugin name.
Let&#8217;s come back to the example output I gave earlier:</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">lolcathost</span><span class="o">.</span><span class="n">disk_usage</span><span class="o">.</span><span class="n">lolcats</span><span class="o">.</span><span class="n">used</span>   <span class="mi">9000000</span>    <span class="mi">1383246228</span>
</span></code></pre></td></tr></table></div></figure>


<p>The first two can be overridden with <code>--scheme</code>, the rest is decided by the plugin.
There&#8217;s a few scenarios where you could want to override the scheme.</p>

<ul>
<li>If your systems have properly set FQDNs, <code>Socket.gethostname</code> will return that.
Which may give you metrics named like
<code>www1.app-name.phoenix-1.example.com.disk_usage.root.used</code>.
If that&#8217;s too unwieldy for you, you could for example invoke the check with
<code>--scheme $(hostname --short).disk_usage</code>.</li>
<li>You may want to nest your Sensu-generated metrics deeper into an existing
Graphite ontology: <code>--scheme system.$(hostname).disk_usage</code>.</li>
<li>If you&#8217;re using a cloud Graphite provider like
<a href="https://www.hostedgraphite.com/">HostedGraphite</a>,
you may need to prepend your account&#8217;s API key to the metric name you&#8217;re sending:
<code>--scheme deadbeef4242.$(hostname).disk_usage</code> or even better
<code>--scheme :::hostedgraphite.apikey:::$(hostname).disk_usage</code>.</li>
</ul>


<p>Most of the metrics check have this option. If you want to share your new
metric check, I would strongly recommend adding this same option as well.</p>

<h2>Conclusion</h2>

<p>So that&#8217;s it! I hope my lenghty prose still let me demonstrate clearly how
easy it is to create standard and metrics Sensu checks.
Let me know if you have questions or if you think I&#8217;ve overlooked anything!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Creating a Sensu Check]]></title>
    <link href="http://www.programblings.com/2013/11/06/creating-a-sensu-check/"/>
    <updated>2013-11-06T21:36:00-05:00</updated>
    <id>http://www.programblings.com/2013/11/06/creating-a-sensu-check</id>
    <content type="html"><![CDATA[<p>I recently did a lightning talk
<a href="http://www.devopsmtl.com/2013/11/05/recap-of-the-nov-4th-meetup/">at DevOpsMtl</a>
about creating a Sensu check. Sensu is a monitoring
framework that lets you build your monitoring solution, exactly how you need it.</p>

<p>Despite tons of checks being available already (see the &#8216;plugins&#8217; directory of the
<a href="https://github.com/sensu/sensu-community-plugins/tree/master/plugins">sensu-community-plugins repo</a>),
you may run into situations where you need to build your own. Thankfully, it&#8217;s
pretty easy.</p>

<!-- more -->


<h2>What are sensu checks?</h2>

<p>Sensu checks are run periodically to check anything from basic system state
(CPU, memory, disk usage, load, etc) to the state of software you&#8217;re running
(PostgreSQL, MySQL, ElasticSearch, Redis, etc). You can also go further and
use Sensu to monitor the state of external systems you depend on, even if you
don&#8217;t have direct control over them. At least you can initiate a failover
(e.g. switch to Mailgun if SendGrid is down).</p>

<p><a href="http://docs.sensuapp.org/0.12/checks.html">The doc on checks</a> is pretty comprehensive.
This post is meant as a primer.</p>

<p>So, what&#8217;s a Sensu check? Let&#8217;s start with how they&#8217;re configured:</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>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='json'><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="nt">&quot;checks&quot;</span><span class="p">:</span> <span class="p">{</span>
</span><span class='line'>    <span class="nt">&quot;cpu_usage&quot;</span><span class="p">:</span> <span class="p">{</span>
</span><span class='line'>      <span class="nt">&quot;command&quot;</span><span class="p">:</span> <span class="s2">&quot;check-ram.rb -w 50 -c 15&quot;</span><span class="p">,</span>
</span><span class='line'>      <span class="nt">&quot;interval&quot;</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
</span><span class='line'>      <span class="nt">&quot;subscribers&quot;</span><span class="p">:</span> <span class="p">[</span> <span class="s2">&quot;linux&quot;</span> <span class="p">]</span>
</span><span class='line'>    <span class="p">}</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>The <code>command</code> parameter is simply an executable command that will be run on the
server. Here we have an executable ruby script (properly hash-banged),
invoked with a few parameters.
It doesn&#8217;t have to be Ruby, it can be Bash, Python, a compiled program, anything.
Heck, if you feel like it, you could cram a whole Bash one-liner in your
<code>command</code> parameter and not need to upload a script to the monitored node.</p>

<h2>The API</h2>

<p>The script must behave a certain way for Sensu to be able to make sense of it.
Before I go any further, I&#8217;ll just mention that there are two kinds of checks:
standard checks and metric checks.
In this post I&#8217;ll cover only the first. Go here to read about
<a href="http://www.programblings.com/2013/11/14/sensu-checks-to-report-metrics">metrics checks</a></p>

<p>For those familiar with Nagios, standard Sensu checks are compatible with Nagios
checks. So if you know of a Nagios check that does what you need, you can stop
right here and go grab that. Otherwise, let&#8217;s continue.</p>

<p>The exit status of a Sensu check should be:</p>

<ul>
<li>0: ok</li>
<li>1: warning</li>
<li>2: critical</li>
<li>3 or more: unknown</li>
</ul>


<p>A sensu check optionally outputs text describing the state to stdout or stderr.
Ideally, your check should output at least one line, but it can be more.</p>

<p>Example outputs of check-ram.rb:</p>

<pre>
Exit
Status  Output
0       CheckRAM OK: 65% free RAM left
1       CheckRAM WARNING: 40% free RAM left
2       CheckRAM CRITICAL: 13% free RAM left
3       CheckRAM UNKNOWN: invalid percentage
</pre>


<h3>Dumb check example</h3>

<p>Here&#8217;s an example of a dummy Bash check that monitors the value of $RANDOM.
Anything over 22000 is ok, over 11000 is a warning and below that is critical.</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>
<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>
</pre></td><td class='code'><pre><code class='bash'><span class='line'><span class="c">#!/bin/bash</span>
</span><span class='line'>
</span><span class='line'><span class="c"># Check the state</span>
</span><span class='line'><span class="nv">rand</span><span class="o">=</span><span class="nv">$RANDOM</span> <span class="c"># 0 to 32k</span>
</span><span class='line'>
</span><span class='line'><span class="c"># Report how dire the situation is</span>
</span><span class='line'><span class="k">if</span> <span class="o">[</span> <span class="nv">$rand</span> -gt 22000 <span class="o">]</span>; <span class="k">then</span>
</span><span class='line'><span class="k">  </span><span class="nb">echo</span> <span class="s2">&quot;Ok: random number generated was high enough ($rand)&quot;</span>
</span><span class='line'>  <span class="nb">exit </span>0
</span><span class='line'><span class="k">else</span>
</span><span class='line'><span class="k">  if</span> <span class="o">[</span> <span class="nv">$rand</span> -gt 11000 <span class="o">]</span>; <span class="k">then</span>
</span><span class='line'><span class="k">    </span><span class="nb">echo</span> <span class="s2">&quot;Warning: random number generated was $rand&quot;</span>
</span><span class='line'>    <span class="nb">exit </span>1
</span><span class='line'>  <span class="k">else</span>
</span><span class='line'><span class="k">    </span><span class="nb">echo</span> <span class="s2">&quot;Critical: random number generated was $rand&quot;</span>
</span><span class='line'>    <span class="nb">exit </span>2
</span><span class='line'>  <span class="k">fi</span>
</span><span class='line'><span class="k">fi</span>
</span><span class='line'>
</span><span class='line'><span class="nb">echo</span> <span class="s2">&quot;Unknown: How did I get here?&quot;</span>
</span><span class='line'><span class="nb">exit </span>3 <span class="c"># or higher</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Ruby is nicer</h2>

<p>If you prefer using Ruby, the Sensu folks created a Ruby gem you can start from.</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='bash'><span class='line'>gem install sensu-plugin
</span></code></pre></td></tr></table></div></figure>


<p>Here&#8217;s a simplified version of
<a href="https://github.com/sensu/sensu-community-plugins/blob/master/plugins/system/check-ram.rb">the check-ram.rb</a>
plugin:</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>
<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>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</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 class="c1">#</span>
</span><span class='line'><span class="c1"># Check free RAM Plugin</span>
</span><span class='line'><span class="c1">#</span>
</span><span class='line'>
</span><span class='line'><span class="nb">require</span> <span class="s1">&#39;sensu-plugin/check/cli&#39;</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">CheckRAM</span> <span class="o">&lt;</span> <span class="no">Sensu</span><span class="o">::</span><span class="no">Plugin</span><span class="o">::</span><span class="no">Check</span><span class="o">::</span><span class="no">CLI</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">option</span> <span class="ss">:warn</span><span class="p">,</span>
</span><span class='line'>    <span class="ss">:short</span> <span class="o">=&gt;</span> <span class="s1">&#39;-w WARN&#39;</span><span class="p">,</span>
</span><span class='line'>    <span class="ss">:proc</span> <span class="o">=&gt;</span> <span class="nb">proc</span> <span class="p">{</span><span class="o">|</span><span class="n">a</span><span class="o">|</span> <span class="n">a</span><span class="o">.</span><span class="n">to_i</span> <span class="p">},</span>
</span><span class='line'>    <span class="ss">:default</span> <span class="o">=&gt;</span> <span class="mi">10</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">option</span> <span class="ss">:crit</span><span class="p">,</span>
</span><span class='line'>    <span class="ss">:short</span> <span class="o">=&gt;</span> <span class="s1">&#39;-c CRIT&#39;</span><span class="p">,</span>
</span><span class='line'>    <span class="ss">:proc</span> <span class="o">=&gt;</span> <span class="nb">proc</span> <span class="p">{</span><span class="o">|</span><span class="n">a</span><span class="o">|</span> <span class="n">a</span><span class="o">.</span><span class="n">to_i</span> <span class="p">},</span>
</span><span class='line'>    <span class="ss">:default</span> <span class="o">=&gt;</span> <span class="mi">5</span>
</span><span class='line'>
</span><span class='line'>  <span class="k">def</span> <span class="nf">run</span>
</span><span class='line'>    <span class="n">total_ram</span><span class="p">,</span> <span class="n">free_ram</span> <span class="o">=</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span>
</span><span class='line'>
</span><span class='line'>    <span class="sb">`free -m`</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">drop</span><span class="p">(</span><span class="mi">1</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">line</span><span class="o">|</span>
</span><span class='line'>      <span class="n">free_ram</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">split</span><span class="o">[</span><span class="mi">3</span><span class="o">].</span><span class="n">to_i</span> <span class="k">if</span> <span class="n">line</span> <span class="o">=~</span> <span class="sr">/^-\/\+ buffers\/cache:/</span>
</span><span class='line'>      <span class="n">total_ram</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">split</span><span class="o">[</span><span class="mi">1</span><span class="o">].</span><span class="n">to_i</span> <span class="k">if</span> <span class="n">line</span> <span class="o">=~</span> <span class="sr">/^Mem:/</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">unknown</span> <span class="s2">&quot;invalid percentage&quot;</span> <span class="k">if</span> <span class="n">config</span><span class="o">[</span><span class="ss">:crit</span><span class="o">]</span> <span class="o">&gt;</span> <span class="mi">100</span> <span class="ow">or</span> <span class="n">config</span><span class="o">[</span><span class="ss">:warn</span><span class="o">]</span> <span class="o">&gt;</span> <span class="mi">100</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">percents_left</span> <span class="o">=</span> <span class="n">free_ram</span><span class="o">*</span><span class="mi">100</span><span class="o">/</span><span class="n">total_ram</span>
</span><span class='line'>    <span class="n">message</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">percents_left</span><span class="si">}</span><span class="s2">% free RAM left&quot;</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">critical</span> <span class="k">if</span> <span class="n">percents_left</span> <span class="o">&lt;</span> <span class="n">config</span><span class="o">[</span><span class="ss">:crit</span><span class="o">]</span>
</span><span class='line'>    <span class="n">warning</span> <span class="k">if</span> <span class="n">percents_left</span> <span class="o">&lt;</span> <span class="n">config</span><span class="o">[</span><span class="ss">:warn</span><span class="o">]</span>
</span><span class='line'>    <span class="n">ok</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>You inherit from <code>Sensu::Plugin::Check::CLI</code>, then define a <code>run</code> method and
you&#8217;re off to the races.</p>

<h3>CLI parameters</h3>

<p>The <code>option</code> method lets you declare how your script should be invoked.
Here&#8217;s a few things you can specify:</p>

<ul>
<li>default value</li>
<li>required arguments</li>
<li>short and long argument names (<code>-v</code> or <code>--version</code>)</li>
<li>a description for the CLI help</li>
<li>a proc to run on the argument. Commonly used to call .to_i, .to_f.
All values you get in the <code>config</code> hash are strings otherwise.</li>
<li>is it a boolean argument (this is the only case where you don&#8217;t get a string).</li>
</ul>


<p>Using <code>option</code> also has the nice side effect of producing a useful <code>--help</code> for your script.</p>

<p>The workings of <code>option</code> will sound familiar to fans of <a href="http://whatisthor.com">Thor</a>,
but in our case, <code>option</code> is a feature provided by Opscode&#8217;s
<a href="https://github.com/opscode/mixlib-cli">mixlib-cli gem</a>.
You can go see there to see all of the documentation for <code>option</code>.</p>

<p>The instance method <code>config</code> is also created by mixlib-cli. It returns a hash
of all resolved CLI parameters (manually specified value or default and so on).
<code>config</code> being an instance method, it&#8217;s available inside <code>run</code> or in any other
method you care to define, without needing to pass around the hash.</p>

<h3>Reporting the state</h3>

<p>So you have defined your params and you know how to access them in your code.
The <code>sensu-plugin</code> gem also gives you a few helper methods to help you report
the observed state in a consistent manner.</p>

<p>The basics are</p>

<ul>
<li><code>ok(message)</code></li>
<li><code>warning(message)</code></li>
<li><code>critical(message)</code></li>
<li><code>unknown(message)</code></li>
</ul>


<p>Each of those corresponds exactly to the API we defined at the top.
One thing to know is that calling any of those stops the execution of the script
right away.</p>

<p>The check-ram.rb example uses a slightly different approach. Since the message
is always exactly the same, it calls <code>message(message)</code> once, and then calls
<code>ok()</code> (or other) without a message.</p>

<p>If you look back at the code for check-ram.rb, you&#8217;ll notice that the message
reported is &#8220;65% free RAM left&#8221;. The sensu-plugin gem automatically normalizes
the output with the check name and status: &#8220;CheckRAM OK: 65% free RAM left&#8221;.</p>

<h2>Testing your check</h2>

<p>Since Sensu checks are simple executables, now you only need to run your check
manually in all appropriate scenarios to validate that your check works as expected.</p>

<p>No one&#8217;s created an automated test harness yet for Sensu checks.
So manual testing will have to do for now :-)</p>

<h2>Last step</h2>

<p>The last step of creating a Sensu check is to visit the
<a href="https://github.com/sensu/sensu-community-plugins">sensu-community-plugins</a>
repo, create a pull request and share your check with the world.
You&#8217;re probably not the only one who needs to monitor whatever you just
created a check for, so why not give back to the community?</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Hosting a Website on S3]]></title>
    <link href="http://www.programblings.com/2013/07/12/hosting-a-website-on-s3/"/>
    <updated>2013-07-12T21:05:00-04:00</updated>
    <id>http://www.programblings.com/2013/07/12/hosting-a-website-on-s3</id>
    <content type="html"><![CDATA[<p>I recently took part in a discussion about static site generators
like Middleman, Jekyll and Octopress.
I mentioned that I was hosting this site on S3, and also doing more advanced
stuff, like setting up redirects.</p>

<p>Here&#8217;s how I do it. It&#8217;s pretty simple.</p>

<!-- more -->


<h2>Requirements</h2>

<ul>
<li><a href="http://git-scm.com/book/en/Getting-Started-Installing-Git">git</a></li>
<li><a href="http://s3tools.org/download">s3cmd</a>, then <code>s3cmd --configure</code></li>
<li><a href="http://www.ruby-lang.org/en/downloads/">ruby</a></li>
</ul>


<p>Installing these on my platform
(OSX with <a href="https://github.com/mxcl/homebrew/wiki/Installation">Homebrew</a>)
is a breeze:</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'>brew install git s3cmd # same with apt-get & yum</span></code></pre></td></tr></table></div></figure>


<p>A ruby developer will undoubtedly use another method to install the language.
For someone who doesn&#8217;t mind:</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'>brew install ruby # same with apt-get, maybe not with yum*.</span></code></pre></td></tr></table></div></figure>


<p>* At least, yum on CentOS 6.4 and older installs an unsupported version of Ruby
, which is 1.8.7 (as of summer 2013).
YMMV if that&#8217;s your ruby is that old.</p>

<h2>Deploying to S3 with s3cmd</h2>

<h3>Setting up the bucket</h3>

<p>Create your bucket with the
<a href="https://console.aws.amazon.com/s3/home">AWS console</a>.
<code>s3cmd</code> can do it too, but use the AWS console for hosted sites,
because there&#8217;s other settings you can only do in the console anyway.</p>

<ol>
<li>Name your bucket the same as your website&#8217;s hostname.
 E.g.: <code>www.programblings.com</code></li>
<li>Optional: If you set up logging to another bucket, use a target prefix to
 keep the logs from your different static sites in different directories.
 E.g.: <strong>Target Prefix</strong>: <code>www.programblings.com</code>.</li>
<li>Still from the AWS console, open your bucket&#8217;s settings and open the
 &#8220;Static Website Hosting&#8221;.</li>
<li>Enable it. Set <strong>Index Document</strong>: <code>index.html</code> and
 <strong>Error Document</strong>: <code>not-found/index.html</code> (or your preferred error page).</li>
</ol>


<h3>Uploading content</h3>

<p>The website generator I use outputs to <code>public</code>. To deploy this subdirectory to
my bucket:</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'>s3cmd sync --acl-public public/ s3://www.programblings.com</span></code></pre></td></tr></table></div></figure>


<p>If you&#8217;ve already updated your DNS to point to your bucket,
navigate there with your browser.
If you don&#8217;t want to mess with DNS just yet, just go to
<code>[yoursite].s3-website-[yourregion].amazonaws.com</code>. In my case:
<a href="http://www.programblings.com.s3-website-us-east-1.amazonaws.com/">www.programblings.com.s3-website-us-east-1.amazonaws.com</a> (check it out, it works).</p>

<p>You&#8217;re online already.</p>

<h4>True sync</h4>

<p><code>s3cmd</code>&#8217;s syncing doesn&#8217;t delete old files by default, though.
It only adds.
So let&#8217;s make sure we delete old stuff by adding <code>--delete</code> to our command:</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'>s3cmd sync --delete --acl-public public/ s3://www.programblings.com</span></code></pre></td></tr></table></div></figure>


<p>This <code>sync</code> command ensures that obsolete files are purged.</p>

<h3>HTTP Caching (or other headers)</h3>

<p>Now let&#8217;s say that I want to set some caching headers to let my
<a href="https://www.cloudflare.com">Free CDN</a> (and much more)
serve my site faster, all around the world.</p>

<p>I can add <code>--add-header=Cache-Control:public,max-age=300</code> (5 minutes) to my
s3cmd deploy command.
Which results in the following mouthful:</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>
</pre></td><td class='code'><pre><code class=''><span class='line'>s3cmd sync --delete --acl-public public/ s3://www.programblings.com \
</span><span class='line'>  --add-header=Cache-Control:public,max-age=300</span></code></pre></td></tr></table></div></figure>


<p>My generator&#8217;s scripts are provided via rake. So here&#8217;s how I set up my deploy
task:</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>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">task</span> <span class="ss">:deploy</span> <span class="k">do</span>
</span><span class='line'>  <span class="nb">system</span>  <span class="s2">&quot;s3cmd sync --delete --acl-public public/ s3://www.programblings.com&quot;</span> <span class="o">+</span>
</span><span class='line'>          <span class="s2">&quot; --add-header=Cache-Control:public,max-age=300&quot;</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<p>Depending on what tool you use, you may have another task at hand,
that can force the rendering of your whole site.
In my case, it was another rake task named <code>generate</code>.
So my deploy task actually started with</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">task</span> <span class="ss">:deploy</span> <span class="o">=&gt;</span> <span class="ss">:generate</span> <span class="k">do</span>
</span></code></pre></td></tr></table></div></figure>


<h3>Making it safer</h3>

<p>Let&#8217;s fast forward a few blog posts.
You&#8217;ve deployed stuff you shouldn&#8217;t have a few times already.</p>

<p>A quick way to establish a bit of trust in what you&#8217;re deploying
is to simply ensure that everything is commited to your git repo already.</p>

<p>In other words, <code>git status --porcelain</code> should return an empty string.</p>

<p>My rake task now look like 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>
<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="n">task</span> <span class="ss">:deploy</span> <span class="o">=&gt;</span> <span class="ss">:generate</span> <span class="k">do</span>
</span><span class='line'>  <span class="k">unless</span> <span class="s1">&#39;&#39;</span> <span class="o">==</span> <span class="p">(</span><span class="n">status</span> <span class="o">=</span> <span class="sb">`git status --porcelain`</span><span class="p">)</span>
</span><span class='line'>    <span class="nb">abort</span> <span class="s2">&quot;You have unstaged changes. Make sure to commit or stash first.</span><span class="se">\n\n</span><span class="si">#{</span><span class="n">status</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>  <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>  <span class="nb">system</span>  <span class="s2">&quot;s3cmd sync --delete --acl-public public/ s3://www.programblings.com&quot;</span> <span class="o">+</span>
</span><span class='line'>          <span class="s2">&quot; --add-header=Cache-Control:public,max-age=300&quot;</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>


<h2>Redirection</h2>

<p>If you&#8217;ve migrated your site away from another platform, you may have
some old urls that aren&#8217;t valid on this platform anymore, but you still want
to redirect to a working url.</p>

<p>The <a href="http://docs.aws.amazon.com/AmazonS3/latest/dev/HowDoIWebsiteConfiguration.html">AWS documentation</a>
being what it is, let me just give a few concrete examples
of what you can put in your S3 website&#8217;s &#8220;Redirection Rules&#8221;
(found in your bucket&#8217;s website hosting section, in the AWS console).</p>

<p>The following example redirects <code>/feed</code> to my current RSS service&#8217;s feed,
<code>feeds.feedburner.com/Programblings</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>
<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>
</pre></td><td class='code'><pre><code class='xml'><span class='line'><span class="nt">&lt;RoutingRules&gt;</span>
</span><span class='line'>  <span class="nt">&lt;RoutingRule&gt;</span>
</span><span class='line'>    <span class="nt">&lt;Condition&gt;</span>
</span><span class='line'>      <span class="nt">&lt;KeyPrefixEquals&gt;</span>feed<span class="nt">&lt;/KeyPrefixEquals&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/Condition&gt;</span>
</span><span class='line'>    <span class="nt">&lt;Redirect&gt;</span>
</span><span class='line'>      <span class="nt">&lt;HostName&gt;</span>feeds.feedburner.com<span class="nt">&lt;/HostName&gt;</span>
</span><span class='line'>      <span class="nt">&lt;ReplaceKeyWith&gt;</span>Programblings<span class="nt">&lt;/ReplaceKeyWith&gt;</span>
</span><span class='line'>      <span class="nt">&lt;HttpRedirectCode&gt;</span>302<span class="nt">&lt;/HttpRedirectCode&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/Redirect&gt;</span>
</span><span class='line'>  <span class="nt">&lt;/RoutingRule&gt;</span>
</span><span class='line'><span class="nt">&lt;/RoutingRules&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>I have another static site that&#8217;s so simple that I haven&#8217;t even bothered
creating an error page yet.  I&#8217;ve only overridden the 403 errors.
403 is S3&#8217;s default answer to all files who are either not there or not public.</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>
<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='xml'><span class='line'><span class="nt">&lt;RoutingRules&gt;</span>
</span><span class='line'>  <span class="nt">&lt;RoutingRule&gt;</span>
</span><span class='line'>    <span class="nt">&lt;Condition&gt;</span>
</span><span class='line'>      <span class="nt">&lt;HttpErrorCodeReturnedEquals&gt;</span>403<span class="nt">&lt;/HttpErrorCodeReturnedEquals&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/Condition&gt;</span>
</span><span class='line'>    <span class="nt">&lt;Redirect&gt;</span>
</span><span class='line'>      <span class="nt">&lt;ReplaceKeyWith&gt;</span>?not-found<span class="nt">&lt;/ReplaceKeyWith&gt;</span>
</span><span class='line'>      <span class="nt">&lt;HttpRedirectCode&gt;</span>302<span class="nt">&lt;/HttpRedirectCode&gt;</span>
</span><span class='line'>    <span class="nt">&lt;/Redirect&gt;</span>
</span><span class='line'>  <span class="nt">&lt;/RoutingRule&gt;</span>
</span><span class='line'><span class="nt">&lt;/RoutingRules&gt;</span>
</span></code></pre></td></tr></table></div></figure>


<p>This rule redirects all errors to the main index page,
but will also let me dig into my analytics tool&#8217;s page views on <code>?not-found</code> later on,
if I&#8217;m ever curious.</p>

<p>In your &#8220;Redirection Rules&#8221;, keep in mind that the root block (<code>RoutingRules</code>)
can contain multiple <code>RoutingRule</code> blocks.</p>

<h2>Closing notes</h2>

<p>Hosting a few static websites on S3 is so cheap it will probably fit in your
free tier usage of the service. A no brainer, if you ask me.</p>

<p>If you found my setup interesting, here&#8217;s another interesting
take. It&#8217;s a personal deployment pipeline.
I lets its author deploy to a pre-prod site.
It also lets him promote the preprod site&#8217;s content to production.
But it doesn&#8217;t let him push straight to production. The article is
<a href="http://blog.thepete.net/blog/2012/08/02/octopress-deployment-pipeline/">Octopress Deployment Pipeline</a>.</p>

<p>Oh, one last thing while we&#8217;re there:
I&#8217;ve never actually gone back to my logs stored on S3 ;-)</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Do You Back Up Your DNS Records?]]></title>
    <link href="http://www.programblings.com/2012/07/23/do-you-back-up-your-dns-records/"/>
    <updated>2012-07-23T11:34:00-04:00</updated>
    <id>http://www.programblings.com/2012/07/23/do-you-back-up-your-dns-records</id>
    <content type="html"><![CDATA[<p>At the time of writing, <a href="http://www.zerigo.com">Zerigo DNS</a> is being hit by a DDOS
attack (<a href="https://twitter.com/zerigo/status/227262239407759360">reference starting here on Twitter</a>).</p>

<p>I was able to migrate our company&#8217;s services &#8211; <a href="http://www.socialgrapes.com">SocialGrapes</a> and
<a href="http://socialgrapeslab.com">SocialGrapesLAB</a> &#8211; to DNSimple pretty quickly,
mainly because I remembered most of our DNS settings. But still, I had no idea
about some of the finer details, like mail server settings, and didn&#8217;t immediately
remember to put back the records for our CDN.</p>

<p>So in the process of fixing all of this, I decided to add two simple tasks to my
<code>rake backup</code> task. They may be useful to you too:</p>

<!-- more -->


<p>Requirements:</p>

<ul>
<li>the Nokogiri Ruby gem</li>
<li>the dnsimple-ruby Ruby gem</li>
<li>curl</li>
</ul>


<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>
<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>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
<span class='line-number'>53</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">namespace</span> <span class="ss">:backup</span> <span class="k">do</span>
</span><span class='line'>  <span class="c1"># ...</span>
</span><span class='line'>
</span><span class='line'>  <span class="n">namespace</span> <span class="ss">:dns</span> <span class="k">do</span>
</span><span class='line'>    <span class="n">task</span> <span class="ss">:zerigo</span> <span class="k">do</span>
</span><span class='line'>      <span class="nb">require</span> <span class="s1">&#39;nokogiri&#39;</span>
</span><span class='line'>      <span class="n">dir</span>   <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;DNS_BACKUP_DIR&#39;</span><span class="o">]</span> <span class="o">||</span> <span class="s1">&#39;.&#39;</span><span class="p">,</span> <span class="s1">&#39;zerigo&#39;</span> <span class="p">)</span>
</span><span class='line'>      <span class="n">user</span>  <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;ZERIGO_USER&#39;</span><span class="o">]</span>
</span><span class='line'>      <span class="n">key</span>   <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;ZERIGO_KEY&#39;</span><span class="o">]</span>
</span><span class='line'>
</span><span class='line'>      <span class="sb">`mkdir -p </span><span class="si">#{</span><span class="n">dir</span><span class="si">}</span><span class="sb">`</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">list</span> <span class="o">=</span> <span class="sb">`curl --user </span><span class="si">#{</span><span class="n">user</span><span class="si">}</span><span class="sb">:</span><span class="si">#{</span><span class="n">key</span><span class="si">}</span><span class="sb"> http://ns.zerigo.com/api/1.1/zones.xml`</span>
</span><span class='line'>      <span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dir</span><span class="p">,</span> <span class="s1">&#39;_list.xml&#39;</span><span class="p">),</span> <span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="p">{</span><span class="o">|</span><span class="n">f</span><span class="o">|</span> <span class="n">f</span><span class="o">.</span><span class="n">write</span> <span class="n">list</span><span class="p">}</span>
</span><span class='line'>
</span><span class='line'>      <span class="no">Nokogiri</span><span class="o">::</span><span class="no">XML</span><span class="p">(</span><span class="n">list</span><span class="p">)</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s1">&#39;zones zone&#39;</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">node</span><span class="o">|</span>
</span><span class='line'>        <span class="nb">id</span>      <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s1">&#39;id&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">text</span>
</span><span class='line'>        <span class="n">domain</span>  <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s1">&#39;domain&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">text</span>
</span><span class='line'>        <span class="n">output</span>  <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dir</span><span class="p">,</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">domain</span><span class="si">}</span><span class="s2">.xml&quot;</span><span class="p">)</span>
</span><span class='line'>        <span class="nb">puts</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">domain</span><span class="si">}</span><span class="s2"> (</span><span class="si">#{</span><span class="nb">id</span><span class="si">}</span><span class="s2">) =&gt; </span><span class="si">#{</span><span class="n">output</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>
</span><span class='line'>        <span class="sb">`curl --user </span><span class="si">#{</span><span class="n">user</span><span class="si">}</span><span class="sb">:</span><span class="si">#{</span><span class="n">key</span><span class="si">}</span><span class="sb"> -o &quot;</span><span class="si">#{</span><span class="n">output</span><span class="si">}</span><span class="sb">&quot; http://ns.zerigo.com/api/1.1/zones/</span><span class="si">#{</span><span class="nb">id</span><span class="si">}</span><span class="sb">/hosts.xml`</span>
</span><span class='line'>      <span class="k">end</span>
</span><span class='line'>    <span class="k">end</span>
</span><span class='line'>
</span><span class='line'>    <span class="n">task</span> <span class="ss">:dnsimple</span> <span class="k">do</span>
</span><span class='line'>      <span class="n">dir</span>   <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;DNS_BACKUP_DIR&#39;</span><span class="o">]</span> <span class="o">||</span> <span class="s1">&#39;.&#39;</span><span class="p">,</span> <span class="s1">&#39;dnsimple&#39;</span> <span class="p">)</span>
</span><span class='line'>      <span class="n">user</span>  <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;DNSIMPLE_USER&#39;</span><span class="o">]</span>
</span><span class='line'>      <span class="n">key</span>   <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">&#39;DNSIMPLE_KEY&#39;</span><span class="o">]</span>
</span><span class='line'>
</span><span class='line'>      <span class="sb">`mkdir -p </span><span class="si">#{</span><span class="n">dir</span><span class="si">}</span><span class="sb">`</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">list</span> <span class="o">=</span> <span class="sb">`dnsimple -u </span><span class="si">#{</span><span class="n">user</span><span class="si">}</span><span class="sb"> -p </span><span class="si">#{</span><span class="n">key</span><span class="si">}</span><span class="sb"> list`</span>
</span><span class='line'>      <span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dir</span><span class="p">,</span> <span class="s1">&#39;_list.txt&#39;</span><span class="p">),</span> <span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="p">{</span><span class="o">|</span><span class="n">f</span><span class="o">|</span> <span class="n">f</span><span class="o">.</span><span class="n">write</span> <span class="n">list</span><span class="p">}</span>
</span><span class='line'>
</span><span class='line'>      <span class="n">list</span><span class="o">.</span><span class="n">lines</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&amp;</span><span class="ss">:strip</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">domain</span><span class="o">|</span>
</span><span class='line'>        <span class="k">next</span> <span class="k">if</span> <span class="n">domain</span> <span class="o">=~</span> <span class="sr">/Found .* domain/</span>
</span><span class='line'>
</span><span class='line'>        <span class="n">output</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dir</span><span class="p">,</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">domain</span><span class="si">}</span><span class="s2">.txt&quot;</span><span class="p">)</span>
</span><span class='line'>        <span class="nb">puts</span> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">domain</span><span class="si">}</span><span class="s2"> =&gt; </span><span class="si">#{</span><span class="n">output</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'>
</span><span class='line'>        <span class="sb">`dnsimple -u </span><span class="si">#{</span><span class="n">user</span><span class="si">}</span><span class="sb"> -p </span><span class="si">#{</span><span class="n">key</span><span class="si">}</span><span class="sb"> record:list </span><span class="si">#{</span><span class="n">domain</span><span class="si">}</span><span class="sb"> &gt; &quot;</span><span class="si">#{</span><span class="n">output</span><span class="si">}</span><span class="sb">&quot;`</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><span class='line'>
</span><span class='line'>
</span><span class='line'>  <span class="n">desc</span> <span class="s2">&quot;backup dns records from all services&quot;</span>
</span><span class='line'>  <span class="n">task</span> <span class="ss">:dns</span> <span class="o">=&gt;</span> <span class="o">[</span><span class="s1">&#39;dns:zerigo&#39;</span><span class="p">,</span> <span class="s1">&#39;dns:dnsimple&#39;</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">desc</span> <span class="s2">&quot;Run all backup tasks FROM=env (default production)&quot;</span>
</span><span class='line'><span class="n">task</span> <span class="ss">:backup</span> <span class="o">=&gt;</span> <span class="o">[</span><span class="s1">&#39;backup:dns&#39;</span><span class="p">,</span> <span class="s1">&#39;backup:database&#39;</span><span class="p">,</span> <span class="s1">&#39;backup:images&#39;</span><span class="o">]</span>
</span></code></pre></td></tr></table></div></figure>


<p>To reuse this, you should install all dependencies, then set up the following
environment variables:</p>

<ul>
<li>DNSIMPLE_USER (your account&#8217;s email)</li>
<li>DNSIMPLE_KEY (not the API key, but the password, unfortunately)</li>
<li>ZERIGO_USER (your account&#8217;s email)</li>
<li>ZERIGO_KEY (your account&#8217;s api key. Turn on api access in Manage account / DNS / preferences)</li>
<li>optionally, DNS_BACKUP_DIR</li>
</ul>


<p>Obviously all of this is an almost trivial backup that will only help you
restore things manually when things go bad. You may want to replicate any new
record to a secondary service, but I chose not to.  I&#8217;m comfortable with this
situation, since <a href="http://socialgrapeslab.com">rating wines you love or dislike</a>
is not considered critical ;-)</p>

<p>So, do you back up your DNS records?</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Bach from the dead]]></title>
    <link href="http://www.programblings.com/2012/07/04/bach-from-the-dead/"/>
    <updated>2012-07-04T08:01:00-04:00</updated>
    <id>http://www.programblings.com/2012/07/04/bach-from-the-dead</id>
    <content type="html"><![CDATA[<p><img src="http://www.programblings.com/uploads/2012/bach_from_the_dead.jpg" alt="Bach from the dead" /></p>

<p>I think it&#8217;s pretty funny that the last article on my blog is 3 years old, and starts with &#8220;I haven’t been blogging much lately&#8221; :-)</p>

<!-- more -->


<p>A lot has happened since then. I&#8217;ve worked for more than a year for a now bust
startup (SmartHippo), and then went on to work for
<a href="http://www.socialgrapes.com">SocialGrapes</a>,
for more than 2 years. I&#8217;m still there, as the lead developer and CTO.</p>

<p>I could say we&#8217;re right in the
<a href="http://www.avc.com/a_vc/2012/03/the-startup-curve.html">trough of sorrow</a>.
But that&#8217;s not what this post is about.</p>

<p>This post is about coming back to blogging.
I miss rambling about the stuff I do day in and day out. Wordpress fatigue kept
eventually eroded my desire to blog.</p>

<p>This blog is now hosted with Octopress on S3, which I think is pretty neat :-)
I may post about my setup, but there&#8217;s quite a few blog posts in the wild
discussing hosting jekyll-based sites on S3.</p>

<p>I&#8217;ve got a ton to blog about, I just hope I can find enough time! I&#8217;ve started
working on git_remote_branch again, I created a JavaScript library that I
haven&#8217;t talked about anywhere (I didn&#8217;t have a good place :), I&#8217;ve
discovered a ton of new tools, and so on.</p>

<p>I&#8217;ll likely start with a series of posts about Heroku, though. After presenting
&#8220;Advanced Heroku&#8221; at the last Montreal.rb, I realized that a single blog post
about it all would be even more long and tedious than the presentation :-)</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[A new Ruby and Rails blog is born]]></title>
    <link href="http://www.programblings.com/2009/02/16/a-new-ruby-and-rails-blog-is-born/"/>
    <updated>2009-02-16T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2009/02/16/a-new-ruby-and-rails-blog-is-born</id>
    <content type="html"><![CDATA[<p>I haven&#8217;t been blogging much lately. I&#8217;ve been too busy with some vacation time and, of course, work.</p>




<p>This is going to change, but it&#8217;s not all going to happen on Programblings.</p>




<p>It&#8217;s been a long time coming, but <a href='http://giraffesoft.ca'>giraffesoft</a> finally has a blog. We&#8217;re going to kickstart our blog with a week of open source releases.</p>




<p>At giraffesoft we like DRY code. We all know that creating Rails plugins is barely more work than actually implementing the functionality inside of a specific application. For that reason, we create plugins all the time when working on projects.</p>




<p>So this week, we&#8217;re going to polish up a few of them &#8211; big and small &#8211; and officially introduce them to the world.</p>




<p>For now, please let me direct you to the brand-spanking new <a href='http://giraffesoft.ca/blog'>giraffesoft blog</a>.</p>




<p>If you&#8217;re too lazy to read the introductory post, here&#8217;s the punchlines:</p>




<ul>
<li><a href='http://feeds.giraffesoft.ca/giraffesoft-the-blog'>follow our RSS feed</a> or</li>

<li><a href='http://twitter.com/giraffesoft'>follow us on Twitter</a>.</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Rubinius for the Layman, Part 3 - Try Rubinius in 20 minutes]]></title>
    <link href="http://www.programblings.com/2008/11/25/rubinius-for-the-layman-part-3-try-rubinius-in-20-minutes/"/>
    <updated>2008-11-25T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2008/11/25/rubinius-for-the-layman-part-3-try-rubinius-in-20-minutes</id>
    <content type="html"><![CDATA[<p>I guess we&#8217;ve all heard <a href='http://blog.fallingsnow.net/2008/11/18/a-sad-day/'>last week&#8217;s sad news</a> about Engine Yard <a href='http://blog.engineyard.com/2008/11/17/rubinius-past-present-and-future'>diminishing the awesome support</a> they&#8217;ve given the Rubinius project. That&#8217;s personally how I see it: they&#8217;ve put the project on steroids for roughly a year, rather than &#8220;they&#8217;re now cutting back&#8221; x people.</p>




<p>As Brian Ford <a href='http://blog.brightredglow.com/2008/11/18/rubinius-is-a-community-project'>pointed out</a>, Rubinius is a community project. And Rubinius is not going away. A lot of people can&#8217;t wait to have a Ruby written more in Ruby than in C or C++. Koichi Sasada (lead developer on Ruby 1.9) even recently projected that Rubinius would eventually be the Ruby implementation of choice.</p>




<!-- more -->




<p>Rubinius&#8217; future is promising. I&#8217;d like to go from that positive note, and have YOU try Rubinius now. I promise that in 20 minutes, you&#8217;ll be running Rubinius and enjoying it. The longest parts of the process will be waiting (cloning, compiling), so it won&#8217;t even be difficult. Note: the article may look long, but it&#8217;s not. Half of it is code samples and the results returned.</p>




<p>So it&#8217;s been aeons since the last article of the RFTL series. But yes, this article is part of a series. You can look at the first 2 parts if you want. Some details<a href='#footnote_1'><sup>1</sup></a> won&#8217;t be up to date anymore, but it&#8217;ll help you get the gist of Rubinius if you&#8217;re not familiar with the project yet.</p>




<ul>
<li><a href="http://www.programblings.com/2008/04/01/rubinius-for-the-layman-part-1-rubies-all-the-way-down/">Rubinius for the Layman, Part 1: Rubies All the Way Down</a></li>

<li><a href="http://www.programblings.com/2008/04/15/rubinius-for-the-layman-part-2-how-rubinius-is-friendly/">Rubinius for the Layman, Part 2: How Rubinius is Friendly</a></li>

<li>Rubinius for the Layman, Part 3 - Try Rubinius in 20 minutes</li>
</ul>




<p>The 20 minutes timer starts now, for those who went ahead and read the past articles.</p>




<h1 id='install_rubinius'>Install Rubinius</h1>




<h2 id='prerequisites'>Prerequisites</h2>




<p>Prerequisites are probably already taken care of on most Ruby developers&#8217; machines:</p>




<ul>
<li>ruby 1.8, rubygems, rake and ParseTree (<code>sudo gem install rake ParseTree</code>)</li>

<li>git (no need to understand it, really, just having it installed)</li>

<li>general C++ building tools</li>
</ul>




<h3 id='dependencies_for_mac_users'>Dependencies for Mac users</h3>




<p>Leopard users should have all they need when Xcode is installed. Insert your Leopard upgrade DVD and from your terminal:</p>




<pre><code>open /Volumes/Mac\ OS\ X\ Upgrade\ DVD/Optional\ Installs/Xcode\ Tools/XcodeTools.mpkg </code></pre>




<h3 id='dependencies_for_linux_users'>Dependencies for Linux users</h3>




<p>Linux users have to make sure the following packages are installed. Use your the equivalent command for your distro:</p>




<pre><code>sudo apt-get install gcc bison make pkg-config libtool git</code></pre>




<p>(where make == GNU make)</p>




<h2 id='get_the_rubinius_code'>Get the Rubinius code</h2>




<p>Right now the GitHub feature to download a tarball is disabled for big projects like Rubinius. They say the feature on the radar as one of the things to fix in the next few weeks. Which will be awesome.</p>




<p>For now we have have to clone the repo, which in this case takes a few minutes. Find yourself a comfortable directory and:</p>




<pre><code>git clone git://github.com/evanphx/rubinius.git
# go make coffee
cd rubinius</code></pre>




<h2 id='build_rubinius'>Build Rubinius</h2>




<p>Assuming you&#8217;ve installed all the dependencies, the following should work right off the bat. If it&#8217;s not the case, check out the <a href='#footnote_2'>notes on the subject</a>.</p>




<pre><code>rake build
# go get a http://www.brawndo.com/</code></pre>




<p>Later, when you want to recompile from a clean slate, just run <code>rake distclean</code>.</p>




<p>If you have not gotten a BRAWNDO, please <a href='#run_rubinius'>skip over the next paragraph</a>.</p>




<p>RUBINIUS, like BRAWNDO, is one of the CRAZIEST ideas of the LAST DECADE! Can you realize you&#8217;re ABOUT to try the Ruby IMPLEMENTATION that&#8217;s got the BEST Ruby code ratio AMONG THEM ALL! Isn&#8217;t that FREAKING AWESOME? You can also do some of the CRAZIEST INTROSPECTION with MethodContext, StaticScope and other classes like THAT!</p>




<h1 id='run_rubinius'>Run Rubinius</h1>




<p>The Rubinius executable is rbx in the &#8216;bin&#8217; subdirectory. It&#8217;s a bit different from MRI in that rbx starts an irb session if you don&#8217;t specify a file to run. So let&#8217;s do that:</p>




<pre><code>bin/rbx
# in irb
puts &quot;Don&#39;t you spring a hello world on me&quot;
#=&gt; Don&#39;t you spring a hello world on me</code></pre>




<p>Ok then. Well, technically you&#8217;ve now tried Rubinius in less than 20 minutes. Now if you keep reading, you&#8217;ll really taste some true Rubinius awesomeness.</p>




<h2 id='kickass_introspection'>Kick-ass introspection</h2>




<p>Let&#8217;s start slow by patching <code>Object</code> to help us quickly grok the new kinds of objects we may encounter:</p>




<pre><code>class Object
  # Return only the methods not present on basic objects
  def interesting_methods
    (self.methods - Object.new.methods).sort
  end
end
#=&gt; #&lt;CompiledMethod interesting_methods file=(irb)&gt;</code></pre>




<p>And now let&#8217;s create a basic little class that will help us start our exploration of a <code>MethodContext</code> instance.</p>




<pre><code>class C
  def initialize
    @inst = 42
  end
  def get_mc
    local_var = &#39;value&#39;
    MethodContext.current
  end
end
#=&gt; #&lt;CompiledMethod get_mc file=(irb)&gt;</code></pre>




<p>So with the help of an instance of the class <code>C</code>, let&#8217;s start poking gently at a <code>MethodContext</code>.</p>




<pre><code>c   = C.new
ctx = c.get_mc
#=&gt; #&lt;MethodContext:0xcc #&lt;C:0xca&gt;#get_mc (irb):7&gt;

ctx.interesting_methods
#=&gt; [&quot;__add_method__&quot;, &quot;_get_field&quot;, &quot;_set_field&quot;, &quot;activate&quot;, 
 &quot;active_path&quot;, &quot;alias_method&quot;, &quot;back_ref&quot;, &quot;block&quot;, &quot;class_variable_defined?&quot;,
 &quot;const_defined?&quot;, &quot;const_path_defined?&quot;, &quot;context_from_proc&quot;, &quot;context_stack&quot;, 
 &quot;copy&quot;, &quot;current_scope&quot;, &quot;describe&quot;, &quot;disable_long_return!&quot;, &quot;dynamic_locals&quot;, 
 &quot;file&quot;, &quot;fp&quot;, &quot;from_eval?&quot;, &quot;get_eval_local&quot;, &quot;ip&quot;, &quot;ip=&quot;, &quot;last_match&quot;, 
 &quot;last_match=&quot;, &quot;line&quot;, &quot;lines&quot;, &quot;locals&quot;, &quot;locals=&quot;, &quot;location&quot;, 
 &quot;make_independent&quot;, &quot;method=&quot;, &quot;method_module&quot;, &quot;method_scope&quot;, 
 &quot;method_scope=&quot;, &quot;name&quot;, &quot;normalized_name&quot;, &quot;nth_ref&quot;, &quot;position_info&quot;, 
 &quot;receiver&quot;, &quot;receiver=&quot;, &quot;reload_method&quot;, &quot;script_object&quot;, &quot;send_private?&quot;, 
 &quot;sender&quot;, &quot;set_eval_local&quot;, &quot;set_iseq&quot;, &quot;sp&quot;, &quot;stack_trace_starting_at&quot;]

ctx.name
#=&gt; :get_mc

ctx.describe
#=&gt; &quot;C\#get_mc&quot;

ctx.method_module
#=&gt; C</code></pre>




<p>Interesting, that reminds me of the monkey-patching discussion that often comes up in the Ruby community. Let&#8217;s try something else:</p>




<pre><code>module ModuleMC
  def module_mc
    MethodContext.current
  end
end
#=&gt; #&lt;CompiledMethod module_mc file=(irb)&gt;

C.include ModuleMC
#=&gt; [ModuleMC]

c.module_mc.method_module
#=&gt; #&lt;IncludedModule:0xd6&gt;

c.module_mc.method_module.name
#=&gt; &quot;ModuleMC&quot;</code></pre>




<p>Wouldn&#8217;t it be nice if we had that kind of introspection, when comes time to debug some mixin magic?</p>




<p>Now let&#8217;s go back our <code>MethodContext</code> object. Or rather, its <code>method</code> accessor, which gives us a <code>CompiledMethod</code> instance:</p>




<pre><code>m = ctx.method
#=&gt; #&lt;CompiledMethod get_mc file=(irb)&gt;

m.interesting_methods
#=&gt; [&quot;__ivars__&quot;, &quot;__ivars__=&quot;, &quot;activate&quot;, &quot;activate_as_script&quot;, 
&quot;as_script&quot;, &quot;child_methods&quot;, &quot;compile&quot;, &quot;decode&quot;, &quot;describe&quot;, 
&quot;exceptions&quot;, &quot;exceptions=&quot;, &quot;file&quot;, &quot;file=&quot;, &quot;first_ip_on_line&quot;, 
&quot;first_line&quot;, &quot;from_string&quot;, &quot;hints&quot;, &quot;hints=&quot;, &quot;inherit_scope&quot;, 
&quot;is_block?&quot;, &quot;iseq&quot;, &quot;iseq=&quot;, &quot;line_from_ip&quot;, &quot;lines&quot;, &quot;lines=&quot;, 
&quot;literals&quot;, &quot;literals=&quot;, &quot;local_count&quot;, &quot;local_count=&quot;, &quot;local_names&quot;, 
&quot;local_names=&quot;, &quot;locate_line&quot;, &quot;min_stack_size&quot;, &quot;name&quot;, &quot;name=&quot;, 
&quot;primitive&quot;, &quot;primitive=&quot;, &quot;private?&quot;, &quot;protected?&quot;, &quot;public?&quot;, 
&quot;required_args&quot;, &quot;required_args=&quot;, &quot;scope&quot;, &quot;scope=&quot;, &quot;send_sites&quot;, 
&quot;serial&quot;, &quot;serial=&quot;, &quot;splat&quot;, &quot;splat=&quot;, &quot;stack_size&quot;, &quot;stack_size=&quot;, 
&quot;total_args&quot;, &quot;total_args=&quot;]

m.describe
#=&gt; &quot;method get_mc: 0 arg(s), 0 required&quot;

m.local_names
#=&gt; #&lt;Tuple: :local_var&gt;

m.literals
#=&gt; #&lt;Tuple: &quot;value&quot;, :MethodContext, #&lt;SendSite:0xda 
#     name=current hits=0 misses=0&gt;&gt;

m.file
#=&gt; :&quot;(irb)&quot;</code></pre>




<p>The <code>local_names</code> method sounds extremely promising, but unfortunately for now, there&#8217;s no primitive for actually getting the local variable&#8217;s value, but it&#8217;s perfectly possible<a href='#footnote_3'><sup>3</sup></a>. It&#8217;s just not been done yet.</p>




<p>By the way, what is that? <code>#describe</code> summarizes the arguments? Let&#8217;s try something more interesting with it:</p>




<pre><code>def method_with_args(arg1, arg2=&#39;default&#39;, *args)
  MethodContext.current
end
#=&gt; #&lt;CompiledMethod method_with_args file=(irb)&gt;

ctx2 = method_with_args(42, &#39;towel&#39;, &quot;don&#39;t panic&quot;)
#=&gt; #&lt;MethodContext:0x16e main#method_with_args (irb):4&gt;

m2 = ctx2.method
#=&gt; #&lt;CompiledMethod method_with_args file=(irb)&gt;

m2.describe
#=&gt; &quot;method method_with_args: 2 arg(s), 1 required, splatted.&quot;

m2.local_names
#=&gt; #&lt;Tuple: :arg1, :arg2, :args&gt;

m2.literals
#=&gt; #&lt;Tuple: &quot;default&quot;, :MethodContext, #&lt;SendSite:0x16c 
#     name=current hits=1 misses=0&gt;&gt;</code></pre>




<p>Nice! Ok, now let&#8217;s come back to our <code>CompiledMethod</code> instance and check out it&#8217;s <code>scope</code> accessor.</p>




<pre><code>ss = m.scope
#=&gt; #&lt;StaticScope:0xea parent=#&lt;StaticScope:0xe8 parent=nil 
#     module=Object&gt; module=C&gt;

ss.interesting_methods
#=&gt; [&quot;initialize&quot;, &quot;module&quot;, &quot;parent&quot;, &quot;script&quot;, &quot;script=&quot;]

ss.parent
#=&gt; #&lt;StaticScope:0xe8 parent=nil module=Object&gt;</code></pre>




<p>So now we&#8217;ve essentially poked 2 levels deep: <code>ctx.method.scope</code>. Let&#8217;s rewind again and look at a our context&#8217;s <code>receiver</code> and <code>sender</code> accessors. To better understand both, let&#8217;s come back to our OO roots of 30 years back and start calling &#8216;method calls&#8217; &#8216;messages&#8217; instead.</p>




<p>sender (sends message &#8216;get_mc&#8217;) =&gt; receiver</p>




<p><code>sender</code> is then the caller of the method, and <code>receiver</code> is, the object receiving the message. Also known as <code>self</code>, during the execution of the method.</p>




<p>Let&#8217;s see that in action:</p>




<pre><code>r  = ctx.receiver
#=&gt; #&lt;C:0xca @inst=42&gt;

r == c
#=&gt; true</code></pre>




<p>So ctx.receiver is a reference to the instance we&#8217;d put in the variable <code>c</code>. From there of course we can do Ruby&#8217;s regular meta-poking around:</p>




<pre><code>r.instance_variable_get &#39;@inst&#39;
#=&gt; 42</code></pre>




<p>Now let&#8217;s look at the sender:</p>




<pre><code>s = ctx.sender
#=&gt; #&lt;BlockContext:0xf0 main#irb_binding (irb):1&gt;

s.class.ancestors
#=&gt; [BlockContext, MethodContext, Object, PP::ObjectMixin, Kernel]

s.interesting_methods - ctx.interesting_methods
#=&gt; [&quot;env&quot;, &quot;home&quot;]

s.home
#=&gt; #&lt;MethodContext:0xf6 main#irb_binding
#     /Users/mat/dev/_rubies/rubinius/rubinius/lib/irb/workspace.rb:1&gt;

s.env
#=&gt; #&lt;BlockEnvironment:0xf8 @initial_ip=0 @last_ip=268435456 
#     @post_send=0 @bonus=#&lt;Tuple: true&gt;&gt;</code></pre>




<p>When calling a method from IRB, we&#8217;re in a BlockContext instead of a MethodContext, but it&#8217;s still in the family.</p>




<pre><code>s = ctx.sender
#=&gt; #&lt;BlockContext:0xfe main#irb_binding (irb):1&gt;

s.class.ancestors
#=&gt; [BlockContext, MethodContext, Object, Kernel]</code></pre>




<p>Anything new we need to know about?</p>




<pre><code>s.interesting_methods - ctx.interesting_methods
#=&gt; [&quot;env&quot;, &quot;home&quot;]

s.home
#=&gt; #&lt;MethodContext:0x102 main#irb_binding
#     /Users/mat/dev/_rubies/rubinius/rubinius/lib/irb/workspace.rb:1&gt;

s.env
#=&gt; #&lt;BlockEnvironment:0xf8 @initial_ip=0 @last_ip=268435456
#     @post_send=0 @bonus=#&lt;Tuple: true&gt;&gt;</code></pre>




<p>All of this is strangely reminiscent of a stack trace. Before you go collecting all senders to explore the execution stack, let me point you to the convenient <code>context_stack</code>:</p>




<pre><code>ctx.context_stack.length
#=&gt; 27

puts *ctx.context_stack
# Too noisy to output here

puts *ctx.context_stack.map{ |s| s.describe }

#=&gt;
# C#get_mc
# Object#irb_binding {}
# Kernel(IRB::WorkSpace)#eval
# IRB::WorkSpace#evaluate
# IRB::Context#evaluate
# IRB::IrbRubinius#process_statements {}
# IRB::Irb(IRB::IrbRubinius)#signal_status
# IRB::IrbRubinius#process_statements {}
# RubyLex#each_top_level_statement {}
# Kernel(RubyLex)#catch {}
# ThrownValue.register
# Kernel(RubyLex)#catch
# RubyLex#each_top_level_statement
# IRB::IrbRubinius#process_statements
# IRB::Irb(IRB::IrbRubinius)#eval_input
# IRB.start {}
# Kernel(Module)#catch {}
# ThrownValue.register
# Kernel(Module)#catch
# IRB.start
# main.__script__
# CompiledMethod#activate_as_script
# CompiledMethod#as_script
# Compile.single_load
# Compile.unified_load
# Kernel(Object)#require
# Object#__script__
# #=&gt; nil</code></pre>




<p>I&#8217;m pretty sure there&#8217;s other areas specific to Rubinius that can be explored like that. Please share any insight in the comments.</p>




<h2 id='sexpressions'>S-Expressions</h2>




<p>Rubinius groks s-expressions out of the box (similar to standard Ruby with <a href='http://parsetree.rubyforge.org/'>ParseTree or ruby_parser</a>. <a href='http://gist.github.com/27156'>An example</a>).</p>




<pre><code>require &#39;pp&#39;
pp sx = &quot;
  class C
    def meth(arg)
      arg * 2
    end
  end&quot;.to_sexp

#=&gt;
# s(:class,
#  :C,
#  nil,
#  s(:scope,
#   s(:defn,
#    :meth,
#    s(:args, :arg),
#    s(:scope,
#     s(:block, s(:call, s(:lvar, :arg), :*, s(:arglist, s(:fixnum, 2))))))))

sx[0]
#=&gt; :class

sx[3][1][1]
#=&gt; :meth</code></pre>




<p>With something that reminiscent to Lisp, it&#8217;s probably better to explore recursively, though.</p>




<p>S-expressions are used by a lot of the Ruby <a href='http://devver.net/blog/2008/10/ruby-tools-roundup/'>code inspection tools</a> to understand your ugly Ruby code.</p>




<h2 id='gems'>Gems</h2>




<p>I won&#8217;t touch trying out gems for today. There seems to be little issues as the moment. They do install, but I&#8217;ve been having problems running them. Please leave a comment if you&#8217;ve had success with specific gems.</p>




<p>If you&#8217;re curious and want to try playing with gems, Rubygems is already installed.</p>




<pre><code>rbx gem install rails --no-rdoc --no-ri</code></pre>




<p>Pro tip: always skip the documentation when playing with gems Rubinius. The doc takes unusually long to compile.</p>




<h2 id='run_the_famous_test_suite'>Run the famous test suite</h2>




<p>The spec suite that&#8217;s been keeping all Ruby implementations honest was born from the Rubinius project. It&#8217;s been split into a separate project a while ago, since it&#8217;s now such an important and central piece of the Ruby ecosystem.</p>




<h3 id='update_the_specs'>Update the specs</h3>




<p>Since they are now in a different project, we first have to get the most recent version. Easy stuff:</p>




<pre><code>rake rubyspec:update</code></pre>




<h3 id='rbx_in_your_path'>rbx in your PATH</h3>




<p>Before you run the specs, you need to do one little thing. One of the specs expects a shell call to rbx to start Rubinius (as in, the executable must be in your path).</p>




<p>The simplest way to do that for now is just to temporarily add the directory to your path (right in your console, not in your .bash_profile).</p>




<pre><code>pwd
#=&gt; /path/to/project/rubinius
export PATH=$PATH:/path/to/project/rubinius/bin
rbx -v</code></pre>




<h3 id='run_the_specs'>Run the specs</h3>




<pre><code>rake spec
# Time for another BRAWNDO!</code></pre>




<p>Or rather, time to actually look at some of the specs you&#8217;re currently running. If you look in the spec directory, you&#8217;ll see that it&#8217;s pretty extensive, to say the least. To start with something familiar, navigate to spec/ruby/1.8, in subdirectories core or library. Open up a few of the specs in there and stare at them for a few minutes. Or better, improve a few of them and try them out on MRI, JRuby and of course, Rubinius.</p>




<h1 id='conclusion'>Conclusion</h1>




<p>Well, now I&#8217;ve tricked you into putting the Rubinius project on your hard drive. And you&#8217;re a Ruby developer. What are you waiting for?</p>




<ul>
<li><a href='http://github.com/evanphx/rubinius/tree/master/doc/contributing.txt'>Contribute</a></li>

<li><a href='http://github.com/evanphx/rubinius/tree/master/doc'>Documentation</a></li>

<li><a href='http://rubinius.lighthouseapp.com/projects/5089-rubinius/overview'>Tickets overview</a></li>
</ul>




<p>I think Rubinius will be an awesome runtime for our Ruby programs. It probably won&#8217;t be <em>only</em> Ruby in the close future, but the kernel of Ruby (base classes &amp; stuff) is mostly implemented in Ruby, and the compiler is also implemented in Ruby. This is awesome to help understand the workings of the language and to lower the barrier to contribution. Which is already pretty low.</p>




<p>Rubinius is here to stay and it&#8217;s gonna keep rocking.</p>




<h1 id='footnotes'>Footnotes</h1>


<ol>
  <li id='footnote_1'>
    Examples of details not up to date in the old articles are: the LOC numbers and the base language of the VM (used to be C, now C++).
  </li>
  <li id='footnote_2'>
    If the build craps out with a message you understand, cool. Try to install the dependency through apt-get or macports/fink, or search your hard drive to see if the tool&#8217;s just not in your PATH. Otherwise, here are a few related pointers.
    <ul>
      <li>
        <a href='http://github.com/evanphx/rubinius/tree/master/doc/getting_started.txt'>Getting Started</a>
      </li>
      <li>
        <a href='http://github.com/evanphx/rubinius/tree/master/INSTALL'>Installation</a>
      </li>
      <li>
        <a href='http://github.com/evanphx/rubinius/tree/master/doc/common_problems.txt'>Common Problems</a>
      </li>
      <li>
        If you can&#8217;t find an answer in the doc, don&#8217;t hesitate and ask on IRC in #rubinius (freenode.org). The crew&#8217;s very friendly.
      </li>
    </ul>
  </li>
  <li id='footnote_3'>
    For a quick discussion about getting local variable&#8217;s values out of a CompiledMethod, check the [IRC logs around 19:20][9].
  </li>
</ol>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[git-config has autocomplete?]]></title>
    <link href="http://www.programblings.com/2008/11/21/git-config-has-autocomplete/"/>
    <updated>2008-11-21T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2008/11/21/git-config-has-autocomplete</id>
    <content type="html"><![CDATA[<p>Seen on a git 1.6.0.4 installation (dunno about previous versions), installed through MacPorts <a href='#footnote_1'><sup>1</sup></a> with the <a href='http://trac.macports.org/wiki/howto/bash-completion'>+bash_completion</a> option.</p>




<pre><code>$ git config #tab
apply.whitespace               core.compression        ...
branch.                        core.fileMode           
clean.requireForce             core.gitProxy           
color.branch                   core.ignoreStat         
color.branch.current           core.logAllRefUpdates   
...</code></pre>




<!-- more -->




<p>With sub-options too, on words ending with a dot:</p>




<pre><code>$ git config remote.origin. #tab
remote.origin.fetch               remote.origin.receivepack      ...
remote.origin.push                remote.origin.skipDefaultUpdate</code></pre>




<p>And as usual, calling git-config with a setting name without specifying a new value displays the current value.</p>




<pre><code>$ git config remote.origin.url
git://github.com/evanphx/rubinius.git</code></pre>




<p>Git&#8217;s getting easier by the day. Awesome!</p>


<p id='footnote_1'>
  1. A recent change from <a href='http://www.programblings.com/2008/11/18/installing-ruby-19preview1-on-os-x-leopard/#comment-914'>a previous position</a>!
</p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Installing ruby 1.9preview1 on OS X Leopard]]></title>
    <link href="http://www.programblings.com/2008/11/18/installing-ruby-19preview1-on-os-x-leopard/"/>
    <updated>2008-11-18T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2008/11/18/installing-ruby-19preview1-on-os-x-leopard</id>
    <content type="html"><![CDATA[<p>Tonight I&#8217;m trying conciseness.</p>




<p><em>Editor&#8217;s note: I failed.</em></p>




<p>I recently decided to test my <a href='http://grb.rubyforge.org/'>git_remote_branch gem</a> with Ruby 1.9, for the heck of it. Well, I was making sure it <a href='http://www.programblings.com/2008/11/14/git_remote_branch-03-awesomeness-for-the-masses/'>ran on a bunch of platforms</a>: Windows, Ruby 1.8.7 and with the most recent Git version (1.6.0.2, <a href='http://git.or.cz/#download'>get it</a>). So it seemed fitting to check it out under Ruby 1.9.</p>




<p>On Leopard, the only missing dependency to Ruby 1.9 is readline 5.2. This article will present the installation of both. And help heat up your apartment.</p>




<!-- more -->




<h3 id='linux_too'>Linux too</h3>




<p>These instructions will mostly work on Linux as well (tried on Ubuntu). There will be a few minor differences though.</p>




<ul>
<li>Make sure you download the original readline from the gnu site and patch it yourself;</li>

<li>Uninstall older versions of Ruby1.9;</li>

<li>Make sure you have the basic dev tools installed, like gcc and make;</li>

<li>Skip the part about installing Xcode :-)</li>
</ul>




<h2 id='prerequisites'>Prerequisites</h2>




<p>You first need to have the Apple developer tools installed on your mac. They&#8217;re available on your installation CD. Put it in, run the installer. It&#8217;s pretty straightforward.</p>




<pre><code># in your terminal
open /Volumes/Mac\ OS\ X\ Upgrade\ DVD/Optional\ Installs/Xcode\ Tools/XcodeTools.mpkg </code></pre>




<p>If you don&#8217;t compile your own stuff often, you may have to set up your PATH variable in your ~/.bash_profile.</p>




<pre><code># file  ~/.bash_profile
export PATH=&quot;/usr/local/bin:$PATH&quot;</code></pre>




<p>Now, prepare a working directory to keep the source close to the corresponding executables.</p>




<pre><code># in your terminal
sudo mkdir -p /usr/local/src
sudo chgrp admin /usr/local/src
sudo chmod -R 775 /usr/local/src
cd /usr/local/src</code></pre>




<p>Once you&#8217;ve set yourself up, if you don&#8217;t care about the details, you can skip to the end for <a href='#cliffs_notes'>the Cliff&#8217;s notes</a>.</p>




<h2 id='installing_readline'>Installing readline</h2>




<p>This one&#8217;s not as straightforward as it could have been. The gzipped readline library available on the gnu site is 12 patches behind. It so happens that the 12th patch fixes a problem with compilation under OS X. So I applied all 12 to the code and repackaged it. The example uses that file, compiled by me.</p>




<p>You can also do do the patching by yourself if you so wish. Here&#8217;s where you can download the readline code:</p>




<ul>
<li>
<p><a href='ftp://ftp.gnu.org/gnu/readline/readline-5.2.tar.gz'>The main file</a></p>
</li>

<li>
<p><a href='ftp://ftp.gnu.org/gnu/readline/readline-5.2-patches'>The patches</a></p>
</li>
</ul>




<p>So let&#8217;s get on with the instructions to install readline from my patched package:</p>




<pre><code># in your terminal
curl -O http://s3.amazonaws.com/webmat-public/readline-5.2-patch012.tar.gz
md5 readline-5.2-patch012.tar.gz
# should be a9f37d2a22d181f8c23c6a320907917d
tar xzf readline-5.2-patch012.tar.gz
cd readline-5.2-patch012

./configure --prefix=/usr/local
make
sudo make install
cd ..</code></pre>




<h2 id='build_ruby_19'>Build Ruby 1.9</h2>




<h3 id='build_options'>Build options</h3>




<p>Note that here you have a few options as to how you want to distinguish your 1.9 stack from your main 1.8 one.</p>




<p>In the following example, I build Ruby with the &#8216;1.9&#8217; suffix, which means all executables will be suffixed with 1.9: ruby1.9, gem1.9, irb1.9, rake1.9 and so on. This approach is ideal for casual use of two versions side by side. If you don&#8217;t care about the details, skip right over the next paragraph.</p>




<p>The industrial approach would be to put ruby in a non standard directory and only add it to your path when you want to use that version (or use the explicit path to invoke executables). To go industrial, you can simply use the <code>--prefix=/usr/local/ruby1.9</code> option and then drop the <code>--program-suffix</code> argument when you run configure for Ruby. This setup is ideal if you really want to have a bunch of versions living side by side (e.g. all 1.9 versions as well as 1.8.7 in addition to the current 1.8.6).</p>




<h3 id='actual_installation_of_ruby_19'>Actual installation of Ruby 1.9</h3>




<p>Pick the most recent version or Ruby 1.9 on the <a href='ftp://ftp.ruby-lang.org/pub/ruby/'>ftp server</a>. At the time of writing, 1.9.1-preview1 is the most recent.</p>




<p>So, still from /usr/local/src:</p>




<pre><code># in your terminal
curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview1.tar.gz
tar xzvf ruby-1.9.1-preview1.tar.gz
cd ruby-1.9.1-preview1
./configure --prefix=/usr/local --program-suffix=1.9 --enable-pthread --with-readline-dir=/usr/local --enable-shared
make
sudo make install</code></pre>




<p>Now you&#8217;re about to see some of the funniest looking progress indicators around. Ruby&#8217;s about making the programmer happy, and it delivers even in the details!</p>




<p>Note: the recent source packages of Ruby1.9 automatically include the documentation, as the end of the make install attests.</p>




<h2 id='try_ruby_19'>Try Ruby 1.9</h2>




<pre><code># in your terminal
ruby1.9 --version
gem1.9 --version
irb1.9</code></pre>




<p>Once inside the Ruby interactive shell,</p>




<pre><code># in irb1.9
RUBY_VERSION
#=&gt; &quot;1.9.1&quot;
stabby = -&gt;(msg=&#39;inside the stabby lambda&#39;) { puts msg }
stabby.call
# =&gt; &quot;inside the stabby lambda&quot;
stabby.call &#39;hello world&#39;
# =&gt; &quot;hello world&quot;</code></pre>




<p>Yep, Ruby 1.9 introduces the very cool stabby lambda syntax. Ruby 1.8&#8217;s lambdas couldn&#8217;t have optional parameters (unless you fiddled with *args). 1.9&#8217;s stabby lambdas can, with a syntax as clean as a simple method definition, as you just experimented.</p>




<p>Now install the gems you use everyday (or kindly make available to your peers) and help make them 1.9 compatible.</p>




<p>For the sake of the stabby lambda!</p>




<p>That&#8217;s it! (Except for those who skipped to the <a href='#cliffs_notes'>Cliff&#8217;s Notes</a>).</p>




<h2 id='cliffs_notes'>Cliff&#8217;s Notes</h2>




<pre><code># Install patched readline
cd /usr/local/src
curl -O http://s3.amazonaws.com/webmat-public/readline-5.2-patch012.tar.gz
md5 readline-5.2-patch012.tar.gz
# should be a9f37d2a22d181f8c23c6a320907917d
tar xzf readline-5.2-patch012.tar.gz
cd readline-5.2-patch012
./configure --prefix=/usr/local
make
sudo make install
cd ..

# Install Ruby1.9
curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-preview1.tar.gz
tar xzvf ruby-1.9.1-preview1.tar.gz
cd ruby-1.9.1-preview1
./configure --prefix=/usr/local --program-suffix=1.9 --enable-pthread --with-readline-dir=/usr/local --enable-shared
make
sudo make install

# Try Ruby 1.9
ruby1.9 --version
gem1.9 --version
irb1.9

# in irb1.9
RUBY_VERSION
stabby = -&gt;(msg=&#39;inside the stabby lambda&#39;) { puts msg }
stabby.call
stabby.call &#39;hello world&#39;</code></pre>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[git_remote_branch is github-agnostic]]></title>
    <link href="http://www.programblings.com/2008/11/17/git_remote_branch-is-github-agnostic/"/>
    <updated>2008-11-17T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2008/11/17/git_remote_branch-is-github-agnostic</id>
    <content type="html"><![CDATA[<p><a href="http://joshknowles.com">Josh Knowles</a> recently suggested that maybe I could merge grb’s functionality to the github gem.</p>

<p>Both gems being command-line tools that help you use Git in a friendlier manner, the question makes a lot of sense. It makes so much sense in fact, that I decided to blog about it. A post about it will scale much better to answer other users who may potentially ask the same question.</p>

<p>So here’s a slightly edited excerpt from the answer I gave him. And yes, I also ramble in email.</p>

<!-- more -->


<blockquote><p>I’ve seen what Scott added to the github gem. Pretty cool stuff indeed. I think the idea of merging with the github gem has merit. I definitely can see a future where we start having too many distinct command-line tools that help deal with Git’s sometimes obscure or numerous commands.</p>

<p>However I’m not sure I’d like to merge grb into the gh gem, despite the additional awareness it would get. Here’s why.</p>

<p>In my mind, the github gem should be mostly features about GitHub itself, like managing pull requests (the way GitHub does them). It’s starting to accumulate features that probably aren’t GitHub-specific, which I don’t mind, of course. But grb’s features really are GitHub-agnostic. I’ve started working on it before I even started using GitHub, in fact :-)</p>

<p>Reinforcing the previous point, I wouldn’t want someone who doesn’t use GitHub to not realize the features of grb are available to him because they’re included in a gem called ‘github’ ;-)</p>

<p>Also, one of the goals of git_remote_branch is to explicitly teach the underlying git commands. I do this by always spewing out the underlying commands in red, and by having the explain command. I’m pretty sure an unsuspecting user would wonder what hit him if a few of the github commands started spewing out red text in his console ;-) Having explain for a few commands (ported from grb) and not for the rest of the github gem’s commands would be weird, too.</p>

<p>There’s also a few other architectural decisions of grb that may not fit with github’s, like having aliases. Once again, grb being a teaching tool, I want to offer a bunch of aliases for forgetful people like me. So far I don’t see anything like aliases in github and I’m not sure how the authors of github-gem would react to a pull request polluting it with a bunch of aliases ;-)</p>

<p>Last but not least, the github gem already has a track command, which conflicts with grb’s. github’s is used to track a new remote repo in your local repo while grb’s is to track another branch from your current remote repo.</p></blockquote>

<p>So git_remote_branch is GitHub-agnostic. You can use it with any Git hosting solution: GitHub, your own <a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way">Gitosis</a> / gitweb / <a href="http://gitorious.org/projects/gitorious">Gitorious installation</a>, <a href="http://gitorious.org">Gitorious.org</a> hosting, Rubyforge or any other.</p>

<p>Better, grb supports working with all of them at the same time. All grb commands support an optional origin argument.</p>

<p><a href="http://grb.rubyforge.org">Learn more about git_remote_branch</a></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[git_remote_branch 0.3 - Awesomeness for the masses]]></title>
    <link href="http://www.programblings.com/2008/11/14/git_remote_branch-03-awesomeness-for-the-masses/"/>
    <updated>2008-11-14T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2008/11/14/git_remote_branch-03-awesomeness-for-the-masses</id>
    <content type="html"><![CDATA[<h2 id="awesomeness_for_the_masses">Awesomeness for the masses</h2>




<p>git_remote_branch 0.3 has been released!</p>




<p>Previous releases were pretty much only usable by rubyists on OS X. </p>




<p><a title="Works on my machine logo" href="http://www.codinghorror.com/blog/archives/000818.html"><img src="http://www.programblings.com/uploads/2008/06/works-on-my-machine.png" alt="Works on my machine logo" /></a></p>




<p>No more. This release is mostly focused on making sure git_remote_branch works on a broader range of platforms. A few actual features squeaked in, but nothing big like introducing new commands.</p>




<!-- more -->




<p>If you don&#8217;t care about the details just type the following at your command-line.</p>




<pre><code>sudo gem install git_remote_branch
</code></pre>




<p>And check the help</p>




<pre><code>grb --help
</code></pre>




<p>If you encounter installation problems, refer to <a href="http://grb.rubyforge.org">the readme</a>.</p>




<h3 id="platforms">Platforms</h3>




<p>git_remote_branch 0.3 has been tested with the following configurations:</p>




<ul>
<li>OS X Leopard / Ruby 1.8.6 / Git 1.5.4.3 and 1.6.0.2</li>
<li>OS X Leopard / Ruby 1.9.1 / Git 1.5.4.3 and 1.6.0.2</li>
<li>Ubuntu Intrepid Ibex / Ruby 1.8.7 / Git 1.5.6.3</li>
<li>Windows XP / Ruby 1.8.6 / Git 1.6.0.2 (the msys version)</li>
</ul>




<h3 id="features">Features</h3>




<h4 id="better_track">Better track</h4>




<p>Track now works even if you already have a local branch of the same name. It uses git config instead of branch &#8212;track in that case. The subtlety can be observed by running (from a git repository):</p>




<pre><code>grb explain track master
grb explain track non_existent_branch
</code></pre>




<h4 id="force_the_use_of_a_specific_git_executable">Force the use of a specific git executable</h4>




<p>Set the environment variable GRB_GIT to point to it and grb will use this one for all its operations.</p>




<h2 id="documentation_">Documentation </h2>




<p>I&#8217;ve also worked quite a bit on the actual documentation. I used to be ashamed at the quality and availability of the documentation of git_remote_branch. At last I&#8217;ll be able to sleep at night :-)</p>




<h3 id="git_remote_branch_in_a_nutshell">git_remote_branch in a nutshell</h3>




<p>I&#8217;ve rewritten the intro of the readme to be (hopefully) a bit clearer.</p>




<blockquote>
  <p>git_remote_branch is a simple command-line tool that makes it very easy to manipulate branches published in shared repositories.</p>
  
  <p>It achieves this goal by sticking to a few principles:</p>
  <ul>
    <li>keep grb&#8217;s commands extremely regular (they all look alike)</li>
    <li>support aliases for commands</li>
    <li>print all commands it runs on your behalf in red, so you eventually learn them</li>
  </ul>
  <p>Another nice thing about git_remote_branch is that it can simply explain a command (print out all the corresponding git commands) instead of running them on your behalf.</p>
  
  <p>Note: git_remote_branch assumes that the local and 
  remote branches have the same name. Multiple remote 
  repositories (or origins) are supported.</p>
</blockquote>




<h3 id="documentation_availability">Documentation availability</h3>




<p>The main readme is now available on the main <a href="http://grb.rubyforge.org">grb page on rubyforge</a>.</p>




<h3 id="documentation_quality">Documentation quality</h3>




<p>I&#8217;ve added clearer information on getting grb to run in different kinds of situation, due to helpful feedback from <a href="http://github.com/axelson">Axelson</a> and <a href="http://github.com/grempe">Glenn Rempe</a>.</p>




<p>I&#8217;ve also added some information for playing with the code for git_remote_branch (test dependencies and so on). See the end of <a href="http://grb.rubyforge.org">the readme</a>.</p>




<p>Finally, I&#8217;ve updated the links section quite a bit:</p>




<table>
  <tr>
    <th>Documentation</th>
    <td><a href="http://grb.rubyforge.org">http://grb.rubyforge.org</a></td>
  </tr>
  <tr>
    <th>News</th>
    <td><a href="http://www.programblings.com/category/git/git\_remote\_branch/">/category/git/git_remote_branch/</a></td>
  </tr>
  <tr>
    <th>Bug tracker</th>
    <td><a href="http://git-remote-branch.lighthouseapp.com/projects/19198-git\_remote\_branch/overview">Lighthouse</a></td>
  </tr>
  <tr>
    <th>Code</th>
    <td><a href="http://github.com/webmat/git_remote_branch">http://github.com/webmat/git_remote_branch</a></td>
  </tr>
  <tr>
    <th>Mailing list</th>
    <td><a href="http://groups.google.com/group/git_remote_branch">http://groups.google.com/group/git_remote_branch</a></td>
  </tr>
</table>




<h2 id="dare">Dare</h2>




<p>I dare you to find a platform on which git_remote_branch doesn&#8217;t work :-)</p>




<p>If you do, please send me feedback through GitHub or via email. I&#8217;m using gmail and, as usual, I go by the handle of webmat.</p>




<h3 id="last_note_the_git_remote_branch_gem_on_github">Last note: the git_remote_branch gem on GitHub</h3>




<p>Excerpt from the readme:</p>




<blockquote>
  <p>Note that the only stable version of the gem you should trust is the one from <strong>Rubyforge</strong>. The GitHub gem is a development gem. The GitHub gem WILL be rebuilt with the same version number, and other horrible things like that. If you use the GitHub version of git_remote_branch, children will die!</p>
</blockquote>




<p>You&#8217;ve been warned.</p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Installing gems with command-line interfaces on Ubuntu 8.10]]></title>
    <link href="http://www.programblings.com/2008/11/04/installing-gems-with-command-line-interfaces-on-ubuntu-810/"/>
    <updated>2008-11-04T00:00:00-05:00</updated>
    <id>http://www.programblings.com/2008/11/04/installing-gems-with-command-line-interfaces-on-ubuntu-810</id>
    <content type="html"><![CDATA[<p>To install any ruby gem which has a command-line interface on Ubuntu 8.10, you have to add a path to your PATH environment variable. In your .bashrc file, add the following line:</p>

<pre>export PATH=$PATH:/var/lib/gems/1.8/bin</pre>


<p>Also worth noting is the fact that the default ruby interpreter on 8.10 is back to the 1.8 branch: it&#8217;s 1.8.7 (1.9 was the default on 8.04 iirc). 1.9  also be installed right besides 1.8.</p>

<pre>$ ruby --version
ruby 1.8.7 (2008-08-11 patchlevel 72) [i486-linux]
$ ruby1.9 --version
ruby 1.9.0 (2008-06-20 revision 17482) [i486-linux]</pre>


<p>Neither comes installed by default, however. You must install them explicitly.</p>

<pre>sudo aptitude install ruby irb rubygems</pre>


<p>While I&#8217;m at it, why not mention that rubygems 1.2.0 is installed by default. It doesn&#8217;t want to update to 1.3.0 with the usual &#8220;gem update &#8211;system&#8221; command. Since it&#8217;s not my main machine I didn&#8217;t investigate further, but the suggestion is to use apt-get or aptitude. The repos don&#8217;t seem to be up to date with 1.3.0, but rather with a version named something like 1.3.0really1.2.0.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Two Shoulda best practices]]></title>
    <link href="http://www.programblings.com/2008/10/31/two-shoulda-best-practices/"/>
    <updated>2008-10-31T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/10/31/two-shoulda-best-practices</id>
    <content type="html"><![CDATA[<h2 id="in_praise_of_shoulda_macros">In praise of Shoulda macros</h2>


<p>Shoulda contexts let you to share setup code between different tests. This is for me one of Shoulda’s most attractive features.</p>

<p>When you combine this with the technique of defining your own macros to encapsulate assertions or setups that come up often, you end up with seriously DRY and readable tests.</p>

<!-- more -->


<p>I see a few different kinds of Shoulda macros:</p>

<h3 id="assertion_macros">Assertion macros</h3>


<p>Assertions macros often begin with should_. They encapsulate one or a few assertions.</p>

<p>For ActiveRecord models:</p>

<pre><code>should_require_attributes :name, :phone_number
</code></pre>


<p>They may even accept a block and do assertions on its execution, like <a href="http://www.programblings.com/2008/10/27/this-should_raise-an-exception/">should_raise</a>:</p>

<pre><code>should_raise(LoadError, :message =&gt; /vespene/) do
  require "more vespene gas"
end
</code></pre>


<p>To learn more about assertion macros, you can take a look at <a href="http://technicalpickles.com/posts/shoulda-macros-allows-you-to-embrace-your-inner-slacker">Shoulda macros allows you to embrace your inner slacker</a> by Josh Nichols. Inner slacker? I’m right there!</p>

<h3 id="setup_macros">Setup macros</h3>


<p>This kind of macro encapsulates a setup that comes up often in your test suite. One inspired by Restful Authentication’s login_as helper method could be used like this:</p>

<pre><code>logged_in_as :mat do
  # Shoulda tests
end
</code></pre>


<p>These kinds of macros accept a block that defines more Shoulda tests, rather than a block of code testing your app per se.</p>

<h3 id="turnkey_macros">Turnkey macros</h3>


<p>Turnkey macros are beefed up assertion macros. The main difference is their extent. They contain many contexts and a lot of should blocks. They usually accept substantial options hashes or are configured with a setup block. Like should_be_restful in the following example, inspired by the Shoulda documentation:</p>

<pre><code>logged_in_as :stranger do
  should_be_restful do |resource|
    resource.create.params   = { :subject =&gt; "test", :body =&gt; "message" }
    resource.denied.actions  = [:edit, :update, :destroy]
    resource.denied.redirect = "login_url"
    resource.denied.flash    = /only the owner can/i
  end
end
</code></pre>


<h2 id="two_shoulda_best_practices_around_setup_macros">Two Shoulda best practices around setup macros</h2>


<p>This article is specifically about setup macros.</p>

<p>Here’s the implementation of a pretty generic Shoulda macro I could define in my test_helper<a href="#footnote_star">*</a>. This is an implementation of the macro I mentioned at the beginning:</p>

<pre><code># Sets the current person in the session from the person fixtures.
def self.logged_in_as(person, &amp;block)
  context "logged in as #{person}" do
    setup do
      @request.session[:person] = people(person).id
    end

    yield
  end
end
</code></pre>


<p>Which can then be used like this in any controller test:</p>

<pre><code>logged_in_as :mat do
  # tests for users
end

logged_in_as :admin do
  # tests for admin
end
</code></pre>


<p>Setup macros have a very subtle catch, however. Here’s a modified version of the first example above:</p>

<pre><code>logged_in_as :mat do
  setup do
    @request.session[:last_login] = Time.now
  end
  # Some tests
end
</code></pre>


<p>The setup block you see here is never going to be executed. Why?</p>

<p>If we were to replace the logged_in_as macro by the actual code it contains, here’s what it would look like:</p>

<pre><code>context "logged in as #{person}" do
  setup do
    @request.session[:person] = people(person).id
  end
  setup do
    @request.session[:last_login] = Time.now
  end
  # Some tests
end
</code></pre>


<p>Does that make sense? Not so sure.</p>

<p>Shoulda doesn’t like to have multiple setup blocks for a given context. That part <em>does</em> make sense.</p>

<h2 id="best_practice_1_always_describe_the_situation_with_a_context">Best practice #1: Always describe the situation with a context.</h2>


<p>You should always describe the situation in which your test takes place (what your setup is doing) with a context.</p>

<pre><code>logged_in_as :mat do
  context "with last login set to now" do
    setup do
      @request.session[:last_login] = Time.now
    end
    # Some tests
  end
end
</code></pre>


<p>Fair enough. We blame it on the user of the macro :-)</p>

<p>Since we’re using Ruby, most of us are probably in agreement with Matz’ “Make the programmer happy” motto.</p>

<p>So can we also solve the problem from the other end? Create a setup macro that supports a direct inner setup block? Of course we can, this is <strong>Ru</strong>by, not <strong>V</strong>B.</p>

<h2 id="best_practice_2_create_setup_macros_that_support_a_second_setup_block">Best practice #2: Create setup macros that support a second setup block</h2>


<p>A setup is grafted to a context that describes it. As the creator of the macro, I don’t know what crazy setup blocks programmers will put inside their macro. So I simply create a mute context:</p>

<pre><code># Sets the current person in the session from the person fixtures.
def self.logged_in_as(person, &amp;block)
  context "logged in as #{person}" do
    setup do
      @request.session[:person] = people(person).id
    end

    context '' do
      yield
    end
  end
end
</code></pre>


<p>Now my macro supports the following test without a hitch:</p>

<pre><code>logged_in_as :mat do
  setup do
    @request.session[:last_login] = Time.now
  end
  # Some tests
end
</code></pre>


<p>And of course, programmers who stick to best practice #1 can still write a cleaner test without a problem. The awesomeness of contexts lies in the fact that they can be nested:</p>

<pre><code>logged_in_as :mat do
  context "with last login set to now" do
    setup do
      @request.session[:last_login] = Time.now
    end
    # Some tests
  end
end
</code></pre>


<h2 id="conclusion">Conclusion</h2>


<p>Best practice #1 is simple. A setup block should be described by its encompassing context. It’s a question of readability. Nesting a setup block immediately inside a Shoulda macro is a dubious practice.</p>

<p>Best practice #2 is a more pragmatic solution to the problem. Ok, nesting a block right inside a macro isn’t always the best idea.</p>

<p>But when you don’t have the macro right under your nose, it may take you a while before you think about looking at said macro. I don’t know about you, but I have a tendency to have a great deal of confidence in macros that work well across my test suite.</p>

<p>So after you’ve spent an hour questioning Shoulda (or your sanity, or whether you should have become a gardener instead of a software developer) because your setup block isn’t executing, best practice #2 starts to make sense.</p>

<p>It may or may not be necessary in all your setup macros. I find it’s especially useful for macros that are generic enough to be used across your test suite. Or most of all, in setup macros you will share with the world.</p>

<p>Best practice #2 makes setup macros bulletproof to the problem of multiple setups.</p>

<p>Now go refactor your setup macros!</p>

<p>To learn more about Shoulda, check out <a href="http://thoughtbot.com/projects/shoulda">Thoughtbot’s comprehensive documentation</a>.</p>

<p id="footnote_star">* A note on where to define Shoulda macros. Shoulda 2 can now auto load macros that are in the right location. This will help you keep your test_helper cleaner. Read more about it succinctly in <a href="http://technicalpickles.com/posts/shoulda-can-automatically-load-custom-macros">Shoulda can automatically load custom macros</a> by Josh Nichols or in the <a href="http://giantrobots.thoughtbot.com/2008/9/30/shoulda-2-0">Shoulda 2.0 release post</a>.</p>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[This should_raise an exception]]></title>
    <link href="http://www.programblings.com/2008/10/27/this-should_raise-an-exception/"/>
    <updated>2008-10-27T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/10/27/this-should_raise-an-exception</id>
    <content type="html"><![CDATA[<p>If you use Shoulda and, like me, you hate Test::Unit’s assert_raise(), I may have something of interest for you.</p>

<h2 id="why_the_hate">Why the hate?</h2>


<p>Well, assert_raise accepts an <code>*args</code> list of exception types.</p>

<p>If you don’t pass any, you get some nonsense because an empty array doesn’t jive with the exception raised by your block. Useful. So if you don’t care what exception is raised, assert_raise isn’t gonna help you.</p>

<p>Also, assert_raise doesn’t let you specify what kind of exception message you’re expecting. I actually don’t mind that a given assertion should verify exactly one thing. On the other hand I have to jump through hoops to capture the exception if I want to assert on the error message.</p>

<!-- more -->




<h2 id="a_shoulda_macro_to_the_rescue">A shoulda macro to the rescue</h2>


<p>As usual, Shoulda is there to help us keep our test code DRY and intuitive. I’ve concocted a useful macro called should_raise. <a href="http://gist.github.com/20019">Here’s the gist</a>:</p>

<p>It must be called with the block you expect to raise an exception, of course. You can also specify two optional arguments, the exception type and the message.</p>

<h3 id="kindof_or_instanceof">:kind_of or :instance_of</h3>


<p>If not specified, an assertion is made that an exception was raised, but with no restriction on the type of the exception.</p>

<p>If you specify :kind_of, the assertion will be that much more precise. It will check that the exception raised was of the type specified, or a descendant.</p>

<p>If you specify :instance_of, the assertion is now that the exception raised was <em>exactly</em> of the type specified.</p>

<p>A shorthand is also available, where the type of the exception is supplied directly, like should_raise(LoadError), in which case the assertion is the same as with :instance_of.</p>

<p>In all of these cases, exactly one assertion is generated, whether or not :type is specified.</p>

<h3 id="message">:message</h3>


<p>If :message is specified, a second assertion will be added in order to make sure the error message matches the parameter. This can either be a string or a regex. The assertion is simply an assert_match.</p>

<p>If not specified, no assertion is generated for the message.</p>

<h2 id="examples">Examples</h2>


<pre><code><strong>should_raise do
  require "more vespene gas"
end
# 1 assertion

should_raise(LoadError) do
  require "more vespene gas"
end
# 1 more restrictive assertion

should_raise(:instance_of =&gt; LoadError) do
  require "more vespene gas"
end
# 1 assertion, the same as should_raise(LoadError)

should_raise(:kind_of =&gt; ScriptError) do
  require "more vespene gas"
end
# 1 assertion, slightly less strict than with :instance_of (note: LoadError &lt; ScriptError)

should_raise(:message =&gt; "no such file to load") do
  require "more vespene gas"
end
# 2 assertions

should_raise(:message =&gt; /vespene/) do
  require "more vespene gas"
end
# 2 assertions

should_raise(LoadError, :message =&gt; "such file to load") do
  require "more vespene gas"
end
# 2 assertions

should_raise(:kind_of =&gt; LoadError, :message =&gt; "file to load") do
  require "more vespene gas"
end
# 2 assertions

should_raise(:instance_of =&gt; LoadError, :message =&gt; "to load") do
  require "more vespene gas"
end
# 2 assertions
</strong></code></pre>


<h2 id="conclusion">Conclusion</h2>


<p>As you can tell, I’m eagerly awaiting <a href="http://www.starcraft2.com/">Starcraft II</a>.</p>

<p>No, I meant: check out the code on <a href="http://gist.github.com/20019">gist 20019</a>. I’ve included a reasonable suite of unit tests in a comment at the end.</p>

<p>Feel free to use it in any way you like. Just make sure you don’t sue me.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Git global ignores]]></title>
    <link href="http://www.programblings.com/2008/10/22/git-global-ignores/"/>
    <updated>2008-10-22T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/10/22/git-global-ignores</id>
    <content type="html"><![CDATA[<p>I don’t know about you, but for me, using git is so low-friction that I use it basically for everything where I may need a powerful undo button. In other words, I don’t use it only for team software development projects.</p>

<p>For example, I’ve frequently used it in the past to keep track of the modifications I make to an article I work on for few days. God knows <a href="http://www.programblings.com/2008/04/01/rubinius-for-the-layman-part-1-rubies-all-the-way-down/">I</a> <a href="http://www.programblings.com/2008/04/15/rubinius-for-the-layman-part-2-how-rubinius-is-friendly/">write</a> <a href="http://www.programblings.com/2008/06/07/the-illustrated-guide-to-recovering-lost-commits-with-git/">a</a> <a href="http://www.programblings.com/2008/06/23/git-remote-branches/">lot</a> <a href="http://www.programblings.com/2008/07/21/setting-up-a-long-term-fork-with-git/">of</a> <a href="http://www.programblings.com/2008/08/06/time-to-git-collaborating-with-git_remote_branch/">these</a>. There’s a reason I called this blog Prog<strong>ramblings</strong> ;-)</p>

<p>To be honest, I’m using git as I write even this short article.</p>

<!-- more -->


<p>I also use it for trivial one evening coding projects. As soon as I spend more than an hour on code, whatever it is, I’ll usually create a local git repo for it.</p>

<p>One of the annoying things I realized when creating repositories more and more often, is that I always ended up ignoring the same files. Over and over again. Boring.</p>

<p>Fortunately for me, git can be configured to take into consideration a global ignore file. Heck, I can even create a system-wide ignore file if I want (check out git config’s doc for more info).</p>

<h2 id="configure_your_personal_ignore_file">Configure your personal ignore file</h2>


<p>I like to stick to conventions so I call my file .gitignore, and I put it in my home directory. But that’s up to you, really.</p>

<pre><code>git config --global core.excludesfile ~/.gitignore
</code></pre>


<p>Note that there’s one little gotcha to be aware of. If you prefer to edit the .gitconfig file directly (or if you use a weird shell), git expects an absolute path. In the example above, bash converted the ~ shorthand to my home directory.</p>

<p>Now I just add ignore globs to it like any other project level (directory level, really) git ignore file.</p>

<pre><code>echo .DS_Store &gt;&gt; ~/.gitignore
</code></pre>


<p id="you8217ll_still_have_to_ignore">Once I&#8217;ve ignored all my favorite useless files, I can get cracking and never worry about them again.</p>




<h2>I still have to ignore files</h2>


<p>When I create a new repository on which people may actually contribute, I’ll still create a proper ignore file, however. Otherwise I’d convey the message that I consider contributors as slaves who only deserve the boring work of creating ignore files. Since I’m pure of heart, that’s not how I roll.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Discovering great tools - qgit]]></title>
    <link href="http://www.programblings.com/2008/09/19/discovering-great-tools-qgit/"/>
    <updated>2008-09-19T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/09/19/discovering-great-tools-qgit</id>
    <content type="html"><![CDATA[<p>I can&#8217;t believe I hadn&#8217;t taken the time to try out <a href="http://digilander.libero.it/mcostalba/">qgit</a> yet. Check this out:</p>

<figure style="text-align:center">
  <a href="http://www.programblings.com/uploads/2008/09/qgit.png"><img  style="width:500px; height:358px;"
    title="qgit" src="http://www.programblings.com/uploads/2008/09/qgit.png" alt="Screenshot of the main qgit screen"/></a>
  <p>Screenshot of the main qgit screen</p>
</figure>


<p>Install qgit from source on Leopard with <a href="http://rails.wincent.com/wiki/Installing_QGit_2.0rc1_on_Mac_OS_X_Tiger">these instructions</a>.</p>

<p>Warning: installing the Qt 4.3 prerequisite takes an eternity or two (instructions for that are included as well).</p>

<p>Also note that you should make sure to use the newest versions of the downloads: the instructions point to an old 2.0rc1 release of qgit.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Time to git collaborating with git_remote_branch]]></title>
    <link href="http://www.programblings.com/2008/08/06/time-to-git-collaborating-with-git_remote_branch/"/>
    <updated>2008-08-06T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/08/06/time-to-git-collaborating-with-git_remote_branch</id>
    <content type="html"><![CDATA[<h2>git_remote_branch 0.2.6 is out!</h2>


<p>I&#8217;ve just released a new and improved version of git_remote_branch. Code named 0.2.6!</p>

<p>Ok, I admit. I haven&#8217;t really begun using code names.</p>

<p>I&#8217;m promoting the project from a pre-alpha to an alpha release. There&#8217;s still a lot to do, but the stability and &#8220;testedness&#8221; have improved greatly. Following are both sides of the maturity story.</p>

<!-- more -->




<h3>The project is maturing</h3>


<ul>
    <li>grb got its first contributor, <a href="http://github.com/kch">Caio Chassot</a></li>
    <li>I added a lot of tests, both unit and functional
<ul>
    <li> there might even be <a href="http://github.com/webmat/git_remote_branch/tree/master/test/helpers/shoulda_functional_helpers.rb#L40">interesting</a> <a href="http://github.com/webmat/git_remote_branch/tree/master/vendor/capture_fu.rb">stuff</a> to see in there for those who need to test command-line tools</li>
</ul>
</li>
    <li> the gem can now be installed directly from RubyForge</li>
    <li> git_remote_branch now has a <a href="http://groups.google.com/group/git_remote_branch">Google Group</a></li>
</ul>


<h3>The project is still immature</h3>


<ul>
    <li>it swears a lot</li>
    <li>no rubyforge page, despite the project being on rubyforge (at <a href="http://rubyforge.org/projects/grb/">rubyforge.org/projects/grb</a>)</li>
    <li>no real documentation other than running grb help</li>
    <li>very little in code documentation. On the other hand the code is spectacularly clean and readable, so that&#8217;s completely unnecessary. Just kidding.</li>
</ul>


<h3>What&#8217;s new in 0.2.6?</h3>


<p>Three new actual features</p>

<ul>
    <li>the &#8216;rename&#8217; command, contributed by Caio Chassot</li>
    <li>the &#8216;publish&#8217; command</li>
    <li>the −−silent option to completely mute grb output as well as every git command run by grb on your behalf</li>
</ul>


<p>And other stuff</p>

<ul>
    <li>the grb bin file now works when symlinked (also thanks to Caio Chassot)</li>
    <li>lots of unit and functional tests</li>
    <li>bug fixes</li>
    <li>more flexibility for running grb outside of a git repository (e.g. for &#8216;explain&#8217; or &#8216;help&#8217;)</li>
    <li>now officially under the MIT license</li>
    <li>refactored a bunch of rake tasks</li>
</ul>


<h2>Git the new version</h2>


<p>To install the newest version of the gem, simply run</p>

<pre><strong>sudo gem install git_remote_branch</strong></pre>


<p>If you really want to be on the bleeding edge you can also get it on GitHub. Note however that in &#8216;bleeding edge&#8217; the word &#8216;bleeding&#8217; is still the most important one at that point.</p>

<pre><strong>git clone git://github.com/webmat/git_remote_branch.git
cd git_remote_branch
rake install</strong></pre>


<p>The &#8216;install&#8217; task will run the tests before installing so you&#8217;ll need Shoulda, mocha, redgreen and ruby-debug for that approach.</p>

<h2>Not familiar with git_remote_branch?</h2>


<h3>What it is</h3>


<p>The basic idea for git_remote_branch is to trivialize the interaction with remote branches. The first goal is to make the commands for the simple situations easy.</p>

<p>The secondary goal, is to help you learn the commands by seeing them displayed in a beautiful shade of red each time you use grb, along with git&#8217;s output.</p>

<p>git_remote_branch lets you</p>

<ul>
    <li><strong>create</strong> local-remote branche pairs, and tracks the remote branch automatically (for automatic merges when you git pull)</li>
    <li><strong>publish</strong> a local branch as a remote branch, very similar to create</li>
    <li><strong>delete</strong> local-remote branch pairs</li>
    <li><strong>track</strong> a remote-only branch</li>
    <li><strong>rename</strong> a local-remote branch pair</li>
    <li><strong>explain</strong> by simply spitting out the necessary commands to do any of the above</li>
</ul>


<h3>How to use it</h3>


<h4>explain</h4>


<p>If you simply want to use grb as a cheatsheet (and run nothing on your behalf), you can use the explain command:</p>

<pre><strong>$ grb explain create
git_remote_branch version 0.2.6

List of operations to do to create a new remote branch and track it locally:

<span style="color: #ff0000;">git push origin current_branch:refs/heads/branch_to_create
git fetch origin
git branch −−track branch_to_create origin/branch_to_create
git checkout branch_to_create</span></strong></pre>


<p>or</p>

<pre><strong>$ grb explain create my_branch my_origin
git_remote_branch version 0.2.6

List of operations to do to create a new remote branch and track it locally:

<span style="color: #ff0000;">git push my_origin current_branch:refs/heads/my_branch
git fetch my_origin
git branch −−track my_branch my_origin/my_branch
git checkout my_branch</span></strong></pre>


<p>Notice that you can specify any normally expected parameter you&#8217;d normally include and &#8216;explain&#8217; will use them in the list of commands it suggests.</p>

<p>Even better, if you&#8217;re in your repository, the current branch is going to be taken into account:</p>

<pre><strong>(master) $ grb explain create my_branch my_origin
git_remote_branch version 0.2.6

List of operations to do to create a new remote branch and track it locally:

<span style="color: #ff0000;">git push my_origin master:refs/heads/my_branch
git fetch my_origin
git branch −−track my_branch my_origin/my_branch
git checkout my_branch</span></strong></pre>


<p>Of course, &#8216;explain&#8217; works for all commands: create, publish, delete, track and rename.</p>

<h4>The main commands</h4>


<p>I&#8217;m not going to painstakingly give an example for each command. I&#8217;ll only give two, to show how git&#8217;s responses are displayed when running grb without &#8216;explain&#8217;:</p>

<pre><strong>(master)$ grb create test_branch
git_remote_branch version 0.2.6

<span style="color: #ff0000;">git push origin master:refs/heads/test_branch</span>
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:webmat/git_remote_branch.git
 * [new branch]      master -&gt; test_branch

<span style="color: #ff0000;">git fetch origin</span>

<span style="color: #ff0000;">git branch −−track test_branch origin/test_branch</span>

<span style="color: #ff0000;">git checkout test_branch</span>
Switched to branch "test_branch"

(test_branch)$ grb delete test_branch
git_remote_branch version 0.2.6

<span style="color: #ff0000;">git push origin :refs/heads/test_branch</span>
To git@github.com:webmat/git_remote_branch.git
 - [deleted]         test_branch

<span style="color: #ff0000;">git checkout master</span>
Switched to branch "master"

<span style="color: #ff0000;">git branch -d test_branch</span>

(master) $ </strong></pre>


<p>Yes my friends, I have just boldly used grb on my real repository for your viewing pleasure.</p>

<p>But worry not, no repository was hurt during the writing of this article.</p>

<h2>Feedback</h2>


<p>For any feedback you&#8217;re of course welcome to</p>

<ul>
    <li>comment on this article</li>
    <li>post in <a href="http://groups.google.com/group/git_remote_branch">the google group</a></li>
</ul>


<h2>Thanks</h2>


<ul>
    <li>To Caio Chassot for the code contribution</li>
    <li> To the Thin team for a good inspiration on how to help manage gem creation and deployment with rake;</li>
    <li> Feedback from <a href="http://jamesgolick.com">James Golick</a> in day to day collaboration as well as all the people that commented on the <a href="http://www.programblings.com/2008/06/23/git-remote-branches/">initial announcement of git_remote_branch</a>;</li>
    <li> To Chris Wanstrath (defunkt) from the GitHub team for <a href="http://github.com/blog/98-git-remote-branch">pimping of the initial announcement</a> of grb on the GitHub blog.</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Setting up a long term fork with Git]]></title>
    <link href="http://www.programblings.com/2008/07/21/setting-up-a-long-term-fork-with-git/"/>
    <updated>2008-07-21T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/07/21/setting-up-a-long-term-fork-with-git</id>
    <content type="html"><![CDATA[<h2>The context</h2>


<p>Recently at GiraffeSoft we started a new project, based on another existing project we already had going. We could call this a long term fork. Let me give you a little bit more context on the situation.</p>

<ul>
    <li>These projects will both keep being actively developed in the future;</li>
    <li>They will have some fundamental differences that will not be reconciled;</li>
    <li>They will however keep many similarities and we expect that they will benefit from the exchange of some specific patches, as development on both moves forward.</li>
</ul>


<p>In days past, this problem could have been solved reasonably well by cloning the central repository and then exchanging patches and applying them manually.</p>

<p>As you&#8217;ve guessed already, we&#8217;ve decided to try using Git to help manage this long term relationship.</p>

<!-- more -->


<p>I must warn you however. It&#8217;s the first time we attempt keeping a long term fork like that. We&#8217;re not sure whether it&#8217;s going to be worth the trouble and whether the diverging of the two projects will eventually prevent us from efficiently benefiting from using Git to manage the exchange of patches. We&#8217;re not sure whether this is the best way to accomplish this either.</p>

<p>On one hand, all this trouble may or may not be worth the effort. On the other hand, all of this sounds like ultra elite Git-fu. Hence our decision to explore this approach.</p>

<p>Another less technical reasons was also at play in our decision. We wanted to have one wiki per project on GitHub :-)</p>

<h2>What we&#8217;re going to do</h2>


<p>So at first, we have a remote repository for the initial project. There are of course an arbitrary number of client side clones of the repository (what Subversion calls working directories). None of them will be affected in any way.</p>

<p>The first thing I will do is clone the initial project to a new client side repository. I&#8217;ll set this up in such a way that it won&#8217;t use the initial project as its default origin. On the other hand I&#8217;ll make sure it has one branch that interacts with the initial project for future patch exchanges.</p>

<p>Then from that client-side repository, I&#8217;ll initialize a new remote repository, which will serve as the default remote repository for the new project.</p>

<p>What we&#8217;ll end up with is 2 remote repositories which will have a lot in common but won&#8217;t be linked to one another in any way. It won&#8217;t be a GitHub fork, for instance.</p>

<p>There will be exactly one client side repository that knows about the two central repos and that can exchange commits between them. All other new client-side clones of the new project will be plain old regular Git clones.</p>

<p>It would be easy to set up more client side repositories to be aware of both repositories, but to me it doesn&#8217;t really seem necessary.</p>

<h3>Article too long?</h3>


<p>As with my previous articles about Git, I&#8217;ll provide detailed instructions for you to follow along on dummy repositories (if you&#8217;re interested). When you return to this article to attempt something similar, you may want to skip to the <a href="#executive-summary">executive summary</a> section, where I list strictly the important operations without all the rambling.</p>

<h2>The instructions with the rambling</h2>


<h3>Setting up a dummy initial project</h3>


<p>Find yourself a comfortable directory and run these few commands to initiate a dummy client-side repository and its corresponding dummy remote:</p>

<pre><strong>mkdir test; cd $_
mkdir initial_project initial_wd
GIT_DIR=initial_project/ git init

# Creating a dummy repo
cd initial_wd
git init
echo foo &gt; file.txt
git add .
git commit -a -m "initial commit"
echo bar &gt;&gt; file.txt
git commit -a -m "modification"

# Setting up what's gonna be the central repo for our initial app
git remote add origin ../initial_project/
git push origin master

git config branch.master.remote origin
git config branch.master.merge refs/heads/master</strong></pre>


<p>The last 2 config commands configure your master branch to automatically track remote master when issuing the command &#8216;git pull&#8217;. In other words, it&#8217;s equivalent to running the command &#8216;git branch −−track master origin/master&#8217;, with the only difference being that &#8216;branch −−track&#8217; is primarily intended to create a new local branch, whereas here we already have our local branch.</p>

<p>We can now check for the expected behavior:</p>

<pre><strong>#   mat@mm initial_wd (master)$ git pull
#   Already up-to-date.</strong></pre>


<p>Note also that here I simplify the instructions for following along by creating a dummy remote repository that&#8217;s in fact only in another local directory. If for example you wanted to use GitHub, your Git remote command would simply look like:</p>

<pre><strong>git remote add origin git@github.com:username/initial_project.git</strong></pre>


<h3>The actual fork</h3>


<pre><strong># Create a directory to host the new remote repository
cd ..
mkdir project2
GIT_DIR=project2/ git init</strong></pre>


<p>Now we will use Git clone with the -o option. This lets us give the initial project another name than the default &#8216;origin&#8217;. We&#8217;ll want to use the name &#8216;origin&#8217; for the new repository we&#8217;ll create to actually track the new project. I decided to name it the initial project&#8217;s origin &#8216;ip_origin&#8217;.</p>

<pre><strong># Specify origin name, then the path to the shared repo
# and finally a directory name for the local working directory.
git clone -o ip_origin initial_project wd</strong></pre>


<h4>Setting up the relationship with the initial repository</h4>


<p>We first create a branch specifically to track the initial project&#8217;s master branch. Then we set it up to track the initial project.</p>

<pre><strong>cd wd
git branch ip_master
git config branch.ip_master.remote ip_origin
git config branch.ip_master.merge refs/heads/master</strong></pre>


<h4>Setting up the relationship with the new project&#8217;s repository</h4>


<pre><strong>git remote add origin ../project2
git push origin master

git config branch.master.remote origin
git config branch.master.merge refs/heads/master</strong></pre>


<h4>Let&#8217;s pretend some new development happened</h4>


<pre><strong>echo 'shareable modification' &gt; shareable_file.txt
git add shareable_file.txt
git commit -m "shareable modification"

echo "specific to new project" &gt; not_shareable.txt
git add not_shareable.txt
git commit -m "specific to new project"</strong></pre>


<p>So I have now begun working on the new project and I already have one commit that could benefit the initial project as well. The progress looks a little like this:</p>

<p><img src="http://www.programblings.com/uploads/2008/07/ltf-gitk-new-development.png" alt="A look at gitk’s representation of the new development" height="61" width="468" /></p>

<p>So I switch to the branch that manages the relationship with the initial project and I pick the commit before the last one in master.</p>

<pre><strong>git checkout ip_master
git cherry-pick master^</strong></pre>


<p><img src="http://www.programblings.com/uploads/2008/07/ltf-gitk-common-modification-now-in-ip_master.png" alt="Gitk, after cherry-picking one commit" height="71" width="396" /></p>

<p>Everything&#8217;s dandy so far, except for the subtle fact that I have brought us all to the edge of a cliff.</p>

<p>If I tried to push to the initial repository right now, I&#8217;d be in for a nasty surprise:</p>

<pre><strong>#   mat@mm wd (ip_master)$ git push
#   Counting objects: 7, done.
#   Compressing objects: 100% (4/4), done.
#   Writing objects: 100% (6/6), 564 bytes, done.
#   Total 6 (delta 1), reused 0 (delta 0)
#   Unpacking objects: 100% (6/6), done.
#   To /Users/mat/blog/long-term-fork/test/initial_project
#      7178a89..3ca0240  <font color="#ff0000">master</font> <font color="#6666ff">-&gt; master</font></strong></pre>


<p>Oops! By default, &#8216;git push&#8217; syncs up all branches of the same name with the current branch&#8217;s origin. So that would push the <em>new project</em>&#8217;s master branch on our <em>initial</em> project&#8217;s shared master.</p>

<p>This is obviously not what we want. We only want ip_master to be pushed to the initial project&#8217;s master.</p>

<p>Trying to remember to always explicitly run &#8216;git push ip_origin ip_master:master&#8217; wouldn&#8217;t do it for me. To keep the analogy, that would be akin to doing a cartwheel on the edge of said cliff: a lot of fun until you make a mistake. So obviously we&#8217;d like a simple &#8216;git push&#8217; to do the right thing.</p>

<p>So here&#8217;s how we configure it:</p>

<pre><strong>git config remote.ip_origin.push refs/heads/ip_master:master</strong></pre>


<p>Now we can safely issue the &#8216;git push&#8217; command from ip_master and have Git push ip_master to ip_origin/master.</p>

<pre><strong>git push
#   Counting objects: 4, done.
#   Compressing objects: 100% (2/2), done.
#   Writing objects: 100% (3/3), 310 bytes, done.
#   Total 3 (delta 0), reused 0 (delta 0)
#   Unpacking objects: 100% (3/3), done.
#   To /Users/mat/blog/long-term-fork/test/initial_project
#      027a48f..9db6c3f  <font color="#6666ff">ip_master -&gt; master</font></strong></pre>


<p>There&#8217;s now only one remaining annoyance we&#8217;re not yet protected against. If new branches are created in the initial project&#8217;s central repository, a &#8216;git pull&#8217; when standing in the ip_master branch would pull them all in our new project&#8217;s working directory. I consider this one only an annoyance, since I could just decide not to pay attention to them. On the other hand they will be distracting and may also clash with the branches I create for the development on my new project. So we want to avoid that behavior as well.</p>

<p>To better understand the current Git configuration, let&#8217;s have a look at .git/config:</p>

<pre><strong>  ...
  [remote "ip_origin"]
    url = /Users/mat/blog/long-term-fork/test/initial_project
    <font color="#6666ff">fetch = +refs/heads/*:refs/remotes/ip_origin/*</font>
  [branch "master"]
    remote = origin
    merge = refs/heads/master
  [branch "ip_master"]
    remote = ip_origin
    merge = refs/heads/master
  [remote "origin"]
    url = ../project2
    <font color="#6666ff">fetch = +refs/heads/*:refs/remotes/origin/*</font></strong></pre>


<p>So in both &#8216;remote&#8217; sections I can see that fetch is configured to bring everything locally (the * wildcards).</p>

<p>So here&#8217;s how I limit what gets pulled when I pull from the initial project&#8217;s repository.</p>

<pre><strong>git config remote.ip_origin.fetch +refs/heads/master:refs/remotes/ip_origin/master</strong></pre>


<p>The part before the colon is the name of the interesting branch on the remote server. The part after the colon is your local Git repo&#8217;s internal branch, used to track the remote branch (not to be confused with our user branch ip_master).</p>

<p>Setting up remote branches on both projects, pulling, pushing and exchanging more commits is left as an exercise to the reader.</p>

<h2>Conclusion</h2>


<p>So that&#8217;s the gist of it, my friends. I am basically set up to work on my new project like I would in a more typical situation. I also have a special branch set up to interact with the initial project. With this branch I&#8217;ll be able to do two things:</p>

<ul>
    <li>Pull new developments from the initial project and then cherry-pick only the shareable commits into the new project&#8217;s other branches.</li>
    <li>Cherry-pick in the other direction to bring certain commits from the new project into this branch and then push them up to the initial project.</li>
</ul>


<p>For this approach to be useful however, we&#8217;ll have to make sure we create as concise commits as possible. Gone are the days of committing a whole afternoon in one meaningless commit containing 12 different modifications.</p>

<p>Of course coding sprees of a couple hours are not out of the question. Features like &#8216;git add −−patch&#8217; are a great help when comes time to extract meaningful commits out of the result of a few hours of intense coding. For a good introduction to −−patch (and a few other powerful features), be sure to read Ryan Tomayko&#8217;s <a href="http://tomayko.com/writings/the-thing-about-git">The Thing about Git</a>.</p>

<h2 id="executive-summary">The executive summary</h2>


<p>So let&#8217;s reiterate strictly the interesting bits necessary to set up a long term fork when starting a new project from an existing one.</p>

<p>We already have:</p>

<ul>
    <li>the initial project&#8217;s repository at url git@github.com:username/initial_project.git</li>
    <li>the new project&#8217;s empty repository, also created at git@github.com:username/new_project.git</li>
</ul>


<pre><strong># Create new local clone for the new project
git clone -o ip_origin git@github.com:username/initial_project.git new_project
cd new_project

# Set up a standard track between initial master and local ip_master
git config branch.ip_master.remote ip_origin
git config branch.ip_master.merge refs/heads/master

# Automatically push the right branch
<font color="#6666ff">git config remote.ip_origin.push refs/heads/ip_master:master</font>
# Don't bring in the other shared branches from initial project
<font color="#6666ff">git config remote.ip_origin.fetch +refs/heads/master:refs/remotes/ip_origin/master</font>

# Push new local repo it to new shared repo
git remote add origin git@github.com:username/new_project.git
git push origin master

# Configure standard track of master with new local repo
git config branch.master.remote origin
git config branch.master.merge refs/heads/master</strong></pre>


<p>That&#8217;s it! We now only have to cherry-pick like there&#8217;s no tomorrow.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[How to load gems only when your tests are not run from TextMate]]></title>
    <link href="http://www.programblings.com/2008/07/10/how-to-load-gems-only-when-your-tests-are-not-run-from-textmate/"/>
    <updated>2008-07-10T00:00:00-04:00</updated>
    <id>http://www.programblings.com/2008/07/10/how-to-load-gems-only-when-your-tests-are-not-run-from-textmate</id>
    <content type="html"><![CDATA[<p>Working with new people often influences the way you work. The influences can range from picking up simple tricks to seeing fundamental facts about your craft in a new light.This week when <a href="http://jamesgolick.com/2008/7/7/mat-martin-joins-giraffesoft">I began working with James</a> I saw him run his tests directly from TextMate. Of course I knew it was possible to run Ruby from TM, including tests.For some inexplicable reason however I had never bothered to try it. This trick is very convenient for two reasons: TextMate cleans up the backtraces and resolves each level of the trace to a clickable link to your code file. So I decided to include this trick in my workflow.I encountered two problems with this however. Two gems I usually use in my tests don&#8217;t play well with running tests from TextMate.</p>

<!-- more -->




<h2>redgreen</h2>


<p>The redgreen gem highlights the <font color="#008000"><strong>.</strong></font> <strong><font color="#ff0000">F</font></strong> and <font color="#ff9900"><strong>E</strong></font> (among other bits) in your test runs with green, red and yellow. When running my whole test suite it&#8217;s something I want to have. It&#8217;s not only visually pleasing, but it also lets me see at a glance whether any problems were encountered.When run from TextMate, tests using redgreen are displayed without having the console coloring stripped out, which gives something like this:</p>

<p>
<img src="http://www.programblings.com/uploads/2008/07/tests_with_redgreen_in_tm.png" alt="The result of running tests from TextMate, when using redgreen" height="223" width="564" />
</p>


<p>Riiiight.For the record, here&#8217;s the nice result when run at the console:</p>

<p><img src="http://www.programblings.com/uploads/2008/07/tests_with_redgreen_in_console.png" alt="Running tests with redgreen, from the console" height="208" width="409" /></p>


<h2>quietbacktrace</h2>


<p>The other gem I can&#8217;t do without is James Golick and Dan Croak&#8217;s <a href="http://jamesgolick.com/2007/12/3/noisy-backtraces-got-you-down">quietbacktrace</a>. This gem lets you specify filters and silencers to clean up those huuuuuge Rails or Merb backtraces.Filters let you remove useless parts of a given line in the backtrace, such as the path leading to your gems. Silencers let you completely remove some lines from the backtrace, such as all the lines referring to what happened inside Rails, leading to your error. The most popular filters and silencers are already provided with quietbacktrace, as you&#8217;ll see below.So the result, of course is that messing with backtraces breaks TextMate&#8217;s ability to link a backtrace line with the corresponding file.</p>

<h2>A simple snippet to fix this</h2>


<p>Since I didn&#8217;t really want to do away with these tools, I included a bit of a hacky snippet in my test_helper.rb file to detect whether a test run was happening in TextMate or at the console.If you find yourself in the same fix as me, feel free to use the following.Among your requires:</p>

<pre><strong>IN_TM = !ENV['TM_DIRECTORY'].nil?
unless IN_TM
  require 'redgreen'
  require 'quietbacktrace'end</strong></pre>


<p>And then:</p>

<pre><strong>class Test::Unit::TestCase
  unless IN_TM
    self.backtrace_silencers &lt;&lt; :rails_vendor
    self.backtrace_filters   &lt;&lt; :rails_root
  end
  #...
end</strong></pre>


<p>Now I can have my testing niceties when running my tests from the console and they don&#8217;t break the TextMate integration :-)</p>

<h2> Trying this out for the first time?</h2>


<p>If like me you just decided to try this out for the first time, the shortcuts are easy to remember. Command-R runs any Ruby file (in this case, the whole test file) and Command-Shift-R runs the single test the cursor is in.There&#8217;s a little hiccup in sight, however. If you&#8217;re using Rails 2+, you have to apply a very small fix to TextMate before you&#8217;ll be able to run your tests. Read more about the fix on <a href="http://macournoyer.wordpress.com/2007/12/15/getting-textmate-ready-for-rails-20/">Marc-André Cournoyer&#8217;s blog</a>.</p>
]]></content>
  </entry>
  
</feed>
