<?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/"
	>

<channel>
	<title>Kerry Buckley &#187; Ruby</title>
	<atom:link href="http://www.kerrybuckley.org/category/software/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.kerrybuckley.org</link>
	<description>What's the simplest thing that could possibly go wrong?</description>
	<lastBuildDate>Wed, 30 Nov 2011 11:26:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Memoised remote attribute readers for ActiveRecord</title>
		<link>http://www.kerrybuckley.org/2010/04/27/memoised-remote-attribute-readers-for-activerecord/</link>
		<comments>http://www.kerrybuckley.org/2010/04/27/memoised-remote-attribute-readers-for-activerecord/#comments</comments>
		<pubDate>Tue, 27 Apr 2010 11:29:29 +0000</pubDate>
		<dc:creator>Kerry</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.kerrybuckley.org/?p=377</guid>
		<description><![CDATA[I was recently working with an ActiveRecord class that exposed some attributes retrieved from a remote API, rather than from the database. The rules for handling the remote attributes were as follows: If the record is unsaved, return the local value of the attribute, even if it's nil. If the record is saved and we [...]]]></description>
			<content:encoded><![CDATA[<p>I was recently working with an ActiveRecord class that exposed some attributes retrieved from a remote API, rather than from the database. The rules for handling the remote attributes were as follows:</p>
<ul>
<li>If the record is unsaved, return the local value of the attribute, even if it's nil.</li>
<li>If the record is saved and we don't have a local value, call the remote API and remember and return the value.</li>
<li>If the record is saved and we already have a local value, return that.</li>
</ul>
<p>Here's the original code (names changed to protect the innocent):</p>
<div class="igBar"><span id="lruby-8"><a href="#" onclick="javascript:showCodeTxt('ruby-8'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-8">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> MyModel &lt;ActiveRecord::Base</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; attr_writer :foo, :bar</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> foo</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span>new_record? || @foo<span style="color:#006600; font-weight:bold;">&#41;</span> ? @foo : remote_object.<span style="color:#9900CC;">foo</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> bar</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span>new_record? || @bar<span style="color:#006600; font-weight:bold;">&#41;</span> ? @bar : remote_object.<span style="color:#9900CC;">bar</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> remote_object</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; @remote_object ||= RemoteService.<span style="color:#9900CC;">remote_object</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>The <code>remote_object</code> method makes a call to the remote service, and memoises the returned object (which contains all the attributes we are interested in).</p>
<p>I didn't really like the duplication in all these accessor methods &ndash; we had more than the two I've shown here &ndash; so decided to factor it out into a common <code>remote_attr_reader</code> class method. Originally I had the method take a block which returned the remote value, but that made the tests more complicated, so I ended up using convention over configuration and having the accessor for <em>foo</em> call a <em>remote_foo</em> method.</p>
<p>Here's the new code in the model:</p>
<div class="igBar"><span id="lruby-9"><a href="#" onclick="javascript:showCodeTxt('ruby-9'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-9">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> MyModel &lt;ActiveRecord::Base</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; remote_attr_reader :foo, :bar</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> remote_foo</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; remote_object.<span style="color:#9900CC;">foo</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> remote_bar</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; remote_object.<span style="color:#9900CC;">bar</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> remote_object</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; @remote_object ||= RemoteService.<span style="color:#9900CC;">remote_object</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Here's the <code>RemoteAttrReader</code> module that makes it possible:</p>
<div class="igBar"><span id="lruby-10"><a href="#" onclick="javascript:showCodeTxt('ruby-10'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-10">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">module</span> RemoteAttrReader</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> remote_attr_reader *names</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; names.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |name|</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; attr_writer name</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; define_method name <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> new_record? || instance_variable_get<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">"@#{name}"</span><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; instance_eval <span style="color:#996600;">"@#{name}"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">else</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; instance_eval <span style="color:#996600;">"remote_#{name}"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>To make the module available to all models, I added an initialiser containing this line:</p>
<div class="igBar"><span id="lruby-11"><a href="#" onclick="javascript:showCodeTxt('ruby-11'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-11">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">ActiveRecord::Base.<span style="color:#9900CC;">send</span> :extend, RemoteAttrReader </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Here's the spec for the module:</p>
<div class="igBar"><span id="lruby-12"><a href="#" onclick="javascript:showCodeTxt('ruby-12'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-12">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">require</span> File.<span style="color:#9900CC;">dirname</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF; font-weight:bold;">__FILE__</span><span style="color:#006600; font-weight:bold;">&#41;</span> + '/../spec_helper'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> RemoteAttrReaderTestClass</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; extend RemoteAttrReader</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; remote_attr_reader :foo</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> remote_foo</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#996600;">"remote value"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">describe RemoteAttrReader <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; let<span style="color:#006600; font-weight:bold;">&#40;</span>:model<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> RemoteAttrReaderTestClass.<span style="color:#9900CC;">new</span> <span style="color:#006600; font-weight:bold;">&#125;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; describe <span style="color:#996600;">"for an unsaved object"</span> <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; before <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; model.<span style="color:#9900CC;">stub</span><span style="color:#006600; font-weight:bold;">&#40;</span>:new_record?<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">and_return</span> <span style="color:#0000FF; font-weight:bold;">true</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; describe <span style="color:#996600;">"When the attribute is not set"</span> <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; it <span style="color:#996600;">"returns nil"</span> <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; model.<span style="color:#9900CC;">foo</span>.<span style="color:#9900CC;">should</span> be_nil</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; describe <span style="color:#996600;">"When the attribute is set"</span> <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; before <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; model.<span style="color:#9900CC;">foo</span> = <span style="color:#996600;">"foo"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; it <span style="color:#996600;">"returns the attribute"</span> <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; model.<span style="color:#9900CC;">foo</span>.<span style="color:#9900CC;">should</span> == <span style="color:#996600;">"foo"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; describe <span style="color:#996600;">"for a saved object"</span> <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; before <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; model.<span style="color:#9900CC;">stub</span><span style="color:#006600; font-weight:bold;">&#40;</span>:new_record?<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">and_return</span> <span style="color:#0000FF; font-weight:bold;">false</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; describe <span style="color:#996600;">"When the attribute is set"</span> <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; before <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; model.<span style="color:#9900CC;">foo</span> = <span style="color:#996600;">"foo"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; it <span style="color:#996600;">"returns the attribute"</span> <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; model.<span style="color:#9900CC;">foo</span>.<span style="color:#9900CC;">should</span> == <span style="color:#996600;">"foo"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; describe <span style="color:#996600;">"When the attribute is not set"</span> <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; it <span style="color:#996600;">"returns the result of calling remote_&lt;attribute&gt;"</span> <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; model.<span style="color:#9900CC;">foo</span>.<span style="color:#9900CC;">should</span> == <span style="color:#996600;">"remote value"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>To simplify testing of the model, I created a matcher, which I put into a file in <code>spec/support</code>:</p>
<div class="igBar"><span id="lruby-13"><a href="#" onclick="javascript:showCodeTxt('ruby-13'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-13">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> ExposeRemoteAttribute</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> initialize attribute</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; @attribute = attribute</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> matches? model</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; @model = model</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> <span style="color:#0000FF; font-weight:bold;">false</span> <span style="color:#9966CC; font-weight:bold;">unless</span> model.<span style="color:#9900CC;">send</span><span style="color:#006600; font-weight:bold;">&#40;</span>@attribute<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#0000FF; font-weight:bold;">nil</span>?</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; model.<span style="color:#9900CC;">send</span> <span style="color:#996600;">"#{@attribute}="</span>, <span style="color:#996600;">"foo"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> <span style="color:#0000FF; font-weight:bold;">false</span> <span style="color:#9966CC; font-weight:bold;">unless</span> model.<span style="color:#9900CC;">send</span><span style="color:#006600; font-weight:bold;">&#40;</span>@attribute<span style="color:#006600; font-weight:bold;">&#41;</span> == <span style="color:#996600;">"foo"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; model.<span style="color:#9900CC;">stub</span><span style="color:#006600; font-weight:bold;">&#40;</span>:new_record?<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">and_return</span> <span style="color:#0000FF; font-weight:bold;">false</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> <span style="color:#0000FF; font-weight:bold;">false</span> <span style="color:#9966CC; font-weight:bold;">unless</span> model.<span style="color:#9900CC;">send</span><span style="color:#006600; font-weight:bold;">&#40;</span>@attribute<span style="color:#006600; font-weight:bold;">&#41;</span> == <span style="color:#996600;">"foo"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; model.<span style="color:#9900CC;">send</span> <span style="color:#996600;">"#{@attribute}="</span>, <span style="color:#0000FF; font-weight:bold;">nil</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; model.<span style="color:#9900CC;">stub</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">"remote_#{@attribute}"</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">and_return</span> <span style="color:#996600;">"bar"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; model.<span style="color:#9900CC;">send</span><span style="color:#006600; font-weight:bold;">&#40;</span>@attribute<span style="color:#006600; font-weight:bold;">&#41;</span> == <span style="color:#996600;">"bar"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> failure_message_for_should</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#996600;">"expected #{@model.class} to expose remote attribute #{@attribute}"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> failure_message_for_should_not</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#996600;">"expected #{@model.class} not to expose remote attribute #{@attribute}"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> description</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#996600;">"expose remote attribute #{@attribute}"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> expose_remote_attribute expected</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; ExposeRemoteAttribute.<span style="color:#9900CC;">new</span> expected</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Testing the model now becomes a simple case of testing the <em>remote_</em> methods in isolation, and using the matcher to test the behaviour of the <em>remote_attr_reader</em> call(s).</p>
<div class="igBar"><span id="lruby-14"><a href="#" onclick="javascript:showCodeTxt('ruby-14'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-14">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">require</span> File.<span style="color:#9900CC;">dirname</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF; font-weight:bold;">__FILE__</span><span style="color:#006600; font-weight:bold;">&#41;</span> + '/../spec_helper'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">describe MyModel <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; it <span style="color:#006600; font-weight:bold;">&#123;</span> should expose_remote_attribute<span style="color:#006600; font-weight:bold;">&#40;</span>:name<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#125;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; it <span style="color:#006600; font-weight:bold;">&#123;</span> should expose_remote_attribute<span style="color:#006600; font-weight:bold;">&#40;</span>:origin_server<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#125;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; it <span style="color:#006600; font-weight:bold;">&#123;</span> should expose_remote_attribute<span style="color:#006600; font-weight:bold;">&#40;</span>:delivery_domain<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#125;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; describe <span style="color:#996600;">"reading remote foo"</span> <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># test as a normal method</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Technorati Tags: <a href="http://technorati.com/tag/ruby" rel="tag">ruby</a>, <a href="http://technorati.com/tag/rails" rel="tag">rails</a>, <a href="http://technorati.com/tag/activerecord" rel="tag">activerecord</a>, <a href="http://technorati.com/tag/metaprogramming" rel="tag">metaprogramming</a>, <a href="http://technorati.com/tag/rspec" rel="tag">rspec</a>, <a href="http://technorati.com/tag/matcher" rel="tag">matcher</a>, <a href="http://technorati.com/tag/refactoring" rel="tag">refactoring</a>, <a href="http://technorati.com/tag/dry" rel="tag">dry</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrybuckley.org/2010/04/27/memoised-remote-attribute-readers-for-activerecord/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Managing gems in a Rails project</title>
		<link>http://www.kerrybuckley.org/2009/11/02/managing-gems-in-a-rails-project/</link>
		<comments>http://www.kerrybuckley.org/2009/11/02/managing-gems-in-a-rails-project/#comments</comments>
		<pubDate>Mon, 02 Nov 2009 17:24:10 +0000</pubDate>
		<dc:creator>Kerry</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.kerrybuckley.org/?p=321</guid>
		<description><![CDATA[Over the years I've tried a number of approaches for managing gem dependencies in a Rails project. Here's a quick round-up of what I've tried, and the pros and cons of each. Just use what's on the system This is probably most people's default approach when first starting with Rails. Just sudo gem install whatever [...]]]></description>
			<content:encoded><![CDATA[<p>Over the years I've tried a number of approaches for managing gem dependencies in a Rails project. Here's a quick round-up of what I've tried, and the pros and cons of each.</p>
<h4>Just use what's on the system</h4>
<p>This is probably most people's default approach when first starting with Rails. Just <code>sudo gem install</code> whatever you need, require the appropriate gems (either in <code>environment.rb</code> or in the class that uses them), and you're away.</p>
<p>This mostly works OK for small projects where you're the only developer, but you still need to make sure the right gems are installed on the machine you're deploying the application to.</p>
<p>Worse, though, is what happens when you come back to the project after a while, various gems have been updated, and things mysteriously don't work any more. Not only do you have to mess around getting the code to work with the latest gem versions, but you probably don't even know exactly which versions it used to work with.</p>
<h4>Freeze (unpack) gems</h4>
<p>I think I first came across this technique in Err the Blog's <a href="http://errtheblog.com/posts/50-vendor-everything">Vendor Everything</a> post. The idea is to install copies of all your gems into the project's vendor/gems directory, meaning that wherever the code is running, you can guarantee that it has the correct versions of all its dependencies.</p>
<p>This <a href="http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies">got much easier in Rails 2.1</a>, which allowed you to specify all your gems using <code>config.gem</code> lines in <code>environment.rb</code> (you can also put gems only needed in specific environments in the appropriate file, eg you might only want to list things like rspec and cucumber in <code>config/enviroments/test.rb</code>). You can then run <code>sudo rake gems:install</code> to install any gems that aren't on your system, and <code>rake gems:unpack</code> to freeze them into <code>vendor/rails</code>, and be sure that wherever you check out or deploy the code, you'll be running the same versions of the gems. There's even a gems:build task to deal with gems that have native code (but more on that later).</p>
<p>Subsequent versions of Rails have improved on the original rake tasks &ndash; dependencies are now handled much better, for example &ndash; but there are still a few problems. The main one is the handling of gems that are required by rake tasks in your project, rather than just from your application code.</p>
<p>When you call a rake task in your Rails project, this is more-or-less what happens (I may have got some of the details slightly wrong):</p>
<ol>
<li>The top-level <code>Rakefile</code> is loaded.</li>
<li>This in turn requires <code>config/boot.rb</code>, but <em>not</em> <code>config/environment.rb</code>.</li>
<li>It then requires some standard rake stuff, and finally <code>tasks/rails</code> (which is part of Rails &ndash; specifically railties). This finds and requires all the <code>.rake</code> files in your plugins and your project's <code>lib/rake</code> directory.</li>
</ol>
<p>The problems start when you have a task depends on the rails <code>environment</code> task, and also requires a gem which is listed in <code>environment.rb</code>. Because the gem-loading magic only happens when the environment is loaded, the rake task will be blissfully unaware of your frozen gems, and will load them from the system instead.</p>
<p>If the system gem is newer than the frozen one, you get errors like this:</p>
<pre>
can't activate foo (= 1.2.3, runtime) for [], already activated foo-1.2.4 for []
</pre>
<p>If you work on two projects that use different versions of a gem like this, you end up having to uninstall and reinstall them as you switch from one to the other, which gets tedious fairly quickly.</p>
<h4>Specify gems, but don't freeze</h4>
<p>You can get round the wrong-version problem to some extent by specifying version numbers in <code>environment.yml</code> as '>=x.z.y' (or by not specifying them at all). If you're doing that, though, there's not really much benefit in unpacking the gems, and you may as well just use <code>rake gems:install</code> to make sure they're on the system. Of course the downside of this approach is that you can't be sure that everyone's running the exact same versions of the gems. Worse still, you can't be sure that what's on your production box matches your development and test environments.</p>
<h4>GemInstaller</h4>
<p><a href="http://geminstaller.rubyforge.org/">GemInstaller</a> solves most of the problems with the built-in Rails gem management by running as a <a href="http://ryandaigle.com/articles/2007/11/18/what-s-new-in-edge-rails-pre-environment-load-hook">preinitializer</a>, meaning it gets loaded before the other <code>boot.rb</code> gubbins.</p>
<p>GemInstaller uses the gems installed on the system rather than freezing them into the project, but because it gets to run first it ensures that the correct versions are used, even if there are newer versions installed. By default it checks your project's gem list and installs anything that's missing every time it runs (which is whenever you start a server, run the console, execute a rake task etc). You create a YAML file listing the gems you need (dependencies are handled automatically), and other options such as an HTTP proxy if necessary.</p>
<p>Of course on Unix-like systems, which is most of them (although I hear there are still people developing Rails projects on Windows), gems are generally installed as root. GemInstaller can get round this in two ways &ndash; either by setting the <code>--sudo</code> option and setting a rule in <code>/etc/sudoers</code> to allow the appropriate user(s) to run the gem commands as root without having to provide a password, or by using the built-in gem behaviour that falls back to installing in <code>~/.gem</code>.</p>
<p>Personally I like to keep all my gems in one place, accessible to any user, so I went for the sudo approach. The only problem with this is that it uses sudo for all gem commands, rather than just install or update, which means it runs a <code>sudo gem list</code> every time your app starts up. Depending on the way you have Apache and Passenger set up this may mean granting sudo access to what should be a low-privileged user.</p>
<p>I ended up disabling the automatic updating of gems, and just warning when they're missing instead. In fact later versions of GemInstaller don't try to handle the update automatically anyway.</p>
<p>I created a separate script to do the update, which can be run manually, on a post-merge git hook, or as part of the Capistrano deployment task.</p>
<p>Because GemInstaller needs to go out to the network to fetch any new or updated gems, things get a bit more painful (as always) if you are unfortunate enough to be stuck behind a corporate HTTP proxy. Actually it's easy enough to configure if you're <em>always</em> behind a proxy, but it gets slightly trickier if your web access is sometimes proxied and sometimes direct. Nothing that can't be solved of course.</p>
<p>Unfortunately you can still end up with version conflicts if a gem is required by one you have specified, then you explicitly require an older version, but these can usually be resolved by shuffling the order of the gems in <code>geminstaller.yml</code>.</p>
<h4>Bundler</h4>
<p><a href="http://github.com/wycats/bundler">Bundler</a> is the newest kid on the gem management block, and looks to have solved pretty much all the problems faced by the other approaches. It's based on the gem management approach from Merb, and can be used in any Ruby project (not just Rails).</p>
<p>Bundler works by unpacking gems into the project (I recommend using a directory other than the default <code>vendor/gems</code> to avoid confusing Rails &ndash; this can be configured by setting <code>bundle_path</code> and <code>bin_path</code> in the Gemfile), but the intention is that you only commit the <code>.gem</code> files in the cache directory to source control. Gems are then installed locally within the project, including any platform-specific native code as well as the commands in <code>bin</code>.</p>
<p>Because Bundler resolves all dependencies up-front, you only need to specify the gems you're using explicitly, and let it handle the rest, which hopefully means an end to version conflicts at last.</p>
<p>Here's an example Gemfile:</p>
<div class="igBar"><span id="lruby-17"><a href="#" onclick="javascript:showCodeTxt('ruby-17'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-17">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">source 'http://gemcutter.<span style="color:#9900CC;">org</span>'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">source 'http://gems.<span style="color:#9900CC;">github</span>.<span style="color:#9900CC;">com</span>'</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">bundle_path 'vendor/bundled_gems'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">bin_path 'vendor/bundled_gems/bin'</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">gem 'rails', '<span style="color:#006666;color:#800000;">2</span>.<span style="color:#006666;color:#800000;">3</span>.<span style="color:#006666;color:#800000;">4</span>'</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">gem 'bundler', '<span style="color:#006666;color:#800000;">0</span>.<span style="color:#006666;color:#800000;">6</span>.<span style="color:#006666;color:#800000;">0</span>'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">gem 'capistrano', '<span style="color:#006666;color:#800000;">2</span>.<span style="color:#006666;color:#800000;">5</span>.<span style="color:#006666;color:#800000;">8</span>'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">gem 'capistrano-ext', '<span style="color:#006666;color:#800000;">1</span>.<span style="color:#006666;color:#800000;">2</span>.<span style="color:#006666;color:#800000;">1</span>'</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">gem 'cucumber', '<span style="color:#006666;color:#800000;">0</span>.<span style="color:#006666;color:#800000;">4</span>.<span style="color:#006666;color:#800000;">3</span>', :except =&gt; :production</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#008000; font-style:italic;"># [more gems here]</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">disable_system_gems </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Note the two additional sources (rubyforge.org is configured by default), the path overrides, and the last line, which removes the system gems from the paths, avoiding any potential confusion.</p>
<p>I've put this in <code>config/preinitializer.rb</code> to update from the cached gems on startup (this doesn't hit the network):</p>
<div class="igBar"><span id="lruby-18"><a href="#" onclick="javascript:showCodeTxt('ruby-18'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-18">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">$stderr.<span style="color:#CC0066; font-weight:bold;">puts</span> 'Updating bundled gems...'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">system</span> 'gem bundle --cached'</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">"#{RAILS_ROOT}/vendor/bundled_gems/environment"</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>To avoid any startup delays after an upgrade, I also call <code>system 'gem bundle --cached'</code> from the <code>after_update_code</code> hook in the capfile.</p>
<p>Finally, to make sure only the .gem files are checked in, add these lines to <code>.gitignore</code> (you'll still need to explicitly <code>git add</code> the <code>bundled_gems/cache</code> directory):</p>
<pre>
vendor/bundled_gems
!vendor/bundled_gems/cache
</pre>
<p>[Update 3 November] Yehuda Katz just <a href="http://yehudakatz.com/2009/11/03/using-the-new-gem-bundler-today/">posted an article all about Bundler</a>, including features coming in the imminent 0.7 release.</p>
<p>Technorati Tags: <a href="http://technorati.com/tag/ruby" rel="tag">ruby</a>, <a href="http://technorati.com/tag/rails" rel="tag">rails</a>, <a href="http://technorati.com/tag/gems" rel="tag">gems</a>, <a href="http://technorati.com/tag/rubygems" rel="tag">rubygems</a>, <a href="http://technorati.com/tag/geminstaller" rel="tag">geminstaller</a>, <a href="http://technorati.com/tag/bundler" rel="tag">bundler</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrybuckley.org/2009/11/02/managing-gems-in-a-rails-project/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Comments aren&#8217;t always evil</title>
		<link>http://www.kerrybuckley.org/2009/08/14/comments-arent-always-evil/</link>
		<comments>http://www.kerrybuckley.org/2009/08/14/comments-arent-always-evil/#comments</comments>
		<pubDate>Fri, 14 Aug 2009 21:21:36 +0000</pubDate>
		<dc:creator>Kerry</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[comments evil ruby httparty magic]]></category>

		<guid isPermaLink="false">http://www.kerrybuckley.org/?p=330</guid>
		<description><![CDATA[I tend to agree that comments are, in most cases, evil (or at least mildly malevolent), but I did come across one of the exceptions to the rule today. While doing a bit of drive-by refactoring while fixing a bug, I reflexively changed this line: PLAIN TEXT RUBY: unless instance_response.nil? to this: PLAIN TEXT RUBY: [...]]]></description>
			<content:encoded><![CDATA[<p>I tend to agree that <a href="http://deepfriedbytes.com/podcast/episode-35-why-comments-are-evil-and-pair-programming-with-corey-haines/">comments are, in most cases, evil</a> (or at least mildly malevolent), but I did come across one of the exceptions to the rule today.</p>
<p>While doing a bit of drive-by refactoring while fixing a bug, I reflexively changed this line:</p>
<div class="igBar"><span id="lruby-23"><a href="#" onclick="javascript:showCodeTxt('ruby-23'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-23">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">unless</span> instance_response.<span style="color:#0000FF; font-weight:bold;">nil</span>? </div>
</li>
</ol>
</div>
</div>
</div>
<p>
to this:</p>
<div class="igBar"><span id="lruby-24"><a href="#" onclick="javascript:showCodeTxt('ruby-24'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-24">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">if</span> instance_response </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Then reading the comment above the line, expecting to delete it, it all came flooding back:</p>
<div class="igBar"><span id="lruby-25"><a href="#" onclick="javascript:showCodeTxt('ruby-25'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-25">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#008000; font-style:italic;"># Use instance_response.nil? to check if the HTTParty</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#008000; font-style:italic;"># response's inner hash is empty.</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#008000; font-style:italic;"># If you use 'if instance_response', it is always true. </span></div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Now you could maybe argue that this unexpected behaviour is because httparty uses just a little too much of that old <a href="http://railstips.org/2009/8/7/patterns-are-not-scary-method-missing-proxy">method missing proxy magic</a> (which of course <a href="http://gilesbowkett.blogspot.com/2009/07/do-you-believe-in-magic.html">isn't really magic at all</a>), but that's not the point of this post.</p>
<p>In the end I pulled it out into a private method to make it clearer what was going on, but decided to leave the comment in.</p>
<div class="igBar"><span id="lruby-26"><a href="#" onclick="javascript:showCodeTxt('ruby-26'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-26">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">instance_returned</span>? instance_response</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#008000; font-style:italic;"># Use instance_response.nil? to check if the HTTParty</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#008000; font-style:italic;"># response's inner hash is empty.</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#008000; font-style:italic;"># If you use 'if instance_response', it is always true.</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; !instance_response.<span style="color:#0000FF; font-weight:bold;">nil</span>?</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrybuckley.org/2009/08/14/comments-arent-always-evil/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Naresh Jain&#8217;s refactoring teaser</title>
		<link>http://www.kerrybuckley.org/2009/07/17/naresh-jains-refactoring-teaser/</link>
		<comments>http://www.kerrybuckley.org/2009/07/17/naresh-jains-refactoring-teaser/#comments</comments>
		<pubDate>Fri, 17 Jul 2009 08:03:51 +0000</pubDate>
		<dc:creator>Kerry</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[clean code]]></category>
		<category><![CDATA[refactoring]]></category>

		<guid isPermaLink="false">http://www.kerrybuckley.org/?p=298</guid>
		<description><![CDATA[Naresh Jain recently posted a refactoring teaser. The original code was in Java, but I thought I'd have a go at refactoring it in Ruby instead. I deliberately didn't look at Naresh's solution beforehand, so mine goes in a rather different direction. My code's here (with the specs in the same file for simplicity), and [...]]]></description>
			<content:encoded><![CDATA[<p>Naresh Jain recently posted a <a href="http://blogs.agilefaqs.com/2009/07/08/refactoring-teaser-part-1/">refactoring teaser</a>. The original code was in Java, but I thought I'd have a go at refactoring it in Ruby instead. I deliberately didn't look at <a href="http://blogs.agilefaqs.com/2009/07/14/refactoring-teaser-1-take-1/">Naresh's solution</a> beforehand, so mine goes in a rather different direction.</p>
<p>My code's <a href="http://github.com/kerryb/refactoring_teaser_1">here</a> (with the specs in the same file for simplicity), and you can step through the <a href="http://github.com/kerryb/refactoring_teaser_1/commits/master/">history</a> to see the state at each step of the refactoring. The links in the text below take you to the relevant version of the file, and the &Delta;s next to them link to the diffs.</p>
<p><a href="http://github.com/kerryb/refactoring_teaser_1/blob/8a5667da8bf573807cf58eb05b7d35f0437c2956/1.rb">Firstly</a>, I converted the code to Ruby, and made sure the tests (which I converted to RSpec) still passed. It's a fairly straight conversion, although I made a couple of changes while I was at it &ndash; mainly turning it into a module which I mixed into <code>String</code>. I changed the name of the method to <code>phrases</code>, to avoid conflicting with the built-in <code>String#split</code>. The regular expression to split on is much simpler too, because Ruby didn't understand the original, and I had no idea what it was supposed to do anyway.</p>
<p>Here's my initial Ruby version:</p>
<div class="igBar"><span id="lruby-39"><a href="#" onclick="javascript:showCodeTxt('ruby-39'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-39">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#008000; font-style:italic;">#!/usr/bin/env ruby</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#008000; font-style:italic;">#</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#008000; font-style:italic;">#See http://blogs.agilefaqs.com/2009/07/08/refactoring-teaser-part-1/</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">require</span> 'spec'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">module</span> StringExtensions</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; REGEX_TO_SPLIT_ALONG_WHITESPACES = /\s+/</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> phrases<span style="color:#006600; font-weight:bold;">&#40;</span>number<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; list_of_keywords = <span style="color:#996600;">""</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; count = <span style="color:#006666;color:#800000;">0</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; strings = <span style="color:#CC0066; font-weight:bold;">split</span><span style="color:#006600; font-weight:bold;">&#40;</span>REGEX_TO_SPLIT_ALONG_WHITESPACES<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings = single_double_triple_words<span style="color:#006600; font-weight:bold;">&#40;</span>strings<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; size = all_strings.<span style="color:#9900CC;">size</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |phrase|</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">break</span> <span style="color:#9966CC; font-weight:bold;">if</span> count == number</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; list_of_keywords += <span style="color:#996600;">"'"</span> + phrase + <span style="color:#996600;">"'"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; count += <span style="color:#006666;color:#800000;">1</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#006600; font-weight:bold;">&#40;</span>count &lt;size &amp;&amp; count &lt;number<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; &nbsp; list_of_keywords += <span style="color:#996600;">", "</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> list_of_keywords</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; private</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> single_double_triple_words<span style="color:#006600; font-weight:bold;">&#40;</span>strings<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; num_words = strings.<span style="color:#9900CC;">size</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> all_strings <span style="color:#9966CC; font-weight:bold;">unless</span> has_enough_words<span style="color:#006600; font-weight:bold;">&#40;</span>num_words<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Extracting single words. Total size of words == num_words</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Extracting single-word phrases.</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">0</span>...<span style="color:#9900CC;">num_words</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |i|</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; all_strings &lt;&lt;strings<span style="color:#006600; font-weight:bold;">&#91;</span>i<span style="color:#006600; font-weight:bold;">&#93;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Extracting double-word phrases</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">0</span>...<span style="color:#9900CC;">num_words</span> - <span style="color:#006666;color:#800000;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |i|</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; all_strings &lt;&lt;<span style="color:#996600;">"#{strings[i]} #{strings[i + 1]}"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Extracting triple-word phrases</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">0</span>...<span style="color:#9900CC;">num_words</span> - <span style="color:#006666;color:#800000;">2</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |i|</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; all_strings &lt;&lt;<span style="color:#996600;">"#{strings[i]} #{strings[i + 1]} #{strings[i + 2]}"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> all_strings</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; </div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> has_enough_words<span style="color:#006600; font-weight:bold;">&#40;</span>num_words<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; num_words&gt;= <span style="color:#006666;color:#800000;">3</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">String</span>.<span style="color:#9900CC;">send</span><span style="color:#006600; font-weight:bold;">&#40;</span>:<span style="color:#9966CC; font-weight:bold;">include</span>, StringExtensions<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">describe StringExtensions <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; it 'finds all phrases' <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; 'Hello World Ruby'.<span style="color:#9900CC;">phrases</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">6</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">should</span> == <span style="color:#996600;">"'Hello', 'World', 'Ruby', 'Hello World', 'World Ruby', 'Hello World Ruby'"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; it 'returns all phrases <span style="color:#9966CC; font-weight:bold;">when</span> asked <span style="color:#9966CC; font-weight:bold;">for</span> more than exist' <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; 'Hello World Ruby'.<span style="color:#9900CC;">phrases</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">10</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">should</span> == <span style="color:#996600;">"'Hello', 'World', 'Ruby', 'Hello World', 'World Ruby', 'Hello World Ruby'"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; it 'returns the first n phrases <span style="color:#9966CC; font-weight:bold;">when</span> asked <span style="color:#9966CC; font-weight:bold;">for</span> fewer than exist' <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; 'Hello World Ruby'.<span style="color:#9900CC;">phrases</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">4</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">should</span> == <span style="color:#996600;">"'Hello', 'World', 'Ruby', 'Hello World'"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; it 'returns the first word <span style="color:#9966CC; font-weight:bold;">when</span> asked <span style="color:#9966CC; font-weight:bold;">for</span> one phrase' <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; 'Hello World Ruby'.<span style="color:#9900CC;">phrases</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">should</span> == <span style="color:#996600;">"'Hello'"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>I didn't change the specs at all during the refactoring (because I didn't change the API or add any new public methods or classes), and made sure they all passed at each step.</p>
<p>The <a href="http://github.com/kerryb/refactoring_teaser_1/tree/45d5728b779414a784e7e1159af467b58ce2b80e/1.rb">first thing</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/45d5728b779414a784e7e1159af467b58ce2b80e">&Delta;</a> I changed was to simplify that big iterator in <code>phrases</code> that loops through the list of phrases, formatting the output string. Basically all this does is to put each phrase in quotes, then stitch them all together separated by a comma and a space. The first of those tasks is a simple map, and the second is a join. The whole method collapses down to this (ruby methods automatically return the result of their last statement):</p>
<div class="igBar"><span id="lruby-40"><a href="#" onclick="javascript:showCodeTxt('ruby-40'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-40">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> phrases<span style="color:#006600; font-weight:bold;">&#40;</span>number<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; strings = <span style="color:#CC0066; font-weight:bold;">split</span><span style="color:#006600; font-weight:bold;">&#40;</span>REGEX_TO_SPLIT_ALONG_WHITESPACES<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings = single_double_triple_words<span style="color:#006600; font-weight:bold;">&#40;</span>strings<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;color:#800000;">0</span>, number<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">map</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|s| <span style="color:#996600;">"'#{s}'"</span><span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span>', '<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p><a href="http://github.com/kerryb/refactoring_teaser_1/tree/4c69e84b58f1e293ff90879d2bcf281680fab6de/1.rb">Next</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/4c69e84b58f1e293ff90879d2bcf281680fab6de">&Delta;</a> I remembered that by default <code>String#split</code> splits at whitespace anyway, so I did away with the regular expression. <a href="http://github.com/kerryb/refactoring_teaser_1/tree/e6cba0406211a294811c4429130022695829fa5a/1.rb">Then</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/e6cba0406211a294811c4429130022695829fa5a">&Delta;</a> I renamed the <code>strings</code> variable to <code>words</code> to make its purpose a little clearer, leaving the <code>phrases</code> method looking like this:</p>
<div class="igBar"><span id="lruby-41"><a href="#" onclick="javascript:showCodeTxt('ruby-41'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-41">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> phrases<span style="color:#006600; font-weight:bold;">&#40;</span>number<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; words = <span style="color:#CC0066; font-weight:bold;">split</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings = single_double_triple_words<span style="color:#006600; font-weight:bold;">&#40;</span>words<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;color:#800000;">0</span>, number<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">map</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|s| <span style="color:#996600;">"'#{s}'"</span><span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span>', '<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>The section of <code>single_double_triple_words</code> that extracted the single words seemed redundant, as we already had that list &ndash; the original words. I <a href="http://github.com/kerryb/refactoring_teaser_1/tree/04b2a467e08862d4ffc58688492c41a3f19673d1/1.rb">removed it</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/04b2a467e08862d4ffc58688492c41a3f19673d1">&Delta;</a>, and initialised <code>all_strings</code> to the word list instead (not forgetting to rename <code>single_double_triple_words</code> to match its new behaviour):</p>
<div class="igBar"><span id="lruby-42"><a href="#" onclick="javascript:showCodeTxt('ruby-42'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-42">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">module</span> StringExtensions</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> phrases<span style="color:#006600; font-weight:bold;">&#40;</span>number<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; words = <span style="color:#CC0066; font-weight:bold;">split</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings = words</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings += double_triple_words<span style="color:#006600; font-weight:bold;">&#40;</span>words<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;color:#800000;">0</span>, number<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">map</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|s| <span style="color:#996600;">"'#{s}'"</span><span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span>', '<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; private</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> double_triple_words<span style="color:#006600; font-weight:bold;">&#40;</span>strings<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; num_words = strings.<span style="color:#9900CC;">size</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> all_strings <span style="color:#9966CC; font-weight:bold;">unless</span> has_enough_words<span style="color:#006600; font-weight:bold;">&#40;</span>num_words<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Extracting double-word phrases</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">0</span>...<span style="color:#9900CC;">num_words</span> - <span style="color:#006666;color:#800000;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |i|</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; all_strings &lt;&lt;<span style="color:#996600;">"#{strings[i]} #{strings[i + 1]}"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Extracting triple-word phrases</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">0</span>...<span style="color:#9900CC;">num_words</span> - <span style="color:#006666;color:#800000;">2</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |i|</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; all_strings &lt;&lt;<span style="color:#996600;">"#{strings[i]} #{strings[i + 1]} #{strings[i + 2]}"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> all_strings</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; </div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> has_enough_words<span style="color:#006600; font-weight:bold;">&#40;</span>num_words<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; num_words&gt;= <span style="color:#006666;color:#800000;">3</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>That <code>has_enough_words</code> method seemed a bit odd &ndash; particularly the way it was only called once, rather than after extracting each set of phrases. I decided it was probably a premature and incomplete attempt at optimisation, and <a href="http://github.com/kerryb/refactoring_teaser_1/tree/727fffec15e0df85544e7453e5ffb86b138c2bac/1.rb">removed it</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/727fffec15e0df85544e7453e5ffb86b138c2bac">&Delta;</a> for now.</p>
<p>My next target was the duplication in the blocks that calculate double- and triple-word phrases. <a href="http://github.com/kerryb/refactoring_teaser_1/tree/d5ab509fa6bf349f2d47007797d879ef70f996fc/1.rb">First</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/d5ab509fa6bf349f2d47007797d879ef70f996fc">&Delta;</a> I extracted them into separate methods:</p>
<div class="igBar"><span id="lruby-43"><a href="#" onclick="javascript:showCodeTxt('ruby-43'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-43">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">module</span> StringExtensions</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> phrases<span style="color:#006600; font-weight:bold;">&#40;</span>number<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; words = <span style="color:#CC0066; font-weight:bold;">split</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings = words</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings += double_words<span style="color:#006600; font-weight:bold;">&#40;</span>words<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings += triple_words<span style="color:#006600; font-weight:bold;">&#40;</span>words<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;color:#800000;">0</span>, number<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">map</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|s| <span style="color:#996600;">"'#{s}'"</span><span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span>', '<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; private</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> double_words<span style="color:#006600; font-weight:bold;">&#40;</span>strings<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; num_words = strings.<span style="color:#9900CC;">size</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Extracting double-word phrases</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">0</span>...<span style="color:#9900CC;">num_words</span> - <span style="color:#006666;color:#800000;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |i|</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; all_strings &lt;&lt;<span style="color:#996600;">"#{strings[i]} #{strings[i + 1]}"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> all_strings</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> triple_words<span style="color:#006600; font-weight:bold;">&#40;</span>strings<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; num_words = strings.<span style="color:#9900CC;">size</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">0</span>...<span style="color:#9900CC;">num_words</span> - <span style="color:#006666;color:#800000;">2</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |i|</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; all_strings &lt;&lt;<span style="color:#996600;">"#{strings[i]} #{strings[i + 1]} #{strings[i + 2]}"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> all_strings</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>I decided that the <code>num_words</code> variable in the two new methods wasn't really necessary (it was only used once, and I think <code>strings.size</code> expresses intent perfectly clearly), so I <a href="http://github.com/kerryb/refactoring_teaser_1/tree/33e4d64d7920816ff8eb72b98b393ade713f5669/1.rb">inlined it</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/33e4d64d7920816ff8eb72b98b393ade713f5669">&Delta;</a> (and the same in <code>triple_words</code>):</p>
<div class="igBar"><span id="lruby-44"><a href="#" onclick="javascript:showCodeTxt('ruby-44'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-44">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> double_words<span style="color:#006600; font-weight:bold;">&#40;</span>strings<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#008000; font-style:italic;"># Extracting double-word phrases</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">0</span>...<span style="color:#9900CC;">strings</span>.<span style="color:#9900CC;">size</span> - <span style="color:#006666;color:#800000;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |i|</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings &lt;&lt;<span style="color:#996600;">"#{strings[i]} #{strings[i + 1]}"</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> all_strings</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Most of the code in <code>double_words</code> and <code>triple_words</code> was obviously very similar, so I <a href="http://github.com/kerryb/refactoring_teaser_1/tree/813d40d060778bfb8e93c302870d18d6d8c7d1ef/1.rb">created</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/813d40d060778bfb8e93c302870d18d6d8c7d1ef">&Delta;</a> a general <code>extract_phrases</code> method, and called it from both. The new method uses the <em>start position and length</em> version of <code>Array#[]</code> to extract the appropriate number of words, then <code>Array#join</code> to string them together separated by spaces:</p>
<div class="igBar"><span id="lruby-45"><a href="#" onclick="javascript:showCodeTxt('ruby-45'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-45">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> double_words<span style="color:#006600; font-weight:bold;">&#40;</span>strings<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; extract_phrases<span style="color:#006600; font-weight:bold;">&#40;</span>strings, <span style="color:#006666;color:#800000;">2</span><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> triple_words<span style="color:#006600; font-weight:bold;">&#40;</span>strings<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; extract_phrases<span style="color:#006600; font-weight:bold;">&#40;</span>strings, <span style="color:#006666;color:#800000;">3</span><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> extract_phrases<span style="color:#006600; font-weight:bold;">&#40;</span>strings, number_of_words<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; result = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">0</span>...<span style="color:#9900CC;">strings</span>.<span style="color:#9900CC;">size</span> - number_of_words + <span style="color:#006666;color:#800000;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |i|</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; phrase = strings<span style="color:#006600; font-weight:bold;">&#91;</span>i, number_of_words<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span>' '<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; result &lt;&lt;phrase</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; result</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>At this point <code>double_words</code> and <code>triple_words</code> have become just dumb wrappers around <code>extract_phrases</code>, so I <a href="http://github.com/kerryb/refactoring_teaser_1/tree/e10845fa52b6131122bba0944fee85016a6a8413/1.rb">removed them</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/e10845fa52b6131122bba0944fee85016a6a8413">&Delta;</a> and just called <code>extract_phrases</code> directly:</p>
<div class="igBar"><span id="lruby-46"><a href="#" onclick="javascript:showCodeTxt('ruby-46'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-46">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> phrases<span style="color:#006600; font-weight:bold;">&#40;</span>number<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; words = <span style="color:#CC0066; font-weight:bold;">split</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings = words</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings += extract_phrases<span style="color:#006600; font-weight:bold;">&#40;</span>words, <span style="color:#006666;color:#800000;">2</span><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings += extract_phrases<span style="color:#006600; font-weight:bold;">&#40;</span>words, <span style="color:#006666;color:#800000;">3</span><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;color:#800000;">0</span>, number<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">map</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|s| <span style="color:#996600;">"'#{s}'"</span><span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span>', '<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Rather than hardcoding the calls for two and three words, I <a href="http://github.com/kerryb/refactoring_teaser_1/tree/8be9301f293231611e4bc6a8b4455e74189aab2c/1.rb">changed it</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/8be9301f293231611e4bc6a8b4455e74189aab2c">&Delta;</a> to use a loop:</p>
<div class="igBar"><span id="lruby-47"><a href="#" onclick="javascript:showCodeTxt('ruby-47'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-47">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> phrases<span style="color:#006600; font-weight:bold;">&#40;</span>number<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; words = <span style="color:#CC0066; font-weight:bold;">split</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings = words</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">2</span>..<span style="color:#9900CC;">words</span>.<span style="color:#9900CC;">size</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |number_of_words|</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings += extract_phrases<span style="color:#006600; font-weight:bold;">&#40;</span>words, number_of_words<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;color:#800000;">0</span>, number<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">map</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|s| <span style="color:#996600;">"'#{s}'"</span><span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span>', '<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>I decided this was the point to <a href="http://github.com/kerryb/refactoring_teaser_1/tree/b224160440729a5fc64da5c4c6d592d6ad98fb96/1.rb">put the optimisation back</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/b224160440729a5fc64da5c4c6d592d6ad98fb96">&Delta;</a> and stop looking for phrases once we had enough:</p>
<div class="igBar"><span id="lruby-48"><a href="#" onclick="javascript:showCodeTxt('ruby-48'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-48">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> phrases<span style="color:#006600; font-weight:bold;">&#40;</span>number<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; words = <span style="color:#CC0066; font-weight:bold;">split</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings = words</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">2</span>..<span style="color:#9900CC;">words</span>.<span style="color:#9900CC;">size</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |number_of_words|</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">break</span> <span style="color:#9966CC; font-weight:bold;">if</span> all_strings.<span style="color:#9900CC;">length</span>&gt;= number</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings += extract_phrases<span style="color:#006600; font-weight:bold;">&#40;</span>words, number_of_words<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; all_strings<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;color:#800000;">0</span>, number<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">map</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|s| <span style="color:#996600;">"'#{s}'"</span><span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span>', '<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>I decided that <code>number_of_words</code> wasn't particularly clear, so <a href="http://github.com/kerryb/refactoring_teaser_1/tree/1911ab5f3f41c587752284ce1386e7dac0d8aacd/1.rb">changed it</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/1911ab5f3f41c587752284ce1386e7dac0d8aacd">&Delta;</a> to <code>phrase_length</code>, <a href="http://github.com/kerryb/refactoring_teaser_1/tree/364c7fd210ea29a9de8847738463547575428430/1.rb">then</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/364c7fd210ea29a9de8847738463547575428430">&Delta;</a> made the iterator in <code>extract_phrases</code> more ruby-like by using map:</p>
<div class="igBar"><span id="lruby-49"><a href="#" onclick="javascript:showCodeTxt('ruby-49'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-49">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">def</span> extract_phrases<span style="color:#006600; font-weight:bold;">&#40;</span>strings, phrase_length<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">0</span>...<span style="color:#9900CC;">strings</span>.<span style="color:#9900CC;">size</span> - phrase_length + <span style="color:#006666;color:#800000;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">map</span> <span style="color:#9966CC; font-weight:bold;">do</span> |i|</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; strings<span style="color:#006600; font-weight:bold;">&#91;</span>i, phrase_length<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span>' '<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>I then noticed that I hadn't been consistent in changing <code>strings</code> to <code>words</code>, so <a href="http://github.com/kerryb/refactoring_teaser_1/tree/9d3c0db0ef7e0074fddbfa76aa02352b47b3ba6b/1.rb">fixed that</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/9d3c0db0ef7e0074fddbfa76aa02352b47b3ba6b">&Delta;</a>.</p>
<p><a href="http://github.com/kerryb/refactoring_teaser_1/tree/d6d1d9d88f94809e1d0341cb6fb2667fc01bdefd/1.rb">Lastly</a> <a href="http://github.com/kerryb/refactoring_teaser_1/commit/d6d1d9d88f94809e1d0341cb6fb2667fc01bdefd">&Delta;</a>, I decided that even though it was only one line, the code that formats the output deserved pulling out into a method.</p>
<p>Here's my final version of the code:</p>
<div class="igBar"><span id="lruby-50"><a href="#" onclick="javascript:showCodeTxt('ruby-50'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-50">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">module</span> StringExtensions</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> phrases<span style="color:#006600; font-weight:bold;">&#40;</span>number<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; words = <span style="color:#CC0066; font-weight:bold;">split</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; all_strings = words</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">2</span>..<span style="color:#9900CC;">words</span>.<span style="color:#9900CC;">size</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |phrase_length|</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">break</span> <span style="color:#9966CC; font-weight:bold;">if</span> all_strings.<span style="color:#9900CC;">length</span>&gt;= number</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; all_strings += extract_phrases<span style="color:#006600; font-weight:bold;">&#40;</span>words, phrase_length<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; format_output<span style="color:#006600; font-weight:bold;">&#40;</span>all_strings<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;color:#800000;">0</span>, number<span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; private</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> extract_phrases<span style="color:#006600; font-weight:bold;">&#40;</span>words, phrase_length<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;color:#800000;">0</span>...<span style="color:#9900CC;">words</span>.<span style="color:#9900CC;">size</span> - phrase_length + <span style="color:#006666;color:#800000;">1</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">map</span> <span style="color:#9966CC; font-weight:bold;">do</span> |i|</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; words<span style="color:#006600; font-weight:bold;">&#91;</span>i, phrase_length<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span>' '<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> format_output<span style="color:#006600; font-weight:bold;">&#40;</span>phrases<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; phrases.<span style="color:#9900CC;">map</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|s| <span style="color:#996600;">"'#{s}'"</span><span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span>', '<span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrybuckley.org/2009/07/17/naresh-jains-refactoring-teaser/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A couple of rspec mocking gotchas</title>
		<link>http://www.kerrybuckley.org/2009/05/28/a-couple-of-rspec-mocking-gotchas/</link>
		<comments>http://www.kerrybuckley.org/2009/05/28/a-couple-of-rspec-mocking-gotchas/#comments</comments>
		<pubDate>Thu, 28 May 2009 12:05:55 +0000</pubDate>
		<dc:creator>Kerry</dc:creator>
				<category><![CDATA[rspec]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.kerrybuckley.org/?p=289</guid>
		<description><![CDATA[Just a couple of things that have caused a bit of head-scratching lately when writing RSpec specs using the built-in mocking framework. Catching StandardError Watch out if the code you're testing catches StandardError (of course you're not catching Exception, right?). Try this: PLAIN TEXT RUBY: require 'rubygems' require 'spec' &#160; class Foo &#160; def self.foo [...]]]></description>
			<content:encoded><![CDATA[<p>Just a couple of things that have caused a bit of head-scratching lately when writing RSpec specs using the built-in mocking framework.</p>
<h4>Catching StandardError</h4>
<p>Watch out if the code you're testing catches <code>StandardError</code> (of course you're <a href="http://technomancy.us/114">not catching <code>Exception</code></a>, right?). Try this:</p>
<div class="igBar"><span id="lruby-56"><a href="#" onclick="javascript:showCodeTxt('ruby-56'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-56">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">require</span> 'rubygems'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">require</span> 'spec'</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> Foo</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">foo</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; Bar.<span style="color:#9900CC;">bar</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">rescue</span> StandardError</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># do something here and don't re-raise</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> Bar</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">bar</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">describe 'Calling a method that catches StandardError' <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; it 'calls Bar.<span style="color:#9900CC;">bar</span>' <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; Bar.<span style="color:#9900CC;">should_receive</span> :bar</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; Foo.<span style="color:#9900CC;">foo</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Nothing particularly exciting there. Let's run it and check that it passes:</p>
<pre>
$ spec foo.rb
.

Finished in 0.001862 seconds

1 example, 0 failures
</pre>
<p>However, what if we change the example to test the opposite behaviour?</p>
<div class="igBar"><span id="lruby-57"><a href="#" onclick="javascript:showCodeTxt('ruby-57'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-57">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">describe 'Calling a method that catches StandardError' <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; it 'does <span style="color:#9966CC; font-weight:bold;">NOT</span> call Bar.<span style="color:#9900CC;">bar</span>' <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; Bar.<span style="color:#9900CC;">should_not_receive</span> :bar</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; Foo.<span style="color:#9900CC;">foo</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<pre>
$ spec foo.rb
.

Finished in 0.001865 seconds

1 example, 0 failures
</pre>
<p>Wait, surely they can't both pass? Let's take out the rescue and see what's going on:</p>
<div class="igBar"><span id="lruby-58"><a href="#" onclick="javascript:showCodeTxt('ruby-58'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-58">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> Foo</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">foo</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; Bar.<span style="color:#9900CC;">bar</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<pre>
$ spec foo.rb
F

1)
Spec::Mocks::MockExpectationError in 'Calling a method that catches StandardError does NOT call Bar.bar'
<Bar (class)> expected :bar with (no args) 0 times, but received it once
./foo.rb:6:in `foo'
./foo.rb:18:

Finished in 0.002276 seconds

1 example, 1 failure
</pre>
<p>That's more like it.</p>
<p>Of course, what's really happening here is that <code> Spec::Mocks::MockExpectationError</code> is a subclass of <code>StandardError</code>, so is being caught and silently discarded by our method under test.</p>
<p>If you're <a href="http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd">doing TDD properly</a>, this won't result in a useless test (at least not immediately), but it might cause you to spend a while trying to figure out how to get a failing test before you add the call to <code>Foo.foo</code> (assuming the method with the <code>rescue</code> already existed). Generally you can solve the problem by making the code a bit more selective about which exception class(es) it catches, but I wonder whether RSpec exceptions are special cases which ought to directly extend <code>Exception</code>.</p>
<h4>Checking receive counts on previously-stubbed methods</h4>
<p>It's quite common to stub a method on a collaborator in a <code>before</code> block, then check the details of the call to the method in a specific example. This doesn't work quite as you would expect if for some reason you want to check that the method is only called a specific number of times:</p>
<div class="igBar"><span id="lruby-59"><a href="#" onclick="javascript:showCodeTxt('ruby-59'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-59">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">require</span> 'rubygems'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">require</span> 'spec'</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> Foo</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">foo</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; Bar.<span style="color:#9900CC;">bar</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; Bar.<span style="color:#9900CC;">bar</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">class</span> Bar</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">bar</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">describe 'Checking call counts <span style="color:#9966CC; font-weight:bold;">for</span> a stubbed method' <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; before <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; Bar.<span style="color:#9900CC;">stub</span>! :bar</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; it 'only calls a method once' <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; Bar.<span style="color:#9900CC;">should_receive</span><span style="color:#006600; font-weight:bold;">&#40;</span>:bar<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">once</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; Foo.<span style="color:#9900CC;">foo</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<pre>
$ spec foo.rb
.

Finished in 0.001867 seconds

1 example, 0 failures
</pre>
<p>I think what's happening here is that the mock object would normally receive an unexpected call, causing the <em><Bar (class)> expected :bar with (any args) once, but received it twice</em> error that you'd expect. Unfortunately the second call to the method is handled by the stub, so never triggers the error.</p>
<p>You can fix it, but it's messy:</p>
<div class="igBar"><span id="lruby-60"><a href="#" onclick="javascript:showCodeTxt('ruby-60'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-60">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">it 'only calls a method once' <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; Bar.<span style="color:#9900CC;">send</span><span style="color:#006600; font-weight:bold;">&#40;</span>:__mock_proxy<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">reset</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; Bar.<span style="color:#9900CC;">should_receive</span><span style="color:#006600; font-weight:bold;">&#40;</span>:bar<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">once</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; Foo.<span style="color:#9900CC;">foo</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<pre>
$ spec foo.rb
F

1)
Spec::Mocks::MockExpectationError in 'Checking call counts for a stubbed method only calls a method once'
<Bar (class)> expected :bar with (any args) once, but received it twice
./foo.rb:23:

Finished in 0.002542 seconds

1 example, 1 failure
</pre>
<p>Does anyone know a better way?</p>
<p>The full example code is in <a href="http://gist.github.com/118581">this gist</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrybuckley.org/2009/05/28/a-couple-of-rspec-mocking-gotchas/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Helpful message from rspec</title>
		<link>http://www.kerrybuckley.org/2009/05/04/helpful-message-from-rspec/</link>
		<comments>http://www.kerrybuckley.org/2009/05/04/helpful-message-from-rspec/#comments</comments>
		<pubDate>Mon, 04 May 2009 16:21:11 +0000</pubDate>
		<dc:creator>Kerry</dc:creator>
				<category><![CDATA[rspec]]></category>
		<category><![CDATA[ruby rails rspec]]></category>

		<guid isPermaLink="false">http://www.kerrybuckley.org/?p=281</guid>
		<description><![CDATA[Just came across an interesting error message from rspec. I had a spec that looked like this: PLAIN TEXT RUBY: it "should not mass-assign 'confirmed'" do &#160; Blog.new&#40;:confirmed =&#62; true&#41;.confirmed.should_not be_true end Obviously it failed, as I hadn't written the code yet, but there was more in the error message than I expected: ..........F 1) [...]]]></description>
			<content:encoded><![CDATA[<p>Just came across an interesting error message from rspec. I had a spec that looked like this:</p>
<div class="igBar"><span id="lruby-62"><a href="#" onclick="javascript:showCodeTxt('ruby-62'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-62">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">it <span style="color:#996600;">"should not mass-assign 'confirmed'"</span> <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; Blog.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>:confirmed =&gt; <span style="color:#0000FF; font-weight:bold;">true</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">confirmed</span>.<span style="color:#9900CC;">should_not</span> be_true</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span> </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
<p>Obviously it failed, as I hadn't written the code yet, but there was more in the error message than I expected:</p>
<pre><span style="color:green">..........</span><span style="color:red">F</span>

1)
<span style="color:red">RuntimeError in 'Blog should not mass-assign 'confirmed''
'should_not be  true' not only FAILED,
it is a bit confusing.
It might be more clearly expressed in the positive?</span>
.../spec/models/blog_spec.rb:20:

Finished in 0.06192 seconds

11 examples, 1 failure</pre>
<p>In fact, rewriting this as <code>should be_false</code> wouldn't work, as the expected value is nil. I took the hint though, and rewrote it as <code>should be_nil</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrybuckley.org/2009/05/04/helpful-message-from-rspec/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>API vs RSI</title>
		<link>http://www.kerrybuckley.org/2009/03/15/api-vs-rsi/</link>
		<comments>http://www.kerrybuckley.org/2009/03/15/api-vs-rsi/#comments</comments>
		<pubDate>Sun, 15 Mar 2009 12:16:16 +0000</pubDate>
		<dc:creator>Kerry</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[stephenfry]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://www.kerrybuckley.org/?p=266</guid>
		<description><![CDATA[World's-most-famous-twitterer Stephen Fry has a system for handling follow requests: you tweet using the #followmestephen hashtag, and he wades diligently through them, manually following people. This seems an odd sort of thing to do &#8211; most people choose whom to follow based on whether they know them or like what they say, rather than on [...]]]></description>
			<content:encoded><![CDATA[<p>World's-most-famous-twitterer Stephen Fry has <a href="http://www.stephenfry.com/blog/2009/03/02/followmestephen/">a system</a> for handling follow requests: you tweet using the <a href="http://hashtags.org/tag/followmestephen">#followmestephen</a> hashtag, and he wades diligently through them, manually following people.</p>
<p>This seems an odd sort of thing to do &ndash; most people choose whom to follow based on whether they know them or like what they say, rather than on request &ndash; but I suppose when you have over a quarter of a million followers things work a little differently. It also creates <a href="http://twitter.com/stephenfry/status/1327867339">lots of work </a>, and looks like an ideal candidate for automation.</p>
<p>I thought I'd have a quick play with the Twitter API this morning (no doubt I'm not the only one), and cobbled together the script below, which you can also download as <a href='http://www.kerrybuckley.org/wp-content/uploads/2009/03/follow_me_stephen.rb'>follow_me_stephen.rb</a> (although if you're not Mr Fry I'm not sure why you would want to). Save the file, and run using <code>ruby follow_me_stephen.rb</code>.</p>
<p>I wanted to avoid having too many dependencies, so I didn't use the <a href="http://twitter.rubyforge.org/">twitter gem</a>, or the excellent <a href="http://httparty.rubyforge.org/">httparty</a>, but I was too lazy to figure out all the XPaths to handle the Atom version of the API. This means you need to have the JSON gem installed, which is as simple as <code>sudo gem install json</code> (omit the <em>sudo</em> on Windows).</p>
<p>The script's pretty dumb, in that it grabs the whole set of search results every time, and blindly requests to follow everyone, regardless of whether you're already following them.</p>
<div class="igBar"><span id="lruby-64"><a href="#" onclick="javascript:showCodeTxt('ruby-64'); return false;">PLAIN TEXT</a></span></div>
<div class="syntax_hilite"><span class="langName">RUBY:</span>
<div id="ruby-64">
<div class="ruby">
<ol>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#008000; font-style:italic;">#!/usr/bin/env ruby</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#CC0066; font-weight:bold;">require</span> 'net/http'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">begin</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#CC0066; font-weight:bold;">require</span> 'json'</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">rescue</span> LoadError</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; STDERR.<span style="color:#CC0066; font-weight:bold;">puts</span> &lt;&lt;EOF</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">No JSON parser found. <span style="color:#9900CC;">Please</span> run the following command to install:</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; sudo gem install json</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">EOF</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#CC0066; font-weight:bold;">raise</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">module</span> FollowMeStephen</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> run</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; auth_user, password = get_user_details</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; requestors = fetch_requestors</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; requestors.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> |user|</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; follow user, auth_user, password</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; </div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; private</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; </div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> get_user_details</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">print</span> 'Please enter your Twitter username: '</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; auth_user = <span style="color:#CC0066; font-weight:bold;">gets</span>.<span style="color:#CC0066; font-weight:bold;">chomp</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">print</span> 'Please enter your Twitter password: '</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; password = <span style="color:#CC0066; font-weight:bold;">gets</span>.<span style="color:#CC0066; font-weight:bold;">chomp</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> auth_user, password</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; </div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> fetch_requestors</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; requestors = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">puts</span> 'Searching <span style="color:#9966CC; font-weight:bold;">for</span> hashtag <span style="color:#996600;">"followmestephen"</span>...'</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; query = '?q=%23followmestephen&amp;rpp=<span style="color:#006666;color:#800000;">150</span>'</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">while</span> query <span style="color:#9966CC; font-weight:bold;">do</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; search = JSON.<span style="color:#9900CC;">parse</span><span style="color:#006600; font-weight:bold;">&#40;</span>get<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">"/search.json#{query}"</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#41;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">"Received page #{search['page']}"</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; requestors += search<span style="color:#006600; font-weight:bold;">&#91;</span>'results'<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">map</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|r| r<span style="color:#006600; font-weight:bold;">&#91;</span>'from_user'<span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#125;</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; &nbsp; query = search<span style="color:#006600; font-weight:bold;">&#91;</span>'next_page'<span style="color:#006600; font-weight:bold;">&#93;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; requestors.<span style="color:#9900CC;">uniq</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; </div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> follow user, auth_user, password</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">print</span> <span style="color:#996600;">"Following #{user}... "</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; result = post <span style="color:#996600;">"/friendships/create/#{user}.json"</span>, auth_user, password</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">puts</span> result</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; </div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> get path</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; Net::HTTP.<span style="color:#9900CC;">get</span> 'search.<span style="color:#9900CC;">twitter</span>.<span style="color:#9900CC;">com</span>', path</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; </div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> post path, auth_user, password</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; request = Net::HTTP::Post.<span style="color:#9900CC;">new</span> path</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; request.<span style="color:#9900CC;">basic_auth</span> auth_user, password</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; response = Net::HTTP.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>'twitter.<span style="color:#9900CC;">com</span>'<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">start</span> <span style="color:#006600; font-weight:bold;">&#123;</span>|http| http.<span style="color:#9900CC;">request</span><span style="color:#006600; font-weight:bold;">&#40;</span>request<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#125;</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; &nbsp; <span style="color:#006600; font-weight:bold;">&#40;</span>response.<span style="color:#9900CC;">kind_of</span>? Net::HTTPSuccess<span style="color:#006600; font-weight:bold;">&#41;</span> ? 'OK' : 'Failed'</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">end</span></div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">&nbsp;</div>
</li>
<li style="font-weight: bold;color:#26536A;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;"><span style="color:#9966CC; font-weight:bold;">include</span> FollowMeStephen</div>
</li>
<li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;color:#3A6A8B;">
<div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;">run </div>
</li>
</ol>
</div>
</div>
</div>
<p></p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrybuckley.org/2009/03/15/api-vs-rsi/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>My (very!) small part in the Array#forty_two controversy</title>
		<link>http://www.kerrybuckley.org/2008/11/24/my-very-small-part-in-the-arrayforty_two-controversy/</link>
		<comments>http://www.kerrybuckley.org/2008/11/24/my-very-small-part-in-the-arrayforty_two-controversy/#comments</comments>
		<pubDate>Mon, 24 Nov 2008 12:52:11 +0000</pubDate>
		<dc:creator>Kerry</dc:creator>
				<category><![CDATA[General nonsense]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.kerrybuckley.org/2008/11/24/my-very-small-part-in-the-arrayforty_two-controversy/</guid>
		<description><![CDATA[For those outside the Rails community who have no idea what I'm on about, some people got a bit upset about Rails 2.2 defining Array#second up to Array#tenth, so for example you can call foo.fifth instead of foo[4] (you can already call foo.first instead of foo[0]). One of the last changes to be committed before [...]]]></description>
			<content:encoded><![CDATA[<p>For those outside the Rails community who have no idea what I'm on about, some people got a bit upset about Rails 2.2 defining <code>Array#second</code> up to <code>Array#tenth</code>, so for example you can call <code>foo.fifth</code> instead of <code>foo[4]</code> (you can already call <code>foo.first</code> instead of <code>foo[0]</code>). One of the last changes to be committed before 2.2 was released was to slim the list down to just second, third, fourth and fifth, but <a href="http://github.com/rails/rails/commit/e50530ca3ab5db53ebc74314c54b62b91b932389">adding <code>Array#forty_two</code></a> (<a href="http://en.wikipedia.org/wiki/Answer_to_Life,_the_Universe,_and_Everything#Answer_to_Life.2C_the_Universe_and_Everything_.2842.29">the ultimate answer</a>) instead.</p>
<p><img src='http://www.kerrybuckley.org/wp-content/uploads/2008/11/dhh_tweet.png' alt='dhh_tweet.png' /></p>
<p><img src='http://www.kerrybuckley.org/wp-content/uploads/2008/11/commit_1.png' alt='commit_1.png' /></p>
<p><img src='http://www.kerrybuckley.org/wp-content/uploads/2008/11/kerry_reply.png' alt='kerry_reply.png' /></p>
<p><img src='http://www.kerrybuckley.org/wp-content/uploads/2008/11/dhh_reply.png' alt='dhh_reply.png' /></p>
<p><img src='http://www.kerrybuckley.org/wp-content/uploads/2008/11/commit_2.png' alt='commit_2.png' /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrybuckley.org/2008/11/24/my-very-small-part-in-the-arrayforty_two-controversy/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Rails 2.2 Envycast Review</title>
		<link>http://www.kerrybuckley.org/2008/11/08/rails-22-envycast-review/</link>
		<comments>http://www.kerrybuckley.org/2008/11/08/rails-22-envycast-review/#comments</comments>
		<pubDate>Sat, 08 Nov 2008 21:04:43 +0000</pubDate>
		<dc:creator>Kerry</dc:creator>
				<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.kerrybuckley.org/2008/11/08/rails-22-envycast-review/</guid>
		<description><![CDATA[I've been a fan of the RailsEnvy guys (Gregg Pollack and Jason Seifer) ever since their "Hi, I'm Ruby on Rails" spoof of the "I'm a Mac" ads, and have been listening to their podcast ever since. I even got a mention on it once. Well that's not strictly true &#8211; I wasn't actually mentioned, [...]]]></description>
			<content:encoded><![CDATA[<p>I've been a fan of the <a href="http://www.railsenvy.com/">RailsEnvy</a> guys (Gregg Pollack and Jason Seifer) ever since their "<a href="http://www.railsenvy.com/2007/5/14/ruby-on-rails-commercial">Hi, I'm Ruby on Rails</a>" spoof of the "I'm a Mac" ads, and have been listening to their <a href="http://www.railsenvy.com/podcast">podcast</a> ever since. I even got a mention on it once. Well that's not strictly true &ndash; I wasn't <em>actually</em> mentioned, but a <a href="http://capistrano.lighthouseapp.com/projects/8716/tickets/18-add-support-chain-of-gateways">patch</a> I'd contributed to Capistrano was, which is close enough.</p>
<p>Recently, Gregg and Jason have branched out into screencasts, but I hadn't actually watched one because (understandably) they charge for them, and I was too tight to cough up the cash. &pound;1200 for a new MacBook, no problem. A fiver for a screencast? What am I, made of money?</p>
<p>Anyhow, when I <a href="http://twitter.com/greggpollack/status/981073984">saw</a> that they were looking for people to review their <a href="http://envycasts.com/products/ruby-on-rails-22-screencast" title="Ruby on Rails 2.2 Envycast">Ruby on Rails Envycast</a>, covering the latest goodness in Rails 2.2, I jumped at the chance to get a free copy. A wonderful example of cognitive bias, given that I wouldn't have agreed to write a review just to be paid $16.</p>
<h4>What do I get for the money?</h4>
<p>The basic $9 gets you the screencast and a set of code samples to go with it, or for $16 they'll throw in Carlos Brando's <em>Ruby on Rails 2.2</em> PDF too. Alternatively the PDF is available on its own, also for $9.</p>
<h4>Video</h4>
<p>The video is available in Quicktime or Ogg formats at a resolution of 569&times;480, as well as a version optimised for iPhones and iPods. Total running time is just under 45 minutes, and incredibly the first 39&frac12; of those go by before Jason makes any claims about Rails's scalability.</p>
<p>I don't know whether it's unique, but the Envycast style of having the presenters chroma-keyed onto the Keynote presentation generally works very well. The visuals themselves are professional, although sometimes the 'sparkle' effect is a bit overused for my taste. The presentation style is much as you'd expect if you've listened to the podcasts, with plenty of cheesy humour to keep things interesting. I think having two people present in a conversational style is a big help.</p>
<p>The screencast is split into sections, each covering the new features for a different component (ActiveRecord, ActiveSupport, ActionPack, ActionController, Railties, internationalization and performance). The Quicktime version (not sure about the others) has bookmarks, making it easy to jump to a particular section. The whole thing is set against a variety of city skylines to liven the background up a little &ndash; by the way guys, that's <a href="http://en.wikipedia.org/wiki/Tower_bridge">Tower Bridge</a>, not <a href="http://en.wikipedia.org/wiki/London_bridge">London Bridge</a>.</p>
<p>Each new feature is introduced with an example, generally contrasting the 'old' way of doing something with the equivalent in 2.2. There's enough detail to get the idea of what's changed, without dwelling too long on each one. One tiny gripe with the code snippets on screen: the pedant in me hates seeing curly quotes in code, because I know if I typed <code>puts &lsquo;foo&rsquo;</code> into irb instead of <code>puts &apos;foo&apos;</code>, it wouldn't work.</p>
<h4>Code samples</h4>
<p>The screencast comes with a set of code samples to illustrate all the features discussed in the screencast. These take the form of sample classes with Test::Unit test cases, along with rakefiles to run them. The sample directory contains a frozen installation of Rails 2.2, so all you need to do to run them is add the appropriate values to database.yml. I had trouble running them initially because they were inside a directory with a space in its name, but other than that it all worked nicely.</p>
<h4>PDF</h4>
<p>The PDF that comes with the $16 bundle is by Carlos Brando, well-known for his free Rails 2.1 book. It's available in the original Portugese, or translated to English by Carl Youngblood. The book weighs in at 118 pages, and as you would expect goes into more detail than the screencast. It claims to cover all the major changes in Rails 2.2 (I haven't checked!), and contains clear descriptions with examples.</p>
<h4>Conclusion</h4>
<p>So is it worth it? On balance, I think the answer is yes, although I wonder whether they'd sell more at $5 rather than $9 &ndash; after all, I can buy (to pick an example at random) the entire Naked Gun trilogy on DVD for roughly the same amount, and Gregg and Jason aren't <em>that</em> funny. The value is in collecting all the information in one place &ndash; you <em>could</em> trawl through the release notes and lighthouse tickets to get all the same information, but if you value your time at all, the screencast and PDF pay for themselves many times over.</p>
<p>Should you buy the PDF, the video or both? If you just want the hard facts, go for the PDF, but if you want to be entertained too (assuming you find the Rails Envy podcasts entertaining), get the video as well. The next episode, <a href="http://envycasts.com/products/scaling-ruby">Scaling Ruby</a>, is out now, and I might buy it just to see if Jason finally admits that Rails might actually be able to scale.</p>
<p>Technorati Tags: <a href="http://technorati.com/tag/railsenvy+screencast+rails2.2" rel="tag">railsenvy screencast rails2.2</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrybuckley.org/2008/11/08/rails-22-envycast-review/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Defending Ruby and Rails in the Enterprise</title>
		<link>http://www.kerrybuckley.org/2008/06/12/defending-ruby-and-rails-in-the-enterprise/</link>
		<comments>http://www.kerrybuckley.org/2008/06/12/defending-ruby-and-rails-in-the-enterprise/#comments</comments>
		<pubDate>Thu, 12 Jun 2008 09:42:52 +0000</pubDate>
		<dc:creator>Kerry</dc:creator>
				<category><![CDATA[Enterprise]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.kerrybuckley.org/2008/06/12/defending-ruby-and-rails-in-the-enterprise/</guid>
		<description><![CDATA[I consider myself fortunate that the previous two projects I worked on (the BT Web21C Portal and Mojo) were Rails-based (actually it wan't just luck in the former case, as I had a part in selecting the framework). I love the expressiveness and flexibility of the Ruby language, the power and relative simplicity of the [...]]]></description>
			<content:encoded><![CDATA[<p>I consider myself fortunate that the previous two projects I worked on (the <a href="http://web21c.bt.com/">BT Web21C Portal</a> and <a href="http://mojo.bt.com/">Mojo</a>) were Rails-based (actually it wan't just luck in the former case, as I had a part in selecting the framework). I love the expressiveness and flexibility of the Ruby language, the power and relative simplicity of the Rails framework, and the all-round awesomeness of tools like <a href="http://rspec.info/">RSpec</a> and <a href="http://capify.org/">Capistrano</a>, and I don't particularly relish the thought of going back to Java (although I'm told that <a href="http://springframework.org/">Spring</a> is much nicer than last time I used it).</p>
<p>At our recent release planning session, I was assigned to a new project, which involves (among other things) exposing a CLI-based configuration interface as a web service. In our initial discussions, <a href="http://twitter.com/drpep">the</a> <a href="http://twitter.com/ddunwoody">four</a> <a href="http://twitter.com/moserp">of</a> <a href="http://twitter.com/kerryb">us</a> more-or-less agreed on a few initial decisions:</p>
<ul>
<li>The exposure should be <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</a>. Fortunately the people developing the upstream system shared this opinion.</li>
<li>Rails is an ideal framework for RESTful web services.</li>
<li>Ruby seemed like a good fit for parsing the command responses too.</li>
<li>Asynchronous behaviour would be handled using queues (probably <a href="http://activemq.apache.org/">ActiveMQ</a>).</li>
</ul>
<p>Since we'd all been working on Rails projects when the new team was formed, we assumed that this wouldn't be a particularly contentious route to go down, but unfortunately our director/architect/boss didn't see things quite the same way. He had two main objections:</p>
<ul>
<li>Rails may make sense for GUI applications, but why on earth would you use it for a service? All our other [SOAP] services are written in Java.</li>
<li>At some point the application will need to go into support, and we don't have support/operations people with Ruby or Rails experience</li>
</ul>
<p>I think the first point's easier to address, as I'd argue it's based on a misunderstanding: Rails isn't really anything to do with GUIs, but is a framework for creating MVC web applications. Virtually all the heavy lifting Rails takes care of is in the controller and model areas, with the creation of the actual visible GUI being left to the developer to take care of with the usual mix of HTML, CSS and Javascript. The only thing Rails adds is the ability to insert dynamic content using <a href="http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html">ERB</a> &ndash; similar to the role of JSP in Java EE.</p>
<p>A RESTful web service is, to all intents and purposes, the same as a normal web application, but (potentially) without the HTML. All the power that Rails brings to web application development is also harnessed when creating RESTful services.</p>
<p>The second point represents a much more fundamental strategy choice. If the company makes the decision that all development is going to use Java (the language as well as the platform), then we inevitably lose the flexibility to choose what may appear (in a local context) to be the right tool for the job. Personally I think that would be a shortsighted and ill-informed decision: if that were the strategy, we'd presumably all still be developing in C, or COBOL, or Assembler. Or we'd have gone bust. But then I'm not an architect (incidentally, according to Peter Gillard-Moss, that's <a href="http://jupitermoonbeam.blogspot.com/2008/06/10-things-that-should-get-devs-fired.html">reason number 10</a> why I don't deserve to be fired), so what do I know?</p>
<p>However, if Ruby <em>is</em> considered an acceptable technology choice for "normal" web applications, we'll still need people with appropriate skills to support those, so the problem doesn't go away. I suspect even for a Java specialist, supporting a well-written Rails application with good test coverage is probably easier than supporting some of the spaghetti-coded Java I've seen.</p>
<p>Anyway, our arguments obviously weren't totally unconvincing, because we were given a couple of weeks to show what we could produce before getting a final decision. That time runs out on Monday, so if I'm unnaturally grumpy after that it'll be because we've been told to chuck all our work so far away and start from scratch in Java. Or possibly FORTRAN.</p>
<p><strong>Update, 16 June</strong> Well we made our case, and we get to stick with Rails. Celebration all round!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.kerrybuckley.org/2008/06/12/defending-ruby-and-rails-in-the-enterprise/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.811 seconds -->

