<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>As Thick As Two Short Planks - Mark Fowler&#039;s Blog</title>
	<atom:link href="http://blog.twoshortplanks.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.twoshortplanks.com</link>
	<description></description>
	<lastBuildDate>Fri, 20 Jan 2012 09:33:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='blog.twoshortplanks.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>As Thick As Two Short Planks - Mark Fowler&#039;s Blog</title>
		<link>http://blog.twoshortplanks.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://blog.twoshortplanks.com/osd.xml" title="As Thick As Two Short Planks - Mark Fowler&#039;s Blog" />
	<atom:link rel='hub' href='http://blog.twoshortplanks.com/?pushpress=hub'/>
		<item>
		<title>Frac&#8217;ing your HTML</title>
		<link>http://blog.twoshortplanks.com/2012/01/20/frac/</link>
		<comments>http://blog.twoshortplanks.com/2012/01/20/frac/#comments</comments>
		<pubDate>Fri, 20 Jan 2012 09:28:08 +0000</pubDate>
		<dc:creator>2shortplanks</dc:creator>
		
		<guid isPermaLink="false">http://blog.twoshortplanks.com/?p=305</guid>
		<description><![CDATA[In my previous blog entry I talked about encoding weird characters into HTML entities. In this entry I&#8217;m going to talk about converting some patterns of ASCII &#8211; dumb ways of writing fractions &#8211; and turning them into HTML entities or Unicode characters. Hey Good Looking, What&#8217;s Cooking? Imagine a simple recipe: &#60;ul&#62; &#60;li&#62;1/2 cup &#8230; <a href="http://blog.twoshortplanks.com/2012/01/20/frac/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=305&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In my <a href="http://blog.twoshortplanks.com/2012/01/13/entities/">previous</a> blog entry I talked about encoding weird characters into HTML entities. In this entry I&#8217;m going to talk about converting some patterns of ASCII &#8211; dumb ways of writing fractions &#8211; and turning them into HTML entities or Unicode characters.</p>
<h2 id="heygoodlookingwhatscooking">Hey Good Looking, What&#8217;s Cooking?</h2>
<p>Imagine a simple recipe:</p>
<pre><code>&lt;ul&gt;
   &lt;li&gt;1/2 cup of sugar&lt;/li&gt;
   &lt;li&gt;1/2 cup of spice&lt;/li&gt;
   &lt;li&gt;1/4 cup of all things nice&lt;/li&gt;
&lt;/ul&gt;
</code></pre>
<p>While this is nice, <em>we can do better</em>. There&#8217;s nice Unicode<br />
characters for &#188;, &#189; and corresponding HTML entities that we can use to have the browser render them for us. What we need is some way to change all our mucky ASCII into these entities. Faced with this problem on his <a href="http://astray.com/recipes">recipes</a> site European Perl Hacker Léon Brocard wrote a module called <a href="http://metacpan.org/module/HTML::Fraction">HTML::Fraction</a> that could tweak strings of HTML.</p>
<pre><code>use HTML::Fraction;
my $frac = HTML::Fraction-&gt;new();
my $output = $frac-&gt;tweak($string_of_html);
</code></pre>
<p>This module creates output like:</p>
<pre><code>&lt;ul&gt;
   &lt;li&gt;&amp;frac12; cup of sugar&lt;/li&gt;
   &lt;li&gt;&amp;frac12; cup of spice&lt;/li&gt;
   &lt;li&gt;&amp;frac14; cup of all things nice&lt;/li&gt;
&lt;/ul&gt;
</code></pre>
<p>Which renders nicely as:</p>
<ul>
<li>&#189; cup of sugar</li>
<li>&#189; cup of spice</li>
<li>&#188; cup of all things nice</li>
</ul>
<p>HTML::Fraction can even cope with decimal representation in your string. For example:</p>
<ul>
<li>0.5 slugs</li>
<li>0.67 snails</li>
<li>0.14 puppy dogs tails</li>
</ul>
<p>Processed with HTML::Fraction renders like so:</p>
<ul>
<li>&#188; slugs</li>
<li>&#8532; snails</li>
<li>&#8528; puppy dogs tails</li>
</ul>
<h2 id="unicodecharactersinstead">Unicode Characters Instead</h2>
<p>Of course, we don&#8217;t <em>always</em> want to render out HTML. Sometimes we just want a plain old string back. Faced with this issue myself, I wrote a quick subclass called <a href="http://metacpan.org/module/String::Fraction">String::Fraction</a>:</p>
<pre><code>use String::Fraction;
my $frac = String::Fraction-&gt;new();
my $output = $frac-&gt;tweak($string);
</code></pre>
<p>The entire source code of this module is short enough that I can show you it here.</p>
<pre><code>package String::Fraction;
use base qw(HTML::Fraction);

use strict;
use warnings;

our $VERSION = &quot;0.30&quot;;

# Our superclass sometimes uses named entities
my %name2char = (
  '1/4'  =&gt; &quot;\x{00BC}&quot;,
  '1/2'  =&gt; &quot;\x{00BD}&quot;,
  '3/4'  =&gt; &quot;\x{00BE}&quot;,
);

sub _name2char {
  my $self = shift;
  my $str = shift;

  # see if we can work from the Unicode character
  # from the entity returned by our superclass
  my $entity = $self-&gt;SUPER::_name2char($str);
  if ($entity =~ /\A &amp;\#(\d+); \z/x) {
    return chr($1);
  }

  # superclass doesn't return a decimal entity?
  # use our own lookup table
  return $name2char{ $str }
}
</code></pre>
<p>We simply override one method <code>_name2char</code> so that instead of returning a HTML entity we<br />
return corresponding Unicode character.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/twoshortplanks.wordpress.com/305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/twoshortplanks.wordpress.com/305/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/twoshortplanks.wordpress.com/305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/twoshortplanks.wordpress.com/305/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/twoshortplanks.wordpress.com/305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/twoshortplanks.wordpress.com/305/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/twoshortplanks.wordpress.com/305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/twoshortplanks.wordpress.com/305/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/twoshortplanks.wordpress.com/305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/twoshortplanks.wordpress.com/305/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/twoshortplanks.wordpress.com/305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/twoshortplanks.wordpress.com/305/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/twoshortplanks.wordpress.com/305/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/twoshortplanks.wordpress.com/305/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=305&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.twoshortplanks.com/2012/01/20/frac/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/5d71b5f0c61e97cd452d625cc24a4c82?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">2shortplanks</media:title>
		</media:content>
	</item>
		<item>
		<title>Once is Enough</title>
		<link>http://blog.twoshortplanks.com/2012/01/13/entities/</link>
		<comments>http://blog.twoshortplanks.com/2012/01/13/entities/#comments</comments>
		<pubDate>Fri, 13 Jan 2012 19:57:40 +0000</pubDate>
		<dc:creator>2shortplanks</dc:creator>
		
		<guid isPermaLink="false">http://blog.twoshortplanks.com/?p=298</guid>
		<description><![CDATA[<p>In this blog post I discuss how HTML entities work, how to encode them with Perl, and how to detect when you&#8217;ve accidentally double encoded your entities with my module Test::DoubleEncodedEntities.</p> <a href="http://blog.twoshortplanks.com/2012/01/13/entities/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=298&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In this blog post I discuss how HTML entities work, how to encode them with Perl, and how to detect when you&#8217;ve accidentally double encoded your entities with my module Test::DoubleEncodedEntities.</p>
<h2 id="howhtmlentitieswork">How HTML Entities work</h2>
<p>In HTML you can represent any character in simple ASCII by using <em>entities</em>. These come in two forms, either using the decimal codepoint of the character or, for some frequently used characters more readable human <em>named entities</em></p>
<table>
<tr>
<th>Character</th>
<th>Unicode codepoint</th>
<th>Decimal Entity</th>
<th>Named Enitity</th>
</tr>
<tr>
<td>&eacute;</td>
<td>233</td>
<td>&#233;
<td>&amp;eacute;</td>
</tr>
<tr>
<td>&copy;</td>
<td>169</td>
<td>&#169;
<td>&amp;copy;</td>
</tr>
<tr>
<td>&#9731;</td>
<td>9731</td>
<td>&#9731;
<td><em>none</em></td>
</tr>
<tr>
<td>&lt;</td>
<td>60</td>
<td>&#060;
<td>&amp;lt;</td>
</tr>
<tr>
<td>&amp;</td>
<td>38</td>
<td>&#038;
<td>&amp;amp;</td>
</tr>
</table>
<p>So instead of writing</p>
<p><code>
<pre>&lt;!DOCTYPE html&gt;
&lt;html&gt;&lt;body&gt;&copy; 2012 Mark Fowler&lt;/body&gt;&lt;/html&gt;</pre>
<p></code></p>
<p>You can write</p>
<p><code>
<pre>&lt;!DOCTYPE html&gt;
&lt;html&gt;&lt;body&gt;&amp;copy; 2012 Mark Fowler&lt;/body&gt;&lt;/html&gt;</pre>
<p></code></p>
<p>By delivering a document in ASCII and using entities for any codepoints above 127 you can ensure that even the most broken of browsers will render the right characters.</p>
<p>Importantly, when an entity is converted back into a character by the browser the character no longer has any of its special meaning, so you can use encoding to escape sequences that would otherwise be considered markup. For example:</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;&lt;body&gt;say &quot;yep&quot;
  if $ready &amp;amp;&amp;amp; $bad &amp;lt; $good;
&lt;/body&gt;&lt;/html&gt;
</code></pre>
<p>Correctly renders as</p>
<pre><code>say &quot;yep&quot; if $ready &amp;&amp; $bad &lt; $good;
</code></pre>
<h2 id="encodingentitieswithperl">Encoding Entities with Perl</h2>
<p>The go-to module for encoding and decoding entities is <a href="http://metacpan.org/module/HTML::Entities">HTML::Entities</a>. Its use is simple: You pass the string you want to encode into the <code>encode_entities</code> function and it returns the same string with the entities encoded:</p>
<pre><code>use HTML::Entites qw(encode_entities);

my $string = &quot;\x{a9} Mark Fowler 2012&quot;;
my $encoded = encode_entities($string);
say &quot;&lt;!DOCTYPE html&gt;&quot;
say &quot;&lt;html&gt;&lt;body&gt;$encoded&lt;/body&gt;&lt;/html&gt;&quot;;
</code></pre>
<p>If you no longer need the non-encoded string you can have HTML::Entities modify the string you pass to it by not assigning the output to anything (HTML::Entities is smart enough to notice it&#8217;s being called in <em>void context</em> where its return value is not being used.)</p>
<pre><code>use HTML::Entites qw(encode_entities);

my $string = &quot;\x{a9} Mark Fowler 2012&quot;;
encode_entities($string);
say &quot;&lt;!DOCTYPE html&gt;&quot;
say &quot;&lt;html&gt;&lt;body&gt;$string&lt;/body&gt;&lt;/html&gt;&quot;;
</code></pre>
<h2 id="thedoubleencodingproblem">The Double Encoding Problem</h2>
<p>The trouble with encoding HTML entities is that if you do it a second time then you end up with nonsensical looking text. For example </p>
<pre><code>use HTML::Entites qw(encode_entities);

my $string = &quot;\x{a9} Mark Fowler 2012&quot;;
encode_entities($string);
encode_entities($string);
say &quot;&lt;!DOCTYPE html&gt;&quot;
say &quot;&lt;html&gt;&lt;body&gt;$string&lt;/body&gt;&lt;/html&gt;&quot;;
</code></pre>
<p>Outputs</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;hmtl&gt;&lt;body&gt;&amp;amp;copy; Mark Fowler 2012&lt;/body&gt;&lt;/html&gt;
</code></pre>
<p>Which when rendered by the browser displays</p>
<pre><code>&amp;copy; Mark Fowler 2012
</code></pre>
<p>As the <code>&amp;amp;</code> has turned into <code>&amp;</code> but <strong>isn&#8217;t</strong> then combind with the <code>copy;</code> to turn it into the copyright symbol &copy;.</p>
<p>Each subsequent encoding turns the <code>&amp;</code> at the start of the entity into <code>&amp;amp;</code>, including those at the start of any previously created <code>&amp;amp;</code>. Do this ten or so times and you end up with:</p>
<pre><code>&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;copy; Mark Fowler 2012
</code></pre>
<p>The obvious solution is to make sure you encode the entities only once! But that&#8217;s not as easy as it might seem. If you&#8217;re building your output up from multiple processes it&#8217;s quite easy to mistakenly encode twice; Worse, if you&#8217;re using data that you don&#8217;t control (for example, extracted from a web page, downloaded from a feed, imported from a user) you might find that some or more of it had unexpectedly already been encoded.</p>
<h2 id="testingfortheproblem">Testing for the Problem</h2>
<p>I recently re-released my module <a href="http://metacpan.org/module/Test::DoubleEncodedEntities">Test::DoubleEncodedEntities</a> that can be used to write automated tests for double encoding.</p>
<pre><code>use Test::More tests =&gt; 1;
use Test::DoubleEncodedEntities;
ok_dee($string, &quot;check for double encoded entities&quot;);
</code></pre>
<p>It works <em>heuristically</em> by looking for strings that could possibly be double encoded entities. Obviously there&#8217;s lots of HTML documents out there where it&#8217;s perfectly legitimate to have double encoded entities: any of them talking about entity encoding, such as this blog post itself, will naturally do do. However, the vast majority &#8211; where you control the input &#8211; will not have these format of strings and we can test for them.</p>
<p>For example:</p>
<pre><code>use Test::More tests =&gt; 6;
use Test::DoubleEncodedEntities;

ok_dee(&quot;&amp;copy; Mark Fowler 2012&quot;,     &quot;should pass&quot;);
ok_dee(&quot;&amp;amp;copy; Mark Fowler 2012&quot;, &quot;should fail&quot;);
ok_dee(&quot;&#038;copy; Mark Fowler 2012&quot;, &quot;should fail&quot;);
ok_dee(&quot;&#169; Mark Fowler 2012&quot;,     &quot;should pass&quot;);
ok_dee(&quot;&amp;amp;#169; Mark Fowler 2012&quot;, &quot;should fail&quot;);
ok_dee(&quot;&#038;#169; Mark Fowler 2012&quot;, &quot;should fail&quot;);
</code></pre>
<p>Produces the output:</p>
<pre><code>1..6
ok 1 - should pass
not ok 2 - should fail
#   Failed test 'should fail'
#   at test.pl line 5.
# Found 1 &quot;&amp;amp;copy;&quot;
not ok 3 - should fail
#   Failed test 'should fail'
#   at test.pl line 6.
# Found 1 &quot;&#038;copy;&quot;
ok 4 - should pass
not ok 5 - should fail
#   Failed test 'should fail'
#   at test.pl line 8.
# Found 1 &quot;&amp;amp;#169;&quot;
not ok 6 - should fail
#   Failed test 'should fail'
#   at test.pl line 9.
# Found 1 &quot;&#038;#169;&quot;
# Looks like you failed 4 tests of 6.
</code></pre>
<p>Correctly detecting the double encoded entities in the <code>should fail</code> tests</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/twoshortplanks.wordpress.com/298/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/twoshortplanks.wordpress.com/298/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/twoshortplanks.wordpress.com/298/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/twoshortplanks.wordpress.com/298/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/twoshortplanks.wordpress.com/298/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/twoshortplanks.wordpress.com/298/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/twoshortplanks.wordpress.com/298/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/twoshortplanks.wordpress.com/298/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/twoshortplanks.wordpress.com/298/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/twoshortplanks.wordpress.com/298/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/twoshortplanks.wordpress.com/298/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/twoshortplanks.wordpress.com/298/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/twoshortplanks.wordpress.com/298/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/twoshortplanks.wordpress.com/298/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=298&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.twoshortplanks.com/2012/01/13/entities/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/5d71b5f0c61e97cd452d625cc24a4c82?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">2shortplanks</media:title>
		</media:content>
	</item>
		<item>
		<title>Simple Todo List Processing in Perl</title>
		<link>http://blog.twoshortplanks.com/2012/01/07/291/</link>
		<comments>http://blog.twoshortplanks.com/2012/01/07/291/#comments</comments>
		<pubDate>Sat, 07 Jan 2012 19:13:10 +0000</pubDate>
		<dc:creator>2shortplanks</dc:creator>
		
		<guid isPermaLink="false">https://twoshortplanks.wordpress.com/?p=291</guid>
		<description><![CDATA[While I normally use OmniFocus as a GTD tool to manage my todo lists, sometimes I want to collaborate on a todo list with someone else and I don’t want them to have to use a complicated and expensive tool. I’ve often found in this situation a simple shared text file is the way to &#8230; <a href="http://blog.twoshortplanks.com/2012/01/07/291/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=291&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>While I normally use OmniFocus as a GTD tool to manage my todo lists, sometimes I want to collaborate on a todo list with someone else and I don’t want them to have to use a complicated and expensive tool. I’ve often found in this situation a simple shared text file is the way to go.  A file on the office fileserver, or in a shared Dropbox folder, in a obvious format that any can understand with a glance.</p>
<p>Here’s what one looks like:</p>
<pre><code>[X] (extract) Complete coding.
[X] (extract) Get Zefram to code review my code.
[X] (yapc) Write talk submission for YAPC::NA
[X] (yapc) submit talk proposal with ACT
[ ] (extract) Write Array::Extract::Example document.
[ ] (extract) Check in and push to github
[ ] (extract) Upload to CPAN.
[ ] (extract) Publish a blog post about it
</code></pre>
<p>In the above example two tasks each from the the <code>extract</code> project and the <code>yapc</code> project have been marked as completed.  Periodically I want to move these “done” items to a separate archive list &#8211; the done file &#8211; so they don’t clutter up my list.  That’s something I’m going to want to automate with Perl.</p>
<p>The way I’ve chosen to write that script is to use  Tie::File, where each element of the array corresponds to a line of the file.</p>
<h2>Alternatives to Grepping</h2>
<p>At first glance removing all the lines from our array that are ticked might seem like a simple use of grep:</p>
<pre><code>tie my @todo, "Tie::File", $filename or die $!;
@todo = grep { !/\A\[[^ ]]/ } @todo;
</code></pre>
<p>But that’s throwing away everything that we want to move to the done file. An alternative might be to write a grep with side effects:</p>
<pre><code>tie my @todo, "Tie::File", $filename or die $!;
open my $done_fh, "&gt;;&gt;;", $done_filename or die $!;
@todo = grep {
  !/\A\[[^ ]]/ || do {
    say { $done_fh } $_;
  0 }
} @todo;
</code></pre>
<p>But that’s ugly.  The code gets much uglier still if you want a banner preceding the first new entry into the done file saying when the actions were moved there.</p>
<p>What I ended up doing was writing a new module called <a href="http://metacpan.org/module/Array::Extract">Array::Extract</a> which exports a function <code>extract</code> that does exactly what you might expect:</p>
<pre><code>my @done = extract { /\A\[[^ ]]/ } @todo;
</code></pre>
<p><code>@todo</code> is modified to remove anything that the block returns true for and those elements are placed in <code>@done</code>.</p>
<pre><code>open my $done_fh, "&gt;;&gt;;", $done_filename or die $!;
my @done = extract { /\A\[[^ ]]/ } @todo;
print { $done_fh } map { "$_\n" }
  "","Items archived @{[ DateTime-&gt;;now ]}:","",@done;
</code></pre>
<h2>Needs more actions</h2>
<p>Of course, if all I wanted to do was remove the actions that had been completed I probably wouldn’t have reached for Tie::File, but for my next trick I’m going to need to insert some extra content at the top of the file once I’m done processing it.</p>
<p>I want to keep track of projects that have had all their remaining actions marked as done and moved to the done file.  For example, I’ve ticked off all the action in the <code>yapc</code> so I need more actions (write slides, book flight, etc, etc.)  I need a list of these “actionless” projects at the top of my todo list so when I glance at it I know there’s some tasks missing.</p>
<p>Essentially after I run my script I want my todo file to look something like this:</p>
<pre><code>yapc needs more actions

[ ] (extract) Write Array::Extract::Example document
[ ] (extract) Check in and push to github
[ ] (extract) Upload to CPAN
[ ] (extract) Publish a blog post about it
</code></pre>
<p>Here’s the final script that handles that case too:</p>
<pre><code>#!/usr/bin/env perl.  

use 5.012;
use warnings;

use Path::Class;
use Tie::File;
use Array::Extract qw(extract);
use List::MoreUtils qw(uniq last_index);
use DateTime;

########################################################################

my $TODO = file($ENV{HOME}, "Dropbox", "SharedFolder", "TODO.txt");
my $DONE = $TODO-&gt;;dir-&gt;;file("DONE.txt");

########################################################################

# work out what projects are in this array, maintaining order
sub projects(@) {
  return uniq grep { defined $_ } map { /^\[.] \(([^)]+)/; $1 } @_;
}

########################################################################

# tie to the todo list file
tie my @todo, "Tie::File", $TODO-&gt;;stringify or die $!;

# work out what projects are in the file before we remove anything
my @projects = projects @todo;

# remove those items that are done.
my @done = extract { /\A\[[^ ]]/x } @todo;
exit unless @done;

# append what has been done to another file
print { $DONE-&gt;;open("&gt;;&gt;;") or die $! } map { "$_\n" }
  "",
  "Items archived @{[ DateTime-&gt;;now ]}:",
  "",
  @done;

# work out which projects no longer exist
my %remaining_project = map { $_ =&gt;; 1 } projects @todo;
@projects = grep { !$remaining_project{ $_ } } @projects;

# insert this at the section at the top of the file.
splice @todo,0,0,map { "$_ needs more actions" } @projects;

# seperate the "needs more actions" out with a newline
my $break = last_index { /needs more actions\z/ } @todo;
splice @todo, $break+1, 0, "" if defined $break &amp;&amp; $todo[$break+1] ne "";
</code></pre>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/twoshortplanks.wordpress.com/291/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/twoshortplanks.wordpress.com/291/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/twoshortplanks.wordpress.com/291/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/twoshortplanks.wordpress.com/291/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/twoshortplanks.wordpress.com/291/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/twoshortplanks.wordpress.com/291/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/twoshortplanks.wordpress.com/291/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/twoshortplanks.wordpress.com/291/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/twoshortplanks.wordpress.com/291/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/twoshortplanks.wordpress.com/291/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/twoshortplanks.wordpress.com/291/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/twoshortplanks.wordpress.com/291/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/twoshortplanks.wordpress.com/291/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/twoshortplanks.wordpress.com/291/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=291&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.twoshortplanks.com/2012/01/07/291/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/5d71b5f0c61e97cd452d625cc24a4c82?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">2shortplanks</media:title>
		</media:content>
	</item>
		<item>
		<title>Once a week, every week</title>
		<link>http://blog.twoshortplanks.com/2011/12/31/once-a-week-every-week/</link>
		<comments>http://blog.twoshortplanks.com/2011/12/31/once-a-week-every-week/#comments</comments>
		<pubDate>Sat, 31 Dec 2011 19:53:44 +0000</pubDate>
		<dc:creator>2shortplanks</dc:creator>
		
		<guid isPermaLink="false">http://blog.twoshortplanks.com/?p=289</guid>
		<description><![CDATA[This year my new year’s resolution for 2012 will be to release a Perl distribution to the CPAN each and every week. And I think you, as a Perl developer, should do this too. Why am I doing this? Because I’m trying to force myself into more iterative development. Note that I didn’t say a &#8230; <a href="http://blog.twoshortplanks.com/2011/12/31/once-a-week-every-week/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=289&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>This year my new year’s resolution for 2012 will be to <strong>release a Perl distribution to the CPAN each and every week</strong>. And I think you, as a Perl developer, should do this too.</p>
<p>Why am <em>I</em> doing this? Because I’m trying to force myself into more iterative development. Note that I didn’t say a <em>new</em> distribution. Just a new release &#8211; of either an existing or new distribution &#8211; a week.</p>
<p>The simple fact of the matter is that <em>false hubris</em> is causing me to not be releasing as often as I should and consequently I’m seeing lots of problems.</p>
<ul>
<li><strong>Sometimes I’m tempted to do too much in one release</strong>. I’ve got lots of modules that could do with updating, but because I think they need massive amounts of work I don’t ever have the time to make all the changes. I’d be better off just improving them slightly each release and releasing them more often.</li>
<li><strong>Sometimes I’m being a perfectionist with my first release</strong>. I’ve got a bunch of modules that I’ve got 90% done but because there’s theoretically a few more nice to have features I haven’t written yet, I’ve not shipped them. I should <em>Release early release often</em>. What extra features these modules need will soon become apparent once it has more real world users than just me, and hey, in the open source world <em>someone else might write them for me</em>.</li>
<li><strong>Sometimes I don’t value my code enough</strong> and I don’t think the “simple” thing I spent a day or so coding would be useful for anyone else or it’s beneath me to release something so simple to the CPAN. This of course is nonsense &#8211; a day I can save someone else coding is a day they’ve saved, no matter how obvious or simple the code.</li>
</ul>
<p>This all can pretty much be solved by forcing myself to release more often. So, here’s the challenge:</p>
<h2 id="therules">The Rules</h2>
<p>Short version: <em>Upload each week, every week.</em></p>
<p>Longer version:</p>
<ul>
<li>Every week, as defined as the midnight between Saturday night / Sunday morning UTC to the midnight between the following Saturday night / Sunday morning UTC, I must release a new distribution to the CPAN. (Note that this gives me no extra or less allowance during daylight savings or time zone changes.)</li>
<li>For the purpose of disambiguation timings will be counted by PAUSE upload dates</li>
<li>Should an official PAUSE outage occur and I can, hand on my heart, claim that that stopped me uploading, I will give myself a grace period of forty eight hours after either the end of the outage or the end of the previous week (whichever is longer) to complete the upload. In this situation this upload will count for the previous week and an upload will still have to be made for the week that upload took place in.</li>
<li>Scoring for the year will be done by <a href="http://lifehacker.com/281626/jerry--productivity-secret">Seinfeld chain length</a>, that is to say by counting the largest run of uninterrupted weeks, with ties decided by total number of weeks with uploads.</li>
</ul>
<h2 id="youcanplaytoo">You Can Play Too</h2>
<p>Of course, it would be great for the Perl world if every CPAN developer took up this challenge. More importantly, it’d be great for me because it’d give me someone to compete against and to make sure that I keep this self-set challenge up. So how about it? Fancy playing?</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/twoshortplanks.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/twoshortplanks.wordpress.com/289/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/twoshortplanks.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/twoshortplanks.wordpress.com/289/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/twoshortplanks.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/twoshortplanks.wordpress.com/289/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/twoshortplanks.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/twoshortplanks.wordpress.com/289/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/twoshortplanks.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/twoshortplanks.wordpress.com/289/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/twoshortplanks.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/twoshortplanks.wordpress.com/289/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/twoshortplanks.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/twoshortplanks.wordpress.com/289/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=289&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.twoshortplanks.com/2011/12/31/once-a-week-every-week/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/5d71b5f0c61e97cd452d625cc24a4c82?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">2shortplanks</media:title>
		</media:content>
	</item>
		<item>
		<title></title>
		<link>http://blog.twoshortplanks.com/2011/12/02/justsafarijs/</link>
		<comments>http://blog.twoshortplanks.com/2011/12/02/justsafarijs/#comments</comments>
		<pubDate>Fri, 02 Dec 2011 10:13:31 +0000</pubDate>
		<dc:creator>2shortplanks</dc:creator>
		
		<guid isPermaLink="false">http://blog.twoshortplanks.com/?p=282</guid>
		<description><![CDATA[<p>As part of my <a href="http://www.pimpyourmacwithperl.com/">Pimp Your Mac With Perl Talk</a> at the <a href="http://conferences.yapceurope.org/lpw2011/">London Perl Workshop</a> I talked very briefly about one of my newer Perl modules that I haven&#8217;t blogged about before: <a href="http://metacpan.org/module/Mac::Safari::JavaScript">Mac::Safari::JavaScript</a>. This module allows you to execute JavaScript inside your browser from within a Perl program and it <strong>just work</strong>.</p> <a href="http://blog.twoshortplanks.com/2011/12/02/justsafarijs/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=282&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>As part of my <a href="http://www.pimpyourmacwithperl.com/">Pimp Your Mac With Perl Talk</a> at the <a href="http://conferences.yapceurope.org/lpw2011/">London Perl Workshop</a> I talked very briefly about one of my newer Perl modules that I haven&#8217;t blogged about before: <a href="http://metacpan.org/module/Mac::Safari::JavaScript">Mac::Safari::JavaScript</a>. This module allows you to execute JavaScript inside your browser from within a Perl program and it <strong>just work</strong>.</p>
<h2 id="thepowerofjust">The Power of Just</h2>
<p>Piers Cawley gave a lightning talk at YAPC::Europe::2001 about <em>just</em> in which he explained the power of interfaces that <em>just</em> do what you need whenever you need them to and hide a bunch of complexity behind themselves.</p>
<p>To run JavaScript in Safari you <strong>just</strong> call <code>safari_js</code> with the JavaScript you want to execute:</p>
<pre><code>use Mac::Safari::JavaScript qw(safari_js);
safari_js('alert(&quot;Hello World&quot;);');
</code></pre>
<p>This JavaScript is then executed in the current tab of the frontmost Safari window. If you want to return a datascructure to Perl from your JavaScript then you <strong>just</strong> do so:</p>
<pre><code>my $page_title = safari_js(&quot;return document.title;&quot;);
</code></pre>
<p>No matter how complex<a href="1" id="fnref:1" title="see footnote" class="footnote">[1]</a>: it is:</p>
<pre><code>my $details = safari_js(&lt;&lt;'ENDOFJAVASCRIPT');
  return {
    title: document.title,
    who: jQuery('#assignedto').next().text(),
  };
ENDOFJAVASCRIPT
</code></pre>
<p>If you want to have variables avalible to you in your JavaScript then you <strong>just</strong> pass them in:</p>
<pre><code>my $sum = safari_js(&quot;return a+b;&quot;,{ a =&gt; 1, b =&gt; 2 });
</code></pre>
<p>No matter how complex<a href="2" id="fnref:2" title="see footnote" class="footnote">[2]</a> they are:</p>
<pre><code>use Config;
safari_js(&quot;alert(config['version']);&quot;,{config =&gt; \%Config})
</code></pre>
<p>And if you throw an exception in JavaScript, then you <strong>just</strong> catch it the normal way:</p>
<pre><code>use Try::Tiny;
try {
  safari_js(&quot;throw 'bang';&quot;);
} catch {
  print &quot;Exception '$_' thrown from within JavaScript&quot;;
};
</code></pre>
<h2 id="peakingunderthehood">Peaking Under the Hood</h2>
<p>So, how, does this all hang together? Well, it turns out that running JavaScript in your browser from AppleScript isn&#8217;t that hard:</p>
<pre><code>tell application &quot;Safari&quot;
  do JavaScript &quot;alert('hello world');&quot; in document 1
end tell
</code></pre>
<p>And running AppleScript from within Perl isn&#8217;t that hard either:</p>
<pre><code>use Mac::AppleScript qw(RunAppleScript);
RunAppleScript($applescript);
</code></pre>
<p>So it&#8217;s a simple problem, right? Just nest the two inside each other. Er, no, it&#8217;s not <em>just</em> that simple.</p>
<p>It turns out that handling the edge cases is actually quite hard. Typical problems that come up that Mac::Safari::JavaScript <strong>just</strong> deals with you for are:</p>
<ul>
<li>How do we encode data structures that we pass to and from JavaScript?</li>
<li>How do we escape the strings we pass to and from AppleScript?</li>
<li>For that matter how do we encode the program itself so it doesn&#8217;t break?</li>
<li>What happens if the user supplies invalid JavaScript?</li>
<li>How do we get exceptions to propogate properly?</li>
<li>With all this thunking between layers, how do we get the line numbers to match up in our exceptions?</li>
</ul>
<p>And that&#8217;s the power of a module that handles the <strong>just</strong> for you. Rather than writing a few lines of code to get the job done, you can now <strong>just</strong> write one <em>and</em> have that one line handle all the weird edge cases for you.</p>
<div class="footnotes">
<hr />
<ol>
<li id="fn:1">
<p>Okay, so there are some limits. Anything that can be represented by JSON can be returned, but anything that can&#8217;t, can&#8217;t. This means you can&#8217;t return circular data structures and you can&#8217;t return DOM elements. But that would be crazy; <strong>Just</strong> don&#8217;t do that. <a href="1" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>
<li id="fn:2">
<p>Likewise we can only pass into JavaScript something that can be represented as JSON. No circular data strucutres. No weird Perl not-really-data things such as objects, filehandles, code refences, etc. <a href="2" title="return to article" class="reversefootnote">&#160;&#8617;</a></p>
</li>
</ol>
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/twoshortplanks.wordpress.com/282/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/twoshortplanks.wordpress.com/282/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/twoshortplanks.wordpress.com/282/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/twoshortplanks.wordpress.com/282/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/twoshortplanks.wordpress.com/282/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/twoshortplanks.wordpress.com/282/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/twoshortplanks.wordpress.com/282/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/twoshortplanks.wordpress.com/282/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/twoshortplanks.wordpress.com/282/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/twoshortplanks.wordpress.com/282/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/twoshortplanks.wordpress.com/282/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/twoshortplanks.wordpress.com/282/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/twoshortplanks.wordpress.com/282/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/twoshortplanks.wordpress.com/282/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=282&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.twoshortplanks.com/2011/12/02/justsafarijs/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/5d71b5f0c61e97cd452d625cc24a4c82?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">2shortplanks</media:title>
		</media:content>
	</item>
		<item>
		<title>Test::DatabaseRow 2</title>
		<link>http://blog.twoshortplanks.com/2011/11/18/testdatabaserow2/</link>
		<comments>http://blog.twoshortplanks.com/2011/11/18/testdatabaserow2/#comments</comments>
		<pubDate>Fri, 18 Nov 2011 21:07:22 +0000</pubDate>
		<dc:creator>2shortplanks</dc:creator>
		
		<guid isPermaLink="false">http://blog.twoshortplanks.com/?p=279</guid>
		<description><![CDATA[<p>Last week I released an update for one of my older modules, <a href="http://search.cpan.org/~markf/Test-DatabaseRow">Test::DatabaseRow</a>. In the course of this update I completely rewrote the guts of the module, turning the bloated procedural module into a set of clearly defined Moose-like Perl classes.</p> <a href="http://blog.twoshortplanks.com/2011/11/18/testdatabaserow2/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=279&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Last week I released an update for one of my older modules, <a href="http://search.cpan.org/~markf/Test-DatabaseRow">Test::DatabaseRow</a>. In the course of this update I completely rewrote the guts of the module, turning the bloated procedural module into a set of clearly defined Moose-like Perl classes.</p>
<h2 id="whyupdatenow">Why update now?</h2>
<p>Test::DatabaseRow had been failing it&#8217;s tests since Perl 5.13.3 (it was another victim of the changing stringification of regular expressions breaking tests.) We&#8217;re currently planning to upgrade our systems at work from 5.12 to 5.14 in the new year, and (embarrassing) one of the key modules that breaks our 5.14 smoke is Test::DatabaseRow. Oooops.</p>
<p>Since I had my editor open, I decided it might be a good idea to switch to a more modern build system. And, since I was doing that, I thought it might be a good idea to fix one of my long standing todos (testing all rows returned from the database not just the first.)</p>
<p>In other words, once I&#8217;d started, I found it hard to stop, and before I knew it I had a reasonably big task on my hands.</p>
<h2 id="thedecisiontorefactor">The decision to refactor</h2>
<p>When I first wrote Test::DatabaseRow back in 2003, like most testing modules of the time, it sported a simple Exporter based interface. The (mostly correct) wisdom was that simple procedural interfaces make it quicker to write tests. I still think that&#8217;s true, but:</p>
<ul>
<li>
<p><strong>Procedual programming ends up either with very long functions or excessive argument passing</strong>. The single function interface made the internals of Test::DatbaseRow quite difficult &#8211; to avoid having one giant function call I ended up passing all the arguments a multitude of helper functions and then passing the multiple return values of one function onto the next.</p>
</li>
<li>
<p><strong>Many of the calls you write want to share the same defaults</strong> For example, the database handle to use, if we should be verbose in our output, should we do utf&#8211;8 conversion?&#8230; These are handled reasonably well with package level variables as defaults for arguments not passed to the function (which isn&#8217;t such a big deal in a short test script) but the code to support those within the testing class itself isn&#8217;t particularly clean having to cope with defaults evaluation in multiple places.</p>
</li>
<li>
<p><strong>Only being able to return once from the function is a problem</strong>. Sometimes you might want to get extra data back after the test has completed. For example, when I wanted to allow you to optionally return the data extracted from the database I had to do it by allowing you to pass in the args to <code>row_ok</code> references to variables to be populated as it executes. Again, while this isn&#8217;t the end of the world from an external interface point of view, the effect it has on the internals (passing data up and down the stack) is horrible.</p>
</li>
</ul>
<p>For the sake of the internals I wanted things to change. However: I didn&#8217;t want to break the API. I decided to split the module into two halves. An simple external facing module that would provide the procedural interface, and an internal object orientated module that would allow me to produce a cleaner implementation.</p>
<h2 id="nomoosebutsomethingsimilar">No Moose, but something similar</h2>
<p>As I came to create Test::DatabaseRow::Object I found myself really wanting to write this new class with Moose. Now, Moose is a <em>very</em> heavyweight dependency; You don&#8217;t want to have to introduce a dependency on hundreds of modules just because you want to use a simple module to test your code. In fact, Test::DatabaseRow has no non-core dependencies apart from DBI itself, and I wanted to keep it this way with the refactoring. So, no Moose. No Mouse. No Moo. Just me and an editor.</p>
<p>In the end I compromised by deciding to code the module in a Moose &#8220;pull accessor&#8221; style even if I didn&#8217;t have Moose itself to provide the syntax to do this succinctly.</p>
<p>The approach I took was to put most of the logic for Test::DatabaseRow::Object &#8211; anything that potentially changes state of the object &#8211; into lazy loading read only accessors. Doing this allowed me to write my methods in a declarative style, relying entirely on the accessors performing the calculation to populate themselves the first time they&#8217;re accessed. For example. Test::DatabaseRow::Object has a read only accessor called <code>db_results</code> which goes to the database the first time it&#8217;s accessed and executes the SQL that&#8217;s needed to populate it (and the SQL itself comes from <code>sql_and_bind</code> which, unless explicitly stated in the constructor, is populated on first use from the <code>where</code> and <code>table</code> accessors and so on.)</p>
<p>Since I wasn&#8217;t using Moose this produced a lot more code than we&#8217;d normally expect to see, but because I was following a standard Moose conventions it&#8217;s still fairly easy to see what&#8217;s going on (I even went as far to leave a Moose style <code>has</code> accessor declaration in a comment above the blocks of code I had to write to sufficiently convey what I was doing.)</p>
<h2 id="aresultsobject">A results object</h2>
<p>The second big architectural change I made was to stop talking directly to Test::Builder. Instead I changed to returning a results object which was capable of rendering itself out to Test::Builder on demand.</p>
<p>This change made the internals a lot easier to deal with. I was able to break the test up into several functions each returning a success or failure object. As soon I was able to detect failure in any of these functions I could return it to Test::DatabaseRow, but if I got a success &#8211; which now hadn&#8217;t been rendered out to Test::Builder yet &#8211; I could throw it away and move onto the next potentially failing test while I still had other things to check.</p>
<p>This made implementing my missing feature, the ability to report on all rows returned from the database not just the first one, much easier to implement.</p>
<h2 id="problemsproblemsproblems">Problems, problems, problems</h2>
<p>After all this work, and spending hours improving the test coverage of the module, I still botched the release of 2.00. The old module tested the interface with DBI by checking against a database that was on my old laptop in 2003. Since I no longer had that laptop these tests weren&#8217;t being run (I actually deleted them since they were useless) and hence I didn&#8217;t notice when I&#8217;d broken the interface to DBI in my refactoring.</p>
<p>Ilmari pointed out I was being stupid a few minutes after I&#8217;d uploaded. Within ten minutes I&#8217;d written some DBI tests that test with SQLite (if you have DBD::SQLite installed) and released 2.01.</p>
<p>The biggest surprise was the next day where our overnight Hudson powered smokes failed at work, and the only thing that had changed was Test::DatabaseRow (we re-build our dependencies from the latest from CPAN every night, and it&#8217;d automatically picked up the changes.) Swapping in the old version passed. Putting the new version in failed. Had I missed something else in my testing?</p>
<p>No, I hadn&#8217;t.</p>
<p>After several hours of head scratching I eventually worked out that there was an extra bug in Test::DatabaseRow 1.04 that I&#8217;d not even realised was there, and I&#8217;d fixed it with 2.01. The tests were failing in our smokes but not because I&#8217;d broken the testing infrastructure, but because I&#8217;d <em>fixed it</em> and now I was detecting an actual problem in my Hudson test suite that had previously been unexposed.</p>
<h2 id="whatsnext">What&#8217;s next?</h2>
<p>Oh, I&#8217;m already planning Test::DatabaseRow 2.02. On github I&#8217;ve already closed a feature request that chromatic asked for in 2005. Want another feature? File a bug in RT. I&#8217;ll get to it sooner or later&#8230;</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/twoshortplanks.wordpress.com/279/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/twoshortplanks.wordpress.com/279/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/twoshortplanks.wordpress.com/279/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/twoshortplanks.wordpress.com/279/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/twoshortplanks.wordpress.com/279/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/twoshortplanks.wordpress.com/279/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/twoshortplanks.wordpress.com/279/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/twoshortplanks.wordpress.com/279/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/twoshortplanks.wordpress.com/279/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/twoshortplanks.wordpress.com/279/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/twoshortplanks.wordpress.com/279/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/twoshortplanks.wordpress.com/279/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/twoshortplanks.wordpress.com/279/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/twoshortplanks.wordpress.com/279/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=279&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.twoshortplanks.com/2011/11/18/testdatabaserow2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/5d71b5f0c61e97cd452d625cc24a4c82?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">2shortplanks</media:title>
		</media:content>
	</item>
		<item>
		<title>Dear Member of Parliment</title>
		<link>http://blog.twoshortplanks.com/2011/08/16/dearmp/</link>
		<comments>http://blog.twoshortplanks.com/2011/08/16/dearmp/#comments</comments>
		<pubDate>Tue, 16 Aug 2011 10:33:32 +0000</pubDate>
		<dc:creator>2shortplanks</dc:creator>
		
		<guid isPermaLink="false">http://blog.twoshortplanks.com/?p=270</guid>
		<description><![CDATA[As a Perl programmer, both my livelihood and a large chunk of my social life relies entirely on the internet. How would you react if the head of your government made public statements talking about restricting people internet access to people that they (and their agencies) "know" are doing wrong things.. <a href="http://blog.twoshortplanks.com/2011/08/16/dearmp/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=270&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>As a Perl programmer, both my livelihood and a large chunk of my social life relies entirely on the internet. How would you react if the head of your government made public statements talking about restricting people internet access to people that they (and their agencies) &#8220;know&#8221; are doing wrong things&#8230;</p>
<blockquote><p>
&#8230;we are working with the Police, the intelligence services and industry to look at whether it would be right to stop people communicating via these websites and services when we know they are plotting violence, disorder and criminality.
</p></blockquote>
<div align="right"><small><cite>David Cameron, UK Prime Minister</cite></small></div>
<p>In response, I wrote to my MP.  I encourage those of you from the UK to <a href="http://www.writetothem.com">do the same</a>.</p>
<blockquote><p>
Dear Duncan Hames,</p>
<p>I write to you today to express my concerns regarding statements made by the prime minister with respect to restricting access to &#8220;social media&#8221;.</p>
<p>It should be fairly obvious when the chinese regime are praising our censorship plans that they are ill thought through and should be scrapped.</p>
<p>However obvious I feel that I must still enumerate the ways that this plan is wrong on many levels.</p>
<p>Firstly, your prime minister seems unable to distinguish between the medium and the message.  As we move more and more into the digital age more and more communication will take new forms, these new forms will replace more traditional forms of communication in society.  To seek to control over some forms of commutation is modern equivalent of the<br />
government seeking to control the ability for its citizens to write to newspapers or talk in the street.</p>
<p>Secondly, the idea of the government silencing it&#8217;s citizens from communicating with one another is chilling.  While I can understand that some speech may be criminal by it&#8217;s content, woe befall any government who tries to pre-emptively stop such speech, as these very same controls can be used, and abused, to control its citizens.</p>
<p>Thirdly, the prime minister is seeking to put restrictions on people that have not been convicted of a crime (he said, I quote, &#8220;when we know they are plotting violence, disorder and criminality&#8221;, but that is a matter for the courts not the &#8220;[the government,] the Police, the intelligence services and industry&#8221; to decide.)  What safeguards are<br />
being proposed that I, a law abiding citizen, may not also be restricted from communication?</p>
<p>Fourthly, and ironically, your prime minister is suggesting restricting the primary ability for communication with wider society by those individuals who he claims live outside of our society.</p>
<p>Finally, I do not understand your prime minister&#8217;s desire to push for further attention grabbing legislation when our police force can already wield the RIP Act to gather evidence from these new forms of communication.  While I may not agree with the RIP Act, let our police forces use these powers to full effect before granting them new ones.</p>
<p>As a member of your constituency I ask you to ensure that your prime minister is questioned about such blatant flaws in his proposals in parliment.</p>
<p>Thanking you in advance for your help in this matter</p>
<p>Yours sincerely,</p>
<p>Mark Fowler
</p></blockquote>
<p>Those wanting to do more could do a lot worse than set up a regular donation to the <a href="http://www.openrightsgroup.org/">Open Rights Group</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/twoshortplanks.wordpress.com/270/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/twoshortplanks.wordpress.com/270/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/twoshortplanks.wordpress.com/270/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/twoshortplanks.wordpress.com/270/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/twoshortplanks.wordpress.com/270/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/twoshortplanks.wordpress.com/270/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/twoshortplanks.wordpress.com/270/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/twoshortplanks.wordpress.com/270/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/twoshortplanks.wordpress.com/270/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/twoshortplanks.wordpress.com/270/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/twoshortplanks.wordpress.com/270/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/twoshortplanks.wordpress.com/270/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/twoshortplanks.wordpress.com/270/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/twoshortplanks.wordpress.com/270/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=270&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.twoshortplanks.com/2011/08/16/dearmp/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/5d71b5f0c61e97cd452d625cc24a4c82?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">2shortplanks</media:title>
		</media:content>
	</item>
		<item>
		<title>London Calling</title>
		<link>http://blog.twoshortplanks.com/2011/08/05/london-calling/</link>
		<comments>http://blog.twoshortplanks.com/2011/08/05/london-calling/#comments</comments>
		<pubDate>Fri, 05 Aug 2011 08:27:42 +0000</pubDate>
		<dc:creator>2shortplanks</dc:creator>
		
		<guid isPermaLink="false">http://blog.twoshortplanks.com/?p=263</guid>
		<description><![CDATA[Now that I don't live in London anymore (I live in Chippenham, which is eighty two miles away) I don't often get to go to the London Perl Monger Socials, but last night with the meeting happening right by Paddington Station it was too good an chance to miss.
 <a href="http://blog.twoshortplanks.com/2011/08/05/london-calling/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=263&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Now that I don&#8217;t live in London anymore (I live in Chippenham, which is eighty two miles away) I don&#8217;t often get to go to the London Perl Monger Socials, but last night with the meeting happening right by Paddington Station it was too good an chance to miss.</p>
<p>The hot topic of conversation was obviously the impending YAPC::Europe conference.  I sadly won&#8217;t be attending, since I just got back from my trip to YAPC::NA (which I owe a blog post on,) but I was able to give good advise on what talks to go see having already seen the US versions.  There seemed to be a significant amount of problems with clashes in the schedule in Latvia that I can sympathise with.  For example, I was recommending Jesse&#8217;s talk on 5.16 (which I really enjoyed at YAPC::NA,) but it was pointed out that he&#8217;s up against Smylers who I think is also an entertaining and informative speaker.</p>
<p>Jesse&#8217;s talk at YAPC::NA on 5.16 generated quite a bit of conversation around the tables.  Taking a straw poll of the people present I think that they liked the direction that&#8217;s being proposed and those that could would be attending the talk in Latvia to hear more in person.  People in general liked the idea of making the language (optionally) more consistent, easier to parse and more consistent without losing the ability to run older more sloppy code.  Jesse might have been shocked that in Ashville people clapped rather than booed his suggestion that the indirect object syntax not be allowed under &#8220;use 5.16&#8243; but at work we enforce &#8220;no indirect;&#8221; on all our code anyway.  The idea of laying the ground work for possibly re-implementing perl 5 (not Perl, but &#8220;perl&#8221;, the interpreter) by making cleaner syntax was one thing that Jesse said in his talk that people at the social thought was interesting.  Sam Villian pointed out that Git seems to have been re-implemented multiple times and this has been a big advantage for it.</p>
<p>Nicholas Clarke arrived hot and in need of beer after running for the train, being delayed after writing grant proposals.  This kicked off a discussion about the TPF core maintenance grant which morphed into a discussion about the availability of talent to work on Perl 5 core issues (We had both Nicholas and Zefram sitting round the table &#8211; that&#8217;s not a bad chunk of the talent pool in itself.)  In short my opinion is that the more work that&#8217;s done on the Perl core the more interest we&#8217;ll attract, and that&#8217;s a good thing.</p>
<p>Problems with hiring in general were discussed;  I pointed out that at YAPC::NA lots of companies were hiring and offering telecommute positions so they could get the talent they needed.  The outragerous costs charged by not very effective recruiters were mentioned and the real need for high quality technically savvy recruiters (or at least, recruiters with technical experts) was identified as a gap in the market.</p>
<p>For some reason at some point we got into a big discussion about unicode.  Ilmari showed us his awesome library card with &#8220;Manns&aring;ker&#8221; written as &#8220;MannsAyker&#8221;.  &#8220;Manns&aring;ker&#8221; had obviously gone through some terrible UTF-8 bytecode into Latin-1 conversion resulting in &#8220;Manns&Atilde;&yen;ker&#8221; and then someone seems to have re-typed that into it&#8217;s ASCII equivalent.  It&#8217;s not like his donor card was much better either!  This morphed in a discussion about failed attempts to get domain name registrars to adopt proper unicode characters (and the various security issues related around that.)  I wonder if the IT industry will be dealing with this in twenty years time?  Probably.</p>
<p>As is fitting for any modern IT meetup these days we talked a bit about the problems of scale.  This progressed into discussion of the problems of disaster recovery preparation; It&#8217;s very hard to test without impacting customers (it&#8217;s easier if you&#8217;ve got completely redundant systems and you&#8217;re willing to invest into DR with a zero downtime switchover but that&#8217;s rare) and it&#8217;s actually quite hard to get a grip on what you have and haven&#8217;t got covered (systems change rapidly and delaying rollouts to make sure full DR cover is in place may result in a large lost opportunity cost.)</p>
<p>Of course, London.pm still (in addition to all the Perl and computing talk) ricochets between geek trivia and the usual trappings of good friends. &#8220;Why don&#8217;t we talk about Buffy and more?&#8221;, &#8220;Well, what about Ponies?&#8221;, &#8220;Hey, All the cool kids on the internet like My Little Pony these days&#8221;. &#8220;Speaking of kids, is your daughter crawling yet?&#8221; &#8220;She&#8217;s sitting up and waving&#8221;, &#8220;Oh, while I remember, here&#8217;s the bib your youngest left at our house last week&#8221;</p>
<p>As always, I had fun, and I look forward to attending again another time soon.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/twoshortplanks.wordpress.com/263/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/twoshortplanks.wordpress.com/263/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/twoshortplanks.wordpress.com/263/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/twoshortplanks.wordpress.com/263/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/twoshortplanks.wordpress.com/263/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/twoshortplanks.wordpress.com/263/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/twoshortplanks.wordpress.com/263/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/twoshortplanks.wordpress.com/263/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/twoshortplanks.wordpress.com/263/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/twoshortplanks.wordpress.com/263/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/twoshortplanks.wordpress.com/263/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/twoshortplanks.wordpress.com/263/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/twoshortplanks.wordpress.com/263/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/twoshortplanks.wordpress.com/263/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=263&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.twoshortplanks.com/2011/08/05/london-calling/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/5d71b5f0c61e97cd452d625cc24a4c82?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">2shortplanks</media:title>
		</media:content>
	</item>
		<item>
		<title>Unexceptional Exceptions in Perl 5.14</title>
		<link>http://blog.twoshortplanks.com/2011/06/06/unexceptional-exceptions-in-perl-5-14/</link>
		<comments>http://blog.twoshortplanks.com/2011/06/06/unexceptional-exceptions-in-perl-5-14/#comments</comments>
		<pubDate>Mon, 06 Jun 2011 08:37:54 +0000</pubDate>
		<dc:creator>2shortplanks</dc:creator>
		
		<guid isPermaLink="false">http://blog.twoshortplanks.com/?p=260</guid>
		<description><![CDATA[There's a lot to love about Perl 5.14, but one of the best changes is a subtle one:  Native exception handling is now reliable. <a href="http://blog.twoshortplanks.com/2011/06/06/unexceptional-exceptions-in-perl-5-14/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=260&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s a lot to love about Perl 5.14, but one of the best changes is a subtle one:  Native exception handling is now reliable.</p>
<p>Perl&#8217;s native exception syntax uses an eval block as the traditional &#8220;try&#8221; block, and requires checking <code>$@</code> to see if it contains an exception.</p>
<p><code>
<pre>  eval {
    ...; # do something that might throw an exception
  };

  if ($@) {
    ...; # handle exception here
  }</pre>
<p></code></p>
<p>Just like other languages code in the block is evaluated until an exception is thrown and then control jumps out of the block.  Perl doesn&#8217;t have a native <code>catch</code> syntax however &#8211; it simply puts the exception into <code>$@</code> where you can check it with a standard if statement.</p>
<p>Herein lies the problem in all versions of Perl prior to 5.14.  Prior to 5.14 <code>$@</code> is assigned and then the block is immediately exited;  With 5.14 the block is immediately exited and then <code>$@</code> is assigned.  A subtle, but important difference.</p>
<p>Perl&#8217;s improvised catch mechanism <em>relies</em> on <code>eval</code> undefining <code>$@</code> if no exception occurred (so the <code>if</code> block won&#8217;t execute.)  Each time Perl executes an eval therefore it must undefine $@.  Prior to 5.14 this interacts <em>badly</em> with object destructors.</p>
<p><code>
<pre>  package SomethingComplex;
  sub new { return bless {}, shift };
  sub DESTROY {
    eval {
      ...; # some cleanup code that might throw an exception
    };
    if ($@) {
      ...; # handle exception in cleanup code
    }
  }

  package main;

  eval {
    my $thingy = SomethingComplex-&gt;new();
    ...; # do something that might throw an exception
  };
  if ($@) {
    ...; # will never be executed even on exception
  }</pre>
<p></code></p>
<p>If an exception occurs in the eval block in main then execution will stop and control will immediately jump out of the block.  <code>$thingy</code> will fall out of scope.  When this happens the object&#8217;s <code>DESTROY</code> block will be executed.  This in turn runs its own <code>eval</code> which will unset <code>$@</code> as it executes.   Assuming another exception doesn&#8217;t occur during cleanup by the time we reach the <code>if</code> statement in main <code>$@</code> will have been undefined even though an exception happened in the <code>eval</code> block immediately above.  Disaster!</p>
<p>The, simple, quite frankly terrible, workaround is to write this:</p>
<p><code>
<pre>  eval {
    ...; # do something that might throw an exception
    1;
  } or do {
    ...; # handle the exception here
  }</pre>
<p></code></p>
<p>We&#8217;re no longer relying on the <code>$@</code> to tell that an exception has occurred but on the fact that an eval block quill return false on exception handling.  Of course, we can&#8217;t now reliably look at <code>$@</code> to find out what kind of exception occurred.  There&#8217;s ways around this, but they&#8217;re even more complex to code.</p>
<p>A better fix on Perl&#8217;s prior to 5.14 is to use the Try::Tiny module from the CPAN that handles all of this for us.</p>
<p><code>
<pre>  use Try::Tiny;
  try {
    ...; # do something that might cause an exception.
  } catch {
    ...; # handle the exception stored in $_ here
  };</pre>
<p></code></p>
<p>Of course, no matter how tiny Try::Tiny is, there&#8217;s no getting away from the fact that it&#8217;s not a module that&#8217;s bundled with Perl;  I can rely on getting it installed whenever I install software, but not on every machine I might happen to admin and want to make use of the system perl.</p>
<p>Luckily, Perl 5.14 solves this problem entirely for us by executing the block first &#8211; therefore executing all destructors that might mess with <code>$@</code> first &#8211; and then, once all that&#8217;s done, populating <code>$@</code> with the exception.</p>
<p>Thanks Perl 5 Porters!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/twoshortplanks.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/twoshortplanks.wordpress.com/260/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/twoshortplanks.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/twoshortplanks.wordpress.com/260/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/twoshortplanks.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/twoshortplanks.wordpress.com/260/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/twoshortplanks.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/twoshortplanks.wordpress.com/260/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/twoshortplanks.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/twoshortplanks.wordpress.com/260/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/twoshortplanks.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/twoshortplanks.wordpress.com/260/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/twoshortplanks.wordpress.com/260/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/twoshortplanks.wordpress.com/260/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=260&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.twoshortplanks.com/2011/06/06/unexceptional-exceptions-in-perl-5-14/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/5d71b5f0c61e97cd452d625cc24a4c82?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">2shortplanks</media:title>
		</media:content>
	</item>
		<item>
		<title>A Rose By Any Other Name</title>
		<link>http://blog.twoshortplanks.com/2011/01/30/hostify/</link>
		<comments>http://blog.twoshortplanks.com/2011/01/30/hostify/#comments</comments>
		<pubDate>Sun, 30 Jan 2011 06:36:34 +0000</pubDate>
		<dc:creator>2shortplanks</dc:creator>
		
		<guid isPermaLink="false">http://blog.twoshortplanks.com/?p=251</guid>
		<description><![CDATA[In this blog post I'm going to talk about writing a Perl script to automatically change entries in my local /etc/hosts file, and I'll digress into brief discussions on Net::DNS, how to edit files in place using Tie::File, and the sneaky <code>-s</code> switch for dumb command line argument parsing.
 <a href="http://blog.twoshortplanks.com/2011/01/30/hostify/">Continue reading <span class="meta-nav">&#8594;</span></a><img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=251&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>In this blog post I&#8217;m going to talk about writing a Perl script to automatically change entries in my local /etc/hosts file, and I&#8217;ll digress into brief discussions on Net::DNS, how to edit files in place using Tie::File, and the sneaky <code>-s</code> switch for dumb command line argument parsing.</p>
<h2>The Problem I&#8217;m Trying to Solve</h2>
<p>I&#8217;ll just come out and say it:  I don&#8217;t like using the default DNS servers assigned to my laptop by DHCP servers.  In the case of my home network I get the buggy DNS server from my ISP that doesn&#8217;t work as often as I&#8217;d like.  In the case of my work network I often get hostnames resolved to internal IP addresses for servers where (because of my particular job) I really want the public ones.  To avoid the issue completely I hard code my DNS to always point at Google&#8217;s free DNS service on <code>8.8.8.8</code>.  There&#8217;s just one problem with this:</p>
<pre>bash$ ssh sandbox1.dev.example.priv
ssh: Could not resolve hostname sandbox1.dev.example.prvi: nodename nor servname provided, or not known</pre>
<p>Ooops! Entries for my development servers only exists on our local work DNS server and if I&#8217;m not using it I can&#8217;t find any of them!</p>
<p>Luckily my Mac (and other unix like boxes) allows me to override DNS servers using the <code>/etc/hosts</code> file (Windows has something similar too.)  In its simplest form this file contains one override per line, an IP address followed by one or more hostnames it overrides.  For example:</p>
<p>   10.0.0.1 sandbox1.dev.example.priv<br />
   10.0.0.2 sandbox2.dev.example.priv<br />
   10.0.1.1 db.dev.example.priv</p>
<p>And so on.  My kludgy soliton is for each development server that I want to use to put a line in <code>/etc/hosts</code> so I don&#8217;t have to remember it&#8217;s IP address (and more importantly, so I can use the addresses in my browser and still have it map to the right virtual host on the webserver.)  However, doing this by hand gets old <em>real</em> quick.  Running <code>dig</code> against the company DNS server&#8217;s IP address, copying and pasting the resolved IP address into the hosts file using a text editor is something that takes the better part of a minute, is prone to mistakes, and completely interrupts my train of thought.  What I want is a simple command to automate the whole process of adding or updating an entry like this:</p>
<pre>bash$ hostify sandbox.dev.example.com</pre>
<p>And maybe I could have it update all the entries that it knows about so they don&#8217;t get out of date whenever I type:</p>
<pre>bash$ hostify -r</pre>
<p>Right! Time to write some Perl.</p>
<h2>Using Net::DNS to do DNS lookups</h2>
<p>You&#8217;d think that dealing with the complexities of DNS would be the hard bit, but looking up domain names with Perl is actually really trivial.  We can almost copy the example out of the perldoc for <a href="http://search.cpan.org/dist/Net-DNS">Net::DNS</a>:</p>
<pre>
my $res = Net::DNS::Resolver-&gt;new(
  nameservers =&gt; [qw(10.5.0.1)],
);

my $query = $res-&gt;search($hostname);

if ($query) {
  foreach my $rr ($query-&gt;answer) {
    next unless $rr-&gt;type eq "A";
    say "Found an A record: ".$rr-&gt;address;
  }
}
</pre>
<p>And that&#8217;s about all there is to it.  Now for the hard bit&#8230;</p>
<h2>Using Tie::File to edit a file in place</h2>
<p>We either need to add an entry to our existing <code>/etc/hosts</code> file or update one or more entries in the middle of the file.  However, if we were to use the standard <code>open</code> function that Perl provides we&#8217;re going to quickly run into a problem:  The open (and sysopen) syntax is optomised for either appending data onto the end of the file, or in a pinch overwriting byte for byte in the middle of the file.  What it won&#8217;t do is automatically handle the case where we want to replace something in the middle of the file with more or fewer bytes.  We end up having to manually read in and echo out the tail end of the file which results in us having to write a lot of complex &#8220;bookkeeping&#8221; code we&#8217;d rather not concern ourselves with.</p>
<p>One of the easiest ways in Perl to edit a file in place without worry about these niggly details is to instead use a core module called <a href="http://search.cpan.org/dist/Tie-File">Tie::File</a>.  This module uses a magic feature in Perl called <em>tieing</em> where some functionality is <em>tied</em> to a Perl data structure &#8211; any attempts to read from or modify the tied data structure cause Perl code to be executed to do something clever instead of modifying a dumb chunk of memory.  In the case of Tie::File each element in the array that it ties maps to a line in the file on disk &#8211; reading from the array reads in lines from the file, and writing to the array writes out to disk.</p>
<p>So, for example, to <em>tie</em> our array to the hosts file, we just need to use the special <code>tie</code> syntax:</p>
<pre>tie my @file, 'Tie::File', "/etc/hosts"
  or die "Can't open /etc/hosts: $!";</pre>
<p>Now altering a line in the middle of our file is simple:</p>
<pre># alter the 21st line in the file
$file[20] = "10.0.69.1 filestore.example.priv";</pre>
<p>Tie::File seamlessly handles all the complicated bits about moving the stuff after the line we&#8217;ve just altered.  Perfect!</p>
<h2>Rudimentary argument passing with <code>-s</code></h2>
<p>My script needs to be able to only accept one simple command line option to tell it to also update all hostnames it&#8217;s previously inserted.  Because I&#8217;m lazy, I didn&#8217;t even use a module to do this but rather used the simple <code>-s</code> command line option to tell perl to shove anything it sees on the command line starting with a dash into a similarly named variable in the main namespace:</p>
<pre>#!/usr/bin/env perl -s
if ($r) { print "Someone called us with -r\n" }</pre>
<p>Of course, with strictures and warnings on I have to write something a little more complex:</p>
<pre>#!/usr/bin/env perl -s
use 5.12.0;
use warnings;
if ($::r &amp;&amp; $::r) { say "Someone called us with -r" }</pre>
<p>I need to use <code>$::r</code> not <code>$r</code> because the former, being a fully qualified variable, doesn&#8217;t need predeclaration when running under <code>use strict</code> (which is implicitly turned on when I asked to <code>use 5.12.0</code>.)   I also need to use <code>$::r &amp;&amp; $::r</code> not <code>$::r</code> because otherwise warnings would notice that the variable was only being used once in the entire run of the code and emit a warning (this is one of the rare cases where this isn&#8217;t a bug &#8211; the variable really does get its value without ever being set by Perl code.)</p>
<h2>The Complete Script</h2>
<p>And here&#8217;s the complete finished script.</p>
<pre>#!/usr/bin/env perl -s

use 5.12.0;
use warnings;

use Net::DNS;
use Tie::File;

# look at the file
tie my @file, 'Tie::File', "/etc/hosts"
  or die "Can't open /etc/hosts: $!";

# did someone want to update all the cached entires?
if ($::r &amp;&amp; $::r) {
  my $found = 0;
  foreach (@file) {
    # skip down until the comment in my /etc/hosts that
    # states that "cached entries are below this point"
    next unless $found ||= m/cached entries/; 

    # then replace each host entry
    s{\A\d+\.\d+\.\d+\.\d+\s+(?&lt;host&gt;.*)\z}{
       dns_lookup($+{host}) . " $+{host}";
     }e;
  }
  exit unless @ARGV;
}

my $host = shift // die "No hostname supplied\n";
my $ip = dns_lookup( $host );

# look for an existing entry and replace it
foreach (@file) {
  exit if s/\A\d+\.\d+\.\d+\.\d+\s+\Q$host\E\z/$ip $host/;
}

# not found?  Add it to the end
push @file, "$ip $host";

########################################################################

sub dns_lookup {
  my $hostname = shift;

  my $res = Net::DNS::Resolver-&gt;new(
    nameservers =&gt; [qw(10.5.0.1)],
  );

  my $query = $res-&gt;search($hostname);

  if ($query) {
    foreach my $rr ($query-&gt;answer) {
      next unless $rr-&gt;type eq "A";
      return $rr-&gt;address;
    }
    die "No A record for $hostname";
  }

  die "query for $hostname failed: ", $res-&gt;errorstring;
}</pre>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/twoshortplanks.wordpress.com/251/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/twoshortplanks.wordpress.com/251/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/twoshortplanks.wordpress.com/251/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/twoshortplanks.wordpress.com/251/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/twoshortplanks.wordpress.com/251/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/twoshortplanks.wordpress.com/251/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/twoshortplanks.wordpress.com/251/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/twoshortplanks.wordpress.com/251/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/twoshortplanks.wordpress.com/251/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/twoshortplanks.wordpress.com/251/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/twoshortplanks.wordpress.com/251/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/twoshortplanks.wordpress.com/251/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/twoshortplanks.wordpress.com/251/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/twoshortplanks.wordpress.com/251/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.twoshortplanks.com&amp;blog=8961906&amp;post=251&amp;subd=twoshortplanks&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.twoshortplanks.com/2011/01/30/hostify/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/5d71b5f0c61e97cd452d625cc24a4c82?s=96&#38;d=monsterid&#38;r=G" medium="image">
			<media:title type="html">2shortplanks</media:title>
		</media:content>
	</item>
	</channel>
</rss>
