<?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>Meta Bates &#187; ruby</title>
	<atom:link href="http://www.metabates.com/tag/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.metabates.com</link>
	<description>The technical ramblings of Mark Bates.</description>
	<lastBuildDate>Wed, 01 Feb 2012 16:25:34 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Using Sprockets without Rails</title>
		<link>http://www.metabates.com/2011/08/31/using-sprockets-without-rails/</link>
		<comments>http://www.metabates.com/2011/08/31/using-sprockets-without-rails/#comments</comments>
		<pubDate>Wed, 31 Aug 2011 19:17:23 +0000</pubDate>
		<dc:creator>Mark Bates</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[coffee script]]></category>
		<category><![CDATA[coffeescript]]></category>
		<category><![CDATA[rack]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[sprockets]]></category>

		<guid isPermaLink="false">http://www.metabates.com/?p=503</guid>
		<description><![CDATA[I&#8217;ve started working this week on an example application for the next book I&#8217;m about to write and I wanted a simple way for my readers to easily run the app (it&#8217;s going to be a single HTML file with a ton of cool JavaScript going on in it). My first choice for running this [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve started working this week on an example application for the next book I&#8217;m about to write and I wanted a simple way for my readers to easily run the app (it&#8217;s going to be a single HTML file with a ton of cool JavaScript going on in it). My first choice for running this app was to use the popular Ruby library, <a href="http://rack.rubyforge.org/" target="_blank">Rack</a>. If you are unfamiliar with Rack, please check it out. It provides a simple interface for writing web applications. By writing a simple Ruby file readers can use their favorite Rack compatible web server to launch the application. Sounds simple, eh? That&#8217;s because it is.</p>
<p>With a simple Rack application written in a few lines of code I was able to start developing my example application. That&#8217;s when I realized I needed a good way to serve up all my <a href="http://jashkenas.github.com/coffee-script/" target="_blank">CoffeeScript</a> and <a href="http://sass-lang.com/" target="_blank">Sass</a> files. I was going to write a watchr script that did this, but I thought that was a bit heavy handed, and not very flexible, so I turned to <a href="https://github.com/sstephenson/sprockets" target="_blank">Sprockets</a>.</p>
<p>Sprockets recently gained a lot of attention because it is bundled in with <a href="http://guides.rubyonrails.org/3_1_release_notes.html" target="_blank">Rails 3.1</a> to serve up an application&#8217;s assets. It&#8217;s a clever little library that will process your files using CoffeeScript, Sass, etc&#8230; and let you bundle them up in to a single asset by using a manifest. That was exactly what I wanted. After I spent the better part of an afternoon doing a bit of research and debugging here is the Rack configuration file I came up with:</p>
<div id="gist-1184400" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="nb">require</span> <span class="s1">&#39;sprockets&#39;</span></div><div class='line' id='LC2'><span class="n">project_root</span> <span class="o">=</span> <span class="no">File</span><span class="o">.</span><span class="n">expand_path</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">))</span></div><div class='line' id='LC3'><span class="n">assets</span> <span class="o">=</span> <span class="no">Sprockets</span><span class="o">::</span><span class="no">Environment</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">project_root</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">env</span><span class="o">|</span></div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="n">env</span><span class="o">.</span><span class="n">logger</span> <span class="o">=</span> <span class="no">Logger</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="no">STDOUT</span><span class="p">)</span></div><div class='line' id='LC5'><span class="k">end</span></div><div class='line' id='LC6'><br/></div><div class='line' id='LC7'><span class="n">assets</span><span class="o">.</span><span class="n">append_path</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">project_root</span><span class="p">,</span> <span class="s1">&#39;app&#39;</span><span class="p">,</span> <span class="s1">&#39;assets&#39;</span><span class="p">))</span></div><div class='line' id='LC8'><span class="n">assets</span><span class="o">.</span><span class="n">append_path</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">project_root</span><span class="p">,</span> <span class="s1">&#39;app&#39;</span><span class="p">,</span> <span class="s1">&#39;assets&#39;</span><span class="p">,</span> <span class="s1">&#39;javascripts&#39;</span><span class="p">))</span></div><div class='line' id='LC9'><span class="n">assets</span><span class="o">.</span><span class="n">append_path</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">project_root</span><span class="p">,</span> <span class="s1">&#39;app&#39;</span><span class="p">,</span> <span class="s1">&#39;assets&#39;</span><span class="p">,</span> <span class="s1">&#39;stylesheets&#39;</span><span class="p">))</span></div><div class='line' id='LC10'><br/></div><div class='line' id='LC11'><span class="n">map</span> <span class="s2">&quot;/assets&quot;</span> <span class="k">do</span></div><div class='line' id='LC12'>&nbsp;&nbsp;<span class="n">run</span> <span class="n">assets</span></div><div class='line' id='LC13'><span class="k">end</span></div><div class='line' id='LC14'><br/></div><div class='line' id='LC15'><span class="n">map</span> <span class="s2">&quot;/&quot;</span> <span class="k">do</span></div><div class='line' id='LC16'>&nbsp;&nbsp;<span class="n">run</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="o">|</span><span class="n">env</span><span class="o">|</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">[</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="mi">200</span><span class="p">,</span> </div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">{</span></div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s1">&#39;Content-Type&#39;</span>  <span class="o">=&gt;</span> <span class="s1">&#39;text/html&#39;</span><span class="p">,</span> </div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s1">&#39;Cache-Control&#39;</span> <span class="o">=&gt;</span> <span class="s1">&#39;public, max-age=86400&#39;</span> </div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">},</span></div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="no">File</span><span class="o">.</span><span class="n">open</span><span class="p">(</span><span class="s1">&#39;public/index.html&#39;</span><span class="p">,</span> <span class="no">File</span><span class="o">::</span><span class="no">RDONLY</span><span class="p">)</span></div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="o">]</span></div><div class='line' id='LC25'>&nbsp;&nbsp;<span class="p">}</span></div><div class='line' id='LC26'><span class="k">end</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1184400/525bacf6830e9f5ae339b9f2f60814d146d7e529/config.ru" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1184400#file_config.ru" style="float:right;margin-right:10px;color:#666">config.ru</a>
            <a href="https://gist.github.com/1184400">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>That will serve</p>
<pre>/assets/application.css</pre>
<p>via Sprockets. The file itself will live in</p>
<pre>&lt;pwd&gt;/app/assets/stylesheets/application.scss</pre>
<p>The same goes for JavaScript files.</p>
<p>Hopefully this will save someone else a little of time when they&#8217;re trying to do the same thing. Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.metabates.com/2011/08/31/using-sprockets-without-rails/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CoffeeScript &#8211; A Rubyist&#8217;s Love Affair</title>
		<link>http://www.metabates.com/2011/08/10/coffeescript-a-rubyists-love-affair/</link>
		<comments>http://www.metabates.com/2011/08/10/coffeescript-a-rubyists-love-affair/#comments</comments>
		<pubDate>Wed, 10 Aug 2011 13:55:20 +0000</pubDate>
		<dc:creator>Mark Bates</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[bostonrb]]></category>
		<category><![CDATA[coffee script]]></category>
		<category><![CDATA[coffeescript]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.metabates.com/?p=499</guid>
		<description><![CDATA[Last night I had the pleasure of presenting to the Boston Ruby User&#8217;s Group on CoffeeScript. My talk was geared to helping Rubyists understand, and hopefully love, CoffeeScript. Along the way I tried to debunk a few myths and preconceptions as to what CoffeeScript is and isn&#8217;t. The reaction was really positive, so hopefully I [...]]]></description>
			<content:encoded><![CDATA[<p>Last night I had the pleasure of presenting to the <a href="http://www.bostonrb.org">Boston Ruby User&#8217;s Group</a> on CoffeeScript. My talk was geared to helping Rubyists understand, and hopefully love, CoffeeScript. Along the way I tried to debunk a few myths and preconceptions as to what CoffeeScript is and isn&#8217;t. The reaction was really positive, so hopefully I did my job. Anyway, here are the slides:</p>
<p><a href="http://www.slideshare.net/markykang/coffeescript-bostonrb-892011">http://www.slideshare.net/markykang/coffeescript-bostonrb-892011</a></p>
<p>&nbsp;</p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.metabates.com/2011/08/10/coffeescript-a-rubyists-love-affair/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Let&#8217;s say goodbye to YAML for configuration, shall we?</title>
		<link>http://www.metabates.com/2011/06/28/lets-say-goodbye-to-yaml-for-configuration-shall-we/</link>
		<comments>http://www.metabates.com/2011/06/28/lets-say-goodbye-to-yaml-for-configuration-shall-we/#comments</comments>
		<pubDate>Tue, 28 Jun 2011 17:31:46 +0000</pubDate>
		<dc:creator>Mark Bates</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[configatron]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[yaml]]></category>

		<guid isPermaLink="false">http://www.metabates.com/?p=482</guid>
		<description><![CDATA[I have to ask a question to my fellow Rubyists out there? Why are you still using YAML? I know why you think you like YAML. You think it&#8217;s a great way to write configuration files, but it&#8217;s really not. You know what&#8217;s a great way of writing configuration files for Ruby apps? RUBY! I [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.metabates.com/wp-content/uploads/2011/06/yml.png"><img class="alignleft size-medium wp-image-489" title="yml" src="http://www.metabates.com/wp-content/uploads/2011/06/yml-300x300.png" alt="" width="180" height="180" /></a>I have to ask a question to my fellow Rubyists out there? Why are you still using YAML? I know why you <em>think</em> you like YAML. You think it&#8217;s a great way to write configuration files, but it&#8217;s really not. You know what&#8217;s a great way of writing configuration files for Ruby apps? RUBY!</p>
<p>I know it&#8217;s crazy, isn&#8217;t it? But why not? Why would you not want to use Ruby for configuring your applications instead of YAML?</p>
<p>I&#8217;m the maintainer of a pretty popular configuration tool for Ruby apps, <a href="http://github.com/markbates/configatron">Configatron</a>, so I think I have a little experience in this field. I also write and maintain a lot of libraries that require configuration and I have never thought that YAML is the best way to do this.</p>
<p>Let&#8217;s look at an example of what a library developer has to do to load a YAML file to get configurations:</p>
<div id="gist-1051635" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="l-Scalar-Plain">foo</span><span class="p-Indicator">:</span></div><div class='line' id='LC2'>&nbsp;&nbsp;<span class="l-Scalar-Plain">bar</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1051635/8b2f51859c67c88817a39ec2637be8a4a42b0789/config.yml" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1051635#file_config.yml" style="float:right;margin-right:10px;color:#666">config.yml</a>
            <a href="https://gist.github.com/1051635">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="nb">require</span> <span class="s1">&#39;yaml&#39;</span></div><div class='line' id='LC2'><span class="n">config</span> <span class="o">=</span> <span class="no">YAML</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="no">ERB</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="s1">&#39;/path/to/config.yml&#39;</span><span class="p">))</span><span class="o">.</span><span class="n">result</span><span class="p">)</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1051635/26ccf1d5e93777a585e7dec43204e9d3857e2b4c/gistfile1.rb" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1051635#file_gistfile1.rb" style="float:right;margin-right:10px;color:#666">gistfile1.rb</a>
            <a href="https://gist.github.com/1051635">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>I don&#8217;t know about you, but I think that&#8217;s kind of lame. Most everybody runs their YAML files through ERB so that they can make their YAML files more &#8216;Ruby-ish&#8217;. Why not just use Ruby?? Here&#8217;s the same example in Ruby:</p>
<div id="gist-1051638" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="no">SomeLibrary</span><span class="o">.</span><span class="n">config</span> <span class="o">=</span> <span class="p">{</span><span class="ss">:foo</span> <span class="o">=&gt;</span> <span class="ss">:bar</span><span class="p">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1051638/61390f260946f24cd62e871e379b8b7c334aa25d/config.rb" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1051638#file_config.rb" style="float:right;margin-right:10px;color:#666">config.rb</a>
            <a href="https://gist.github.com/1051638">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="nb">require</span> <span class="s1">&#39;/path/to/config.rb&#39;</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/1051638/f64d4b978dfcdffdc6d08d4983c264f93d36ce28/gistfile1.rb" style="float:right;">view raw</a>
            <a href="https://gist.github.com/1051638#file_gistfile1.rb" style="float:right;margin-right:10px;color:#666">gistfile1.rb</a>
            <a href="https://gist.github.com/1051638">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>In addition to not having to deal with all the whitespace, tabs, crazy nesting, etc&#8230; that YAML brings we get to use the full power of Ruby for our configurations! Try storing a Proc in YAML. Yeah, that&#8217;s what I thought. You can drive configurations from the database, environment variables, crazy equations, etc&#8230; the world is your oyster. All you need to do now is stop using YAML!</p>
<p>I&#8217;ve decided to drop YAML support in Configatron 2.9 (coming sometime this Summer) and I encourage all other library developers to do the same. It&#8217;s just not needed, or very nice for that matter. Now, if we can only get Rails to drop the database.yml file, I think we&#8217;ll be all set.</p>
<address>Ps. Make sure to check out my app <a href="http://www.fluxtracker.com?ref=yaml">FluxTracker.com</a> for all your issue, project, and error tracking needs. Also check out <a href="http://tweetko.com?ref=yaml">TweetKO.com</a> for backing up and bookmarking your favorite tweets.</address>
]]></content:encoded>
			<wfw:commentRss>http://www.metabates.com/2011/06/28/lets-say-goodbye-to-yaml-for-configuration-shall-we/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Project, Issue, and Error Tracking United!</title>
		<link>http://www.metabates.com/2011/04/25/project-issue-and-error-tracking-united/</link>
		<comments>http://www.metabates.com/2011/04/25/project-issue-and-error-tracking-united/#comments</comments>
		<pubDate>Mon, 25 Apr 2011 12:00:45 +0000</pubDate>
		<dc:creator>Mark Bates</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[News]]></category>
		<category><![CDATA[Press]]></category>
		<category><![CDATA[Releases]]></category>
		<category><![CDATA[basecamp]]></category>
		<category><![CDATA[error tracking]]></category>
		<category><![CDATA[fluxtracker]]></category>
		<category><![CDATA[hoptoad]]></category>
		<category><![CDATA[issue tracking]]></category>
		<category><![CDATA[lighthouse]]></category>
		<category><![CDATA[project management]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.metabates.com/?p=436</guid>
		<description><![CDATA[For the last few years every project or company I&#8217;ve worked for has started the same way, by setting up Basecamp, Lighthouse and Hoptoad (or similar ones anyway). Why? Basecamp  - so we could share documents and todos. Lighthouse &#8211; so we could track our issues and bugs. Hoptoad &#8211; so we could track the [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.metabates.com/wp-content/uploads/2011/04/issue_list_big.png"><img class="alignleft size-medium wp-image-437" title="issue_list_big" src="http://www.metabates.com/wp-content/uploads/2011/04/issue_list_big-300x225.png" alt="" width="300" height="225" /></a>For the last few years every project or company I&#8217;ve worked for has started the same way, by setting up Basecamp, Lighthouse and Hoptoad (or similar ones anyway). Why? Basecamp  - so we could share documents and todos. Lighthouse &#8211; so we could track our issues and bugs. Hoptoad &#8211; so we could track the errors our application was generating.</p>
<p>These are all very good applications and have served myself and my clients well, but they&#8217;ve suffered from several very big flaws. The first big flaw was the cost. You can easily drop $100 or more a month across these different services. But that wasn&#8217;t the biggest flaw or problem I&#8217;ve had with these services. The biggest problem was lack of integration.</p>
<p>So what do I mean by lack of integration? Well, when an error comes in I want to easily be able to create a new issue from it. When the issue gets resolved, so should the error. If the error reoccurs it should re-open automatically, and so should the issue. I want to be able to create an issue right from a document or be able to attach issues to a document. I should be able to follow the flow from document to issue to error and back again very easily. Unfortunately, these applications don&#8217;t give you that level of integration. They offer some level, but just not enough.</p>
<p>Well, my friends, welcome to the future. Welcome to <strong><a href="http://www.fluxtracker.com?ref=metabates">FluxTracker.com</a></strong>. FluxTracker combines a great issue tracker, a project management system, and an error tracker all in one application. Now you can full integration without any configuration, oh, and you can do it at a fraction of the cost!</p>
<p>We know it isn&#8217;t easy to switch to a different application, that&#8217;s why we&#8217;ve made it easy for you. You can easily <a href="http://www.fluxtracker.com/pages/lighthouse_importing?ref=metabates">import your Lighthouse</a> account. FluxTracker also allows you to easily use the <a href="http://www.fluxtracker.com/pages/api/hoptoad_notifier?ref=metabates">Hoptoad Notifier</a> plugin for your project by just setting a few configuration parameters.</p>
<p>So know you know, you&#8217;re life can be easier. And you now know how easy it is to get started! So what are you waiting for? Go and <a href="https://www.fluxtracker.com/signup?ref=metabates">sign up</a> for our Free plan and start living the dream.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.metabates.com/2011/04/25/project-issue-and-error-tracking-united/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Because everybody has an opinion&#8230;</title>
		<link>http://www.metabates.com/2011/04/15/because-everybody-has-an-opinion/</link>
		<comments>http://www.metabates.com/2011/04/15/because-everybody-has-an-opinion/#comments</comments>
		<pubDate>Sat, 16 Apr 2011 01:30:20 +0000</pubDate>
		<dc:creator>Mark Bates</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[active record]]></category>
		<category><![CDATA[coffee script]]></category>
		<category><![CDATA[erb]]></category>
		<category><![CDATA[haml]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rspec]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.metabates.com/?p=430</guid>
		<description><![CDATA[In case you&#8217;ve been living in a cave this week you&#8217;ve probably heard that Ruby on Rails is going to be including both the CoffeeScript and SASS libraries, it will also make jQuery the default JavaScript framework, replacing the Prototype framework. I would like to start by addressing my experiences with CoffeeScript. My opinion of [...]]]></description>
			<content:encoded><![CDATA[<p>In case you&#8217;ve been living in a cave this week you&#8217;ve probably heard that <a href="http://www.rubyinside.com/rails-3-1-adopts-coffeescript-jquery-sass-and-controversy-4669.html">Ruby on Rails</a> is going to be including both the <a href="http://coffeescript.org/">CoffeeScript</a> and <a href="http://sass-lang.com/">SASS</a> libraries, it will also make <a href="http://jquery.com/">jQuery</a> the default JavaScript framework, replacing the <a href="http://www.prototypejs.org/">Prototype</a> framework.</p>
<p>I would like to start by addressing my experiences with CoffeeScript. My opinion of it is of ambivalence. I&#8217;ve used it on a project, I&#8217;ve played with and in the end I&#8217;ve come out with the opinion of &#8220;it&#8217;s ok&#8221;. It didn&#8217;t blow me away, but at the same time I can see why so many people like. It offers some really cool features that I really wish JavaScript had and you can cut down on the amount of code you have to write. On the other hand the apps I tend to write don&#8217;t tend to be that JavaScript heavy that I really needed to reach out for something like CoffeeScript.</p>
<p><img class="alignleft" src="http://blogs.worldbank.org/files/publicsphere/public%20opinion_JGRNLY.jpeg" alt="" width="326" height="246" />So, how do I feel about CoffeeScript being included with Rails? Well, I&#8217;ll get to that. Let&#8217;s go over some of the most common arguments I&#8217;ve heard from people this week about why they&#8217;re anti-CoffeeScript in Rails.</p>
<blockquote><p>&#8220;It&#8217;s an abstraction layer of JavaScript! JavaScript isn&#8217;t that bad, why can&#8217;t you just write JavaScript?&#8221;</p>
<p>&#8220;It&#8217;s going to be a hinderance to newbies. It&#8217;ll be too much of a learning curve!&#8221;</p></blockquote>
<p>Let&#8217;s start with that second point first, shall we? I agree, it does represent a new element that needs to be learned when coming to Rails. But here&#8217;s the pretty nifty thing about how it&#8217;s all implemented in Rails. In order to actually use CoffeeScript in Rails you have to create your files named foo.js.coffee if, however, you just name your file foo.js then, guess what? You will have to write plain old JavaScript! Seems like newbies, and those who don&#8217;t like CoffeeScript, can just keep writing plain old JavaScript without anything stopping them at all.</p>
<p>Now, let&#8217;s talk about the abstraction layer argument. Yes, CoffeeScript is an abstraction on top of JavaScript, but let&#8217;s take a look at a few other parts of the Rails stack and see how they hold up against this argument.</p>
<p>Here&#8217;s a fairly common Rails stack:</p>
<ul>
<li>ActiveRecord</li>
<li>Haml</li>
<li>jQuery</li>
<li>RSpec</li>
</ul>
<p>What do all those things have in common? Well, they&#8217;re all abstraction layers that sit on top of something else, don&#8217;t they? Let&#8217;s look at that list again?</p>
<ul>
<li>ActiveRecord &#8211; SQL (Structured Query Language)</li>
<li>Haml &#8211; HTML</li>
<li>jQuery &#8211; JavaScript, you could just as easily hand roll those AJAX calls in pure JavaScript.</li>
<li>RSpec &#8211; Test/Unit</li>
</ul>
<p>What I&#8217;ve found funny about the particular argument is that I&#8217;ve heard it MOST from those who use things like HAML, which is a DEFINITELY an abstraction layer that sits on top of HTML. See where I&#8217;m going with this one? Good, I don&#8217;t want to belabor the point. <img src='http://www.metabates.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>So, finally, where do I stand on this whole thing? Well, I view like it Test/Unit and Prototype. Those are both the current standard (although jQuery will replace Prototype in 3.1) and I don&#8217;t like or use either of them. Instead I configure Rails to use jQuery and RSpec. I don&#8217;t like Haml, but those that do simply replace ERB with Haml and they move on with their day. So my take is this, it&#8217;s there, it&#8217;s included. Use it if you like, or don&#8217;t. Is it really that big a deal? No, it really isn&#8217;t. If Rails dropped ERB and went with Haml as the default, would I bitch and moan, probably a bit, but then I&#8217;d just install the Rails-ERB gem and move on with my day, just like I do with jQuery and RSpec today.</p>
<p>So sit back, relax, use the libraries that you want to use, Rails let&#8217;s you do that. Oh, while you&#8217;re relaxing why not try out CoffeeScript, who knows, you might just enjoy it. Or not.</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.metabates.com/2011/04/15/because-everybody-has-an-opinion/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Testing Tools Aren&#8217;t All the Same, Choose Wisely</title>
		<link>http://www.metabates.com/2011/03/04/407-testing-tools-arent-all-the-same-choose-wisely/</link>
		<comments>http://www.metabates.com/2011/03/04/407-testing-tools-arent-all-the-same-choose-wisely/#comments</comments>
		<pubDate>Fri, 04 Mar 2011 15:57:04 +0000</pubDate>
		<dc:creator>Mark Bates</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[cucumber]]></category>
		<category><![CDATA[rspec]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[steak]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[tests]]></category>

		<guid isPermaLink="false">http://www.metabates.com/?p=407</guid>
		<description><![CDATA[&#8220;Testing is painful.&#8221; &#8220;Testing is hard.&#8221; &#8220;Testing is complicated.&#8221; &#8220;Testing is not fun.&#8221; I hear those sorts of things all the time when I talk to people about testing. I agree that sometimes testing can be all of those things, but if you choose the right tools, the tools that best suite you, testing doesn&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p><img class="alignright" title="mario" src="http://www.divanikkiz.com/site/images/stories/mlss_mario-hammer.jpg" alt="" width="255" height="282" />&#8220;Testing is painful.&#8221;</p></blockquote>
<blockquote><p>&#8220;Testing is hard.&#8221;</p></blockquote>
<blockquote><p>&#8220;Testing is complicated.&#8221;</p></blockquote>
<blockquote><p>&#8220;Testing is not fun.&#8221;</p></blockquote>
<p>I hear those sorts of things all the time when I talk to people about testing. I agree that sometimes testing can be all of those things, but if you choose the right tools, the tools that best suite you, testing doesn&#8217;t have to be. Let me give you an example of what I&#8217;m talking about, how choosing the right tools can make a huge impact on how you feel about testing.</p>
<p>When working for a client recently I came across the need for end to end integration testing. I needed to test, amongst other things, the flow of a user registering through the application in a few different ways. Because registration behaves differently based on where you come from and where you want to go, I needed a good way to test that entire flow, so simple unit and functional tests just were not going to cut it.</p>
<p>In the Ruby community there is a big push to use a testing framework called, <a href="http://cukes.info/" target="_blank">Cucumber</a>. Cucumber is a behavior driven development (BDD) tool that let&#8217;s you write user stories in plain English. Those stories then get translated into Ruby code that tests those stories against your application. Because of it&#8217;s popularity, and some of it&#8217;s quite amazing features, this was my first stop on the path to integration testing bliss.</p>
<p>Let me give you an example of a Cucumber script:</p>
<div id="gist-854764" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="k">Feature:</span><span class="nf"> Registration</span></div><div class='line' id='LC2'><span class="nf">  In order to use My Great Application</span></div><div class='line' id='LC3'><span class="nf">  As a user</span></div><div class='line' id='LC4'><span class="nf">  I want to be able to register</span></div><div class='line' id='LC5'><span class="nf">  </span></div><div class='line' id='LC6'><span class="nf">  </span><span class="k">Scenario:</span><span class="nf"> &#39;Standard Registration&#39;</span></div><div class='line' id='LC7'><span class="k">    Given </span><span class="nf">I am not currently logged in</span></div><div class='line' id='LC8'><span class="nf">    </span><span class="k">When </span><span class="nf">I am on the signup page</span></div><div class='line' id='LC9'><span class="nf">    </span><span class="k">Then </span><span class="nf">I should see &quot;</span><span class="s">Sign Up</span><span class="nf">&quot;</span></div><div class='line' id='LC10'><span class="nf">    </span><span class="k">And </span><span class="nf">I fill in &quot;</span><span class="s">Name (required)</span><span class="nf">&quot; with &quot;</span><span class="s">Mickey Dolenz</span><span class="nf">&quot;</span></div><div class='line' id='LC11'><span class="nf">    </span><span class="k">And </span><span class="nf">I fill in &quot;</span><span class="s">Email (required)</span><span class="nf">&quot; with &quot;</span><span class="s">mickey@monkees.com</span><span class="nf">&quot;</span></div><div class='line' id='LC12'><span class="nf">    </span><span class="k">And </span><span class="nf">I fill in &quot;</span><span class="s">Password (required)</span><span class="nf">&quot; with &quot;</span><span class="s">password</span><span class="nf">&quot;</span></div><div class='line' id='LC13'><span class="nf">    </span><span class="k">And </span><span class="nf">I fill in &quot;</span><span class="s">Password confirmation</span><span class="nf">&quot; with &quot;</span><span class="s">password</span><span class="nf">&quot;</span></div><div class='line' id='LC14'><span class="nf">    </span><span class="k">And </span><span class="nf">I press &quot;</span><span class="s">Register</span><span class="nf">&quot;</span></div><div class='line' id='LC15'><span class="nf">    </span><span class="k">Then </span><span class="nf">I should see &quot;</span><span class="s">Sign Up - Confirm Your Account</span><span class="nf">&quot;</span></div><div class='line' id='LC16'><span class="nf">    </span><span class="k">Then </span><span class="nf">I should be on the registration thank you page</span></div><div class='line' id='LC17'><span class="nf">    </span><span class="k">Then </span><span class="nf">&quot;</span><span class="s">mickey@monkees.com</span><span class="nf">&quot; should receive an email</span></div><div class='line' id='LC18'><span class="nf">    </span><span class="k">When </span><span class="nf">I open the email</span></div><div class='line' id='LC19'><span class="nf">    </span><span class="k">Then </span><span class="nf">I should see &quot;</span><span class="s">Confirm my account</span><span class="nf">&quot; in the email body</span></div><div class='line' id='LC20'><span class="nf">    </span><span class="k">When </span><span class="nf">I follow &quot;</span><span class="s">Confirm my account</span><span class="nf">&quot; in the email</span></div><div class='line' id='LC21'><span class="nf">    </span><span class="k">Then </span><span class="nf">I should be on the welcome page</span></div><div class='line' id='LC22'><span class="nf">    </span><span class="k">And </span><span class="nf">I should see &quot;</span><span class="s">Welcome to the Great Application</span><span class="nf">&quot;</span></div><div class='line' id='LC23'><span class="nf">    </span></div><div class='line' id='LC24'><span class="nf">  </span><span class="k">Scenario:</span><span class="nf"> &#39;Accepting an invitation&#39;</span></div><div class='line' id='LC25'><span class="k">    Given </span><span class="nf">I am not currently logged in</span></div><div class='line' id='LC26'><span class="nf">    </span><span class="k">And </span><span class="nf">the &quot;</span><span class="s">Boys and Girls Club</span><span class="nf">&quot; invites &quot;</span><span class="s">mickey@monkees.com</span><span class="nf">&quot; to join</span></div><div class='line' id='LC27'><span class="nf">    </span><span class="k">Then </span><span class="nf">&quot;</span><span class="s">mickey@monkees.com</span><span class="nf">&quot; should receive an email</span></div><div class='line' id='LC28'><span class="nf">    </span><span class="k">When </span><span class="nf">I open the email</span></div><div class='line' id='LC29'><span class="nf">    </span><span class="k">Then </span><span class="nf">I should see &quot;</span><span class="s">Accept Invitation</span><span class="nf">&quot; in the email body</span></div><div class='line' id='LC30'><span class="nf">    </span><span class="k">When </span><span class="nf">I follow &quot;</span><span class="s">Accept Invitation</span><span class="nf">&quot; in the email</span></div><div class='line' id='LC31'><span class="nf">    </span><span class="k">Then </span><span class="nf">I should be on the signup page</span></div><div class='line' id='LC32'><span class="nf">    </span><span class="k">Then </span><span class="nf">I should see &quot;</span><span class="s">Sign Up</span><span class="nf">&quot;</span></div><div class='line' id='LC33'><span class="nf">    </span><span class="k">And </span><span class="nf">I fill in &quot;</span><span class="s">Name (required)</span><span class="nf">&quot; with &quot;</span><span class="s">Mickey Dolenz</span><span class="nf">&quot;</span></div><div class='line' id='LC34'><span class="nf">    </span><span class="k">And </span><span class="nf">the &quot;</span><span class="s">Email (required)</span><span class="nf">&quot; field should contain &quot;</span><span class="s">mickey@monkees.com</span><span class="nf">&quot;</span></div><div class='line' id='LC35'><span class="nf">    </span><span class="k">And </span><span class="nf">I fill in &quot;</span><span class="s">Password (required)</span><span class="nf">&quot; with &quot;</span><span class="s">password</span><span class="nf">&quot;</span></div><div class='line' id='LC36'><span class="nf">    </span><span class="k">And </span><span class="nf">I fill in &quot;</span><span class="s">Password confirmation</span><span class="nf">&quot; with &quot;</span><span class="s">password</span><span class="nf">&quot;</span></div><div class='line' id='LC37'><span class="nf">    </span><span class="k">And </span><span class="nf">I press &quot;</span><span class="s">Register</span><span class="nf">&quot;</span></div><div class='line' id='LC38'><span class="nf">    </span><span class="k">Then </span><span class="nf">the account &quot;</span><span class="s">mickey@monkees.com</span><span class="nf">&quot; should be &quot;</span><span class="s">activated</span><span class="nf">&quot;</span></div><div class='line' id='LC39'><span class="nf">    </span><span class="k">Then </span><span class="nf">I should be on the accept/decline invitation page</span></div><div class='line' id='LC40'><span class="nf">    </span><span class="k">And </span><span class="nf">I should see &quot;</span><span class="s">Join the Boys and Girls Club</span><span class="nf">&quot;</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/854764/81be0e41bf076636677685e985192e211aa693e0/registration.feature" style="float:right;">view raw</a>
            <a href="https://gist.github.com/854764#file_registration.feature" style="float:right;margin-right:10px;color:#666">registration.feature</a>
            <a href="https://gist.github.com/854764">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>That script tests the user registration flow through an application in a couple of different ways, first through &#8216;standard&#8217; registration, and then through being invited to join. Now, the beauty of Cucumber is that these scripts are &#8216;human&#8217; readable. Your product manager, or other stake holders, should be able to write these scripts themselves, and you, the developer, should be able to just plug them in and code until those scripts pass.</p>
<p>Unfortunately, while that sounds like a little slice of Heaven, the reality is far from it in practice. First, getting stake holders to actually write these &#8216;stories&#8217;, as their typically called, is a tough chore to begin with. If they do write them, they&#8217;re typically not going to be &#8216;plug and play&#8217;. Why? Well, when Cucumber reads these scripts it goes line by line and tries to find some code that matches the regular expression of that line and then execute it. If it doesn&#8217;t find matching code, then it fails. That means that your stake holders need to write these scripts in a very particular way or developers need to sit down and massage those stories to fit the correct regular expression.</p>
<p>Now, let me just take this opportunity to say that this is not a post about how much I hate Cucumber, in fact I think Cucumber is a pretty amazing piece of software, and does in fact have a lot of great uses. Instead, what I&#8217;m talking about it is how Cucumber turned out not to be the right tool for the job for me on a recent project.</p>
<p>So why wasn&#8217;t Cucumber the right tool for the job? Great question, glad you asked. Cucumber turned out not to be the right tool for a few reasons. The biggest of which was that I was the one who was writing the user stories. The stake holders had no desire to write these stories, which meant I had to write them. The I had to write the &#8216;steps&#8217; that back each line of the script. In all fairness, Cucumber does give you some great steps right out of the box. After some fiddling I finally got the Cucumber scripts up and running and testing my work flow. But I definitely ran into some issues.</p>
<p>Because Cucumber isn&#8217;t pure Ruby I had a hard time doing something as simple as just printing out the request&#8217;s body and headers without having to write a step that did just that, then add that step to my story, etc&#8230; It&#8217;s overall fiddlyness and non-intuitive way of doing things caused me a lot of grief and time. And, most importantly, I wasn&#8217;t really getting the big benefit of Cucumber, stake holder&#8217;s writing the stories. So I was doing all this work and not getting the benefits of Cucumber.</p>
<p>So what did I do? I turned to a library called <a href="https://github.com/cavalle/steak" target="_blank">Steak</a>. Steak allows you to write integration tests using pure Ruby and integrates directly in with <a href="http://relishapp.com/rspec" target="_blank">RSpec</a>, my preferred testing framework. With Steak I was able to write my integration tests in just a few minutes.</p>
<div id="gist-854844" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="nb">require</span> <span class="no">File</span><span class="o">.</span><span class="n">expand_path</span><span class="p">(</span><span class="no">File</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="bp">__FILE__</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;/acceptance_helper&#39;</span><span class="p">)</span></div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'><span class="n">feature</span> <span class="s2">&quot;Registration Steak&quot;</span><span class="p">,</span> <span class="sx">%q{</span></div><div class='line' id='LC4'><span class="sx">  In order to use My Great Application</span></div><div class='line' id='LC5'><span class="sx">  As a user</span></div><div class='line' id='LC6'><span class="sx">  I want to be able to register</span></div><div class='line' id='LC7'><span class="sx">}</span> <span class="k">do</span></div><div class='line' id='LC8'><br/></div><div class='line' id='LC9'>&nbsp;&nbsp;<span class="n">scenario</span> <span class="s2">&quot;register throught the standard registration process&quot;</span> <span class="k">do</span></div><div class='line' id='LC10'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">visit</span> <span class="n">signup_path</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">expect</span> <span class="p">{</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">fill_in_registration</span><span class="p">(</span><span class="ss">:name</span> <span class="o">=&gt;</span> <span class="s1">&#39;Mickey Dolenz&#39;</span><span class="p">,</span> <span class="ss">:email</span> <span class="o">=&gt;</span> <span class="s1">&#39;mickey@monkees.com&#39;</span><span class="p">)</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span><span class="o">.</span><span class="n">to</span> <span class="n">change</span><span class="p">(</span><span class="n">delivered_emails</span><span class="p">,</span> <span class="ss">:size</span><span class="p">)</span><span class="o">.</span><span class="n">by</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">find_by_email</span><span class="p">(</span><span class="s1">&#39;mickey@monkees.com&#39;</span><span class="p">)</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">user</span><span class="o">.</span><span class="n">should</span> <span class="n">be_unverified</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">page</span><span class="o">.</span><span class="n">should</span> <span class="n">have_content</span><span class="p">(</span><span class="s1">&#39;You have signed up successfully. However, we could not sign you in because your account is unconfirmed.&#39;</span><span class="p">)</span></div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">current_path</span><span class="o">.</span><span class="n">should</span> <span class="o">==</span> <span class="n">root_path</span></div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">visit</span> <span class="n">signin_path</span></div><div class='line' id='LC23'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">fill_in</span> <span class="s1">&#39;user_email&#39;</span><span class="p">,</span> <span class="ss">:with</span> <span class="o">=&gt;</span> <span class="s1">&#39;mickey@monkees.com&#39;</span></div><div class='line' id='LC24'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">fill_in</span> <span class="s1">&#39;user_password&#39;</span><span class="p">,</span> <span class="ss">:with</span> <span class="o">=&gt;</span> <span class="s1">&#39;password&#39;</span></div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">click_button</span> <span class="s1">&#39;Sign In&#39;</span></div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">page</span><span class="o">.</span><span class="n">should</span> <span class="n">have_content</span><span class="p">(</span><span class="s1">&#39;You have to confirm your account before continuing.&#39;</span><span class="p">)</span></div><div class='line' id='LC28'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">current_path</span><span class="o">.</span><span class="n">should</span> <span class="o">==</span> <span class="n">new_user_session_path</span></div><div class='line' id='LC29'><br/></div><div class='line' id='LC30'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">click_email_link_matching</span><span class="p">(</span><span class="sr">/users\/confirmation/</span><span class="p">,</span> <span class="n">delivered_emails</span><span class="o">.</span><span class="n">first</span><span class="p">)</span></div><div class='line' id='LC31'><br/></div><div class='line' id='LC32'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">current_path</span><span class="o">.</span><span class="n">should</span> <span class="o">==</span> <span class="n">welcome_users_path</span></div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">page</span><span class="o">.</span><span class="n">should</span> <span class="n">have_content</span><span class="p">(</span><span class="s1">&#39;Welcome to the Great Application&#39;</span><span class="p">)</span></div><div class='line' id='LC34'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">user</span><span class="o">.</span><span class="n">reload</span></div><div class='line' id='LC35'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">user</span><span class="o">.</span><span class="n">should</span> <span class="n">be_activated</span></div><div class='line' id='LC36'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC37'>&nbsp;&nbsp;</div><div class='line' id='LC38'>&nbsp;&nbsp;<span class="n">scenario</span> <span class="s2">&quot;register from an invitation&quot;</span> <span class="k">do</span></div><div class='line' id='LC39'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">mark</span> <span class="o">=</span> <span class="n">users</span><span class="p">(</span><span class="ss">:mark</span><span class="p">)</span></div><div class='line' id='LC40'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">organization</span> <span class="o">=</span> <span class="n">mark</span><span class="o">.</span><span class="n">organizations</span><span class="o">.</span><span class="n">first</span></div><div class='line' id='LC41'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">signin</span><span class="p">(</span><span class="n">mark</span><span class="p">)</span></div><div class='line' id='LC42'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC43'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">visit</span> <span class="n">new_organization_invitation_path</span><span class="p">(</span><span class="n">organization</span><span class="p">)</span></div><div class='line' id='LC44'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">expect</span> <span class="p">{</span></div><div class='line' id='LC45'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">expect</span> <span class="p">{</span></div><div class='line' id='LC46'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">fill_in</span> <span class="s1">&#39;organization_invitation_worker_emails&#39;</span><span class="p">,</span> <span class="ss">:with</span> <span class="o">=&gt;</span> <span class="s1">&#39;mickey@monkees.com&#39;</span></div><div class='line' id='LC47'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">click_button</span> <span class="s1">&#39;Send Invites&#39;</span></div><div class='line' id='LC48'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="no">DJ</span><span class="o">.</span><span class="n">first</span><span class="o">.</span><span class="n">invoke_job</span></div><div class='line' id='LC49'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span><span class="o">.</span><span class="n">to</span> <span class="n">change</span><span class="p">(</span><span class="n">delivered_emails</span><span class="p">,</span> <span class="ss">:size</span><span class="p">)</span><span class="o">.</span><span class="n">by</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span></div><div class='line' id='LC50'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span><span class="o">.</span><span class="n">to</span> <span class="n">change</span><span class="p">(</span><span class="n">organization</span><span class="o">.</span><span class="n">invitations</span><span class="p">,</span> <span class="ss">:count</span><span class="p">)</span><span class="o">.</span><span class="n">by</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span></div><div class='line' id='LC51'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC52'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">invitation</span> <span class="o">=</span> <span class="n">organization</span><span class="o">.</span><span class="n">invitations</span><span class="o">.</span><span class="n">first</span></div><div class='line' id='LC53'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC54'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">signout</span></div><div class='line' id='LC55'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC56'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">click_first_link_in_email</span><span class="p">(</span><span class="n">delivered_emails</span><span class="o">.</span><span class="n">first</span><span class="p">)</span></div><div class='line' id='LC57'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC58'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">current_path</span><span class="o">.</span><span class="n">should</span> <span class="o">==</span> <span class="n">signup_path</span></div><div class='line' id='LC59'><br/></div><div class='line' id='LC60'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">fill_in_registration</span><span class="p">(</span><span class="ss">:name</span> <span class="o">=&gt;</span> <span class="s1">&#39;Mickey Dolenz&#39;</span><span class="p">)</span></div><div class='line' id='LC61'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC62'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">current_path</span><span class="o">.</span><span class="n">should</span> <span class="o">==</span> <span class="n">organization_invitation_path</span><span class="p">(</span><span class="n">organization</span><span class="p">,</span> <span class="n">invitation</span><span class="p">)</span></div><div class='line' id='LC63'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC64'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">user</span> <span class="o">=</span> <span class="no">User</span><span class="o">.</span><span class="n">find_by_email</span><span class="p">(</span><span class="s1">&#39;mickey@monkees.com&#39;</span><span class="p">)</span></div><div class='line' id='LC65'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">user</span><span class="o">.</span><span class="n">should</span> <span class="n">be_activated</span></div><div class='line' id='LC66'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC67'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">expect</span> <span class="p">{</span></div><div class='line' id='LC68'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">click_on</span> <span class="s1">&#39;Get Started Now!&#39;</span></div><div class='line' id='LC69'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span><span class="o">.</span><span class="n">to</span> <span class="n">change</span><span class="p">(</span><span class="n">user</span><span class="o">.</span><span class="n">organizations</span><span class="p">,</span> <span class="ss">:count</span><span class="p">)</span><span class="o">.</span><span class="n">by</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span></div><div class='line' id='LC70'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC71'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">current_path</span><span class="o">.</span><span class="n">should</span> <span class="o">==</span> <span class="n">organization_campaign_path</span><span class="p">(</span><span class="n">organization</span><span class="p">,</span> <span class="n">organization</span><span class="o">.</span><span class="n">campaigns</span><span class="o">.</span><span class="n">first</span><span class="p">)</span></div><div class='line' id='LC72'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC73'>&nbsp;&nbsp;</div><div class='line' id='LC74'><span class="k">end</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/854844/45d1d080b1d1a19954d6894e08e2261b1b368166/registration_spec.rb" style="float:right;">view raw</a>
            <a href="https://gist.github.com/854844#file_registration_spec.rb" style="float:right;margin-right:10px;color:#666">registration_spec.rb</a>
            <a href="https://gist.github.com/854844">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>While my Steak scripts a bit more wordy and are definitely not &#8216;human&#8217; readable and editable by stakeholders, they did achieve my goal of allowing me to write integration tests quickly.</p>
<p>So here you see I picked a very powerful tool, that has a lot of great benefits, Cucumber, but I picked it for the wrong reasons. I picked it because it was popular, and not because it would help me achieve my goals. If my goals where to have stakeholders write the stories and hand them off to development, than it would&#8217;ve been a better choice. But in the end my goal was to write integration tests and write them quickly, which is why Steak ended up being the right tool for that job.</p>
<p>This has all been a really long winded way of saying doing some research before choosing your testing frameworks, or any framework for that matter. Play with it, research it, make sure it meets your goals, not somebody else&#8217;s. If you choose the right tools then testing doesn&#8217;t need to be scary, complicated, frustrating, etc&#8230; Testing is a <a href="http://www.metabates.com/2010/07/01/testing-is-not-an-option/">requirement</a> and a must have, so why not make it fun?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.metabates.com/2011/03/04/407-testing-tools-arent-all-the-same-choose-wisely/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Building Interfaces and Abstract Classes in Ruby</title>
		<link>http://www.metabates.com/2011/02/07/building-interfaces-and-abstract-classes-in-ruby/</link>
		<comments>http://www.metabates.com/2011/02/07/building-interfaces-and-abstract-classes-in-ruby/#comments</comments>
		<pubDate>Mon, 07 Feb 2011 20:45:05 +0000</pubDate>
		<dc:creator>Mark Bates</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.metabates.com/?p=393</guid>
		<description><![CDATA[So back in the dark ages of my career, pre-2006, I spent a long time coding Java. Yeah, I know, please don&#8217;t judge. Anyway, In Java, for those of you who are unaware were two constructs that I occasionally wish I had in Ruby, those are Interfaces and Abstract Classes. The difference between these two [...]]]></description>
			<content:encoded><![CDATA[<p>So back in the dark ages of my career, pre-2006, I spent a long time coding Java. Yeah, I know, please don&#8217;t judge. Anyway, In Java, for those of you who are unaware were two constructs that I occasionally wish I had in Ruby, those are <a href="http://download.oracle.com/javase/tutorial/java/concepts/interface.html" target="_blank">Interfaces</a> and <a href="http://download.oracle.com/javase/tutorial/java/IandI/abstract.html" target="_blank">Abstract Classes</a>. The difference between these two constructs is subtle, but important.</p>
<p>In Java an Interface is a basically a blueprint of methods that the class who implements the Interface needs to implement. For example:</p>
<div id="gist-814920" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="kd">interface</span> <span class="nc">Bicycle</span> <span class="o">{</span></div><div class='line' id='LC2'><br/></div><div class='line' id='LC3'>&nbsp;&nbsp;<span class="kt">void</span> <span class="nf">changeGear</span><span class="o">(</span><span class="kt">int</span> <span class="n">newValue</span><span class="o">);</span></div><div class='line' id='LC4'><br/></div><div class='line' id='LC5'>&nbsp;&nbsp;<span class="kt">void</span> <span class="nf">speedUp</span><span class="o">(</span><span class="kt">int</span> <span class="n">increment</span><span class="o">);</span></div><div class='line' id='LC6'><br/></div><div class='line' id='LC7'>&nbsp;&nbsp;<span class="kt">void</span> <span class="nf">applyBrakes</span><span class="o">(</span><span class="kt">int</span> <span class="n">decrement</span><span class="o">);</span></div><div class='line' id='LC8'><span class="o">}</span></div><div class='line' id='LC9'><br/></div><div class='line' id='LC10'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ACMEBicycle</span> <span class="kd">implements</span> <span class="n">Bicycle</span> <span class="o">{</span></div><div class='line' id='LC11'>&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;<span class="kd">public</span> <span class="kt">void</span> <span class="nf">changeGear</span><span class="o">(</span><span class="kt">int</span> <span class="n">newValue</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// do some work here</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;<span class="kd">public</span> <span class="kt">void</span> <span class="nf">speedUp</span><span class="o">(</span><span class="kt">int</span> <span class="n">increment</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// do some work here</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;<span class="kd">public</span> <span class="kt">void</span> <span class="nf">applyBrakes</span><span class="o">(</span><span class="kt">int</span> <span class="n">decrement</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// do some work here</span></div><div class='line' id='LC22'>&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC23'><br/></div><div class='line' id='LC24'><span class="o">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/814920/33db62faa407878926d6c84e03759ad77923053a/gistfile1.java" style="float:right;">view raw</a>
            <a href="https://gist.github.com/814920#file_gistfile1.java" style="float:right;margin-right:10px;color:#666">gistfile1.java</a>
            <a href="https://gist.github.com/814920">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>Here we have a <code>Bicycle</code> Interface that says there are three methods that need to be implemented. It is then the responsibility of the <code>ACMEBicycle</code> class to implement those methods. Now, an Abstract Class in Java is similar to an Interface in that it too is a blueprint of methods that the extending class may or may not need to implement. There in lies one of the differences between the two. Let&#8217;s take a look at the same example, but this time we want to implement the same behavior of all of our extending classes for the <code>applyBrakes</code> method:</p>
<div id="gist-814926" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">Bicycle</span> <span class="o">{</span></div><div class='line' id='LC2'>&nbsp;&nbsp;</div><div class='line' id='LC3'>&nbsp;&nbsp;<span class="kd">abstract</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">changeGear</span><span class="o">(</span><span class="kt">int</span> <span class="n">newValue</span><span class="o">);</span></div><div class='line' id='LC4'><br/></div><div class='line' id='LC5'>&nbsp;&nbsp;<span class="kd">abstract</span> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">speedUp</span><span class="o">(</span><span class="kt">int</span> <span class="n">increment</span><span class="o">);</span></div><div class='line' id='LC6'><br/></div><div class='line' id='LC7'>&nbsp;&nbsp;<span class="kd">public</span> <span class="kt">void</span> <span class="nf">applyBrakes</span><span class="o">(</span><span class="kt">int</span> <span class="n">decrement</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// do some work here</span></div><div class='line' id='LC9'>&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC10'>&nbsp;&nbsp;</div><div class='line' id='LC11'><span class="o">}</span></div><div class='line' id='LC12'><br/></div><div class='line' id='LC13'><span class="kd">public</span> <span class="kd">class</span> <span class="nc">ACMEBicycle</span> <span class="kd">extends</span> <span class="n">Bicycle</span> <span class="o">{</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;<span class="kd">public</span> <span class="kt">void</span> <span class="nf">applyBrakes</span><span class="o">(</span><span class="kt">int</span> <span class="n">decrement</span><span class="o">)</span> <span class="o">{</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1">// do some work here</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;<span class="o">}</span></div><div class='line' id='LC18'><br/></div><div class='line' id='LC19'><span class="o">}</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/814926/378f523b40a1dc33ae616ee6ffc58e3b32cc5b23/gistfile1.java" style="float:right;">view raw</a>
            <a href="https://gist.github.com/814926#file_gistfile1.java" style="float:right;margin-right:10px;color:#666">gistfile1.java</a>
            <a href="https://gist.github.com/814926">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>An Abstract Class is a great way to provide a mix of fully implemented methods as well as providing subclasses with a mixture of methods that need to be implemented by the extending class.</p>
<p>The really powerful part of all of this is two fold. First, the Java compiler will happily yell at you and fail if it finds that you haven&#8217;t implemented some of the methods that you were told you had to. Second, you can easily see the methods that you need to document right there, you can even copy/paste their definitions right into your class so you can start to fill them out.</p>
<p>So, how does this bring us over to Ruby? Great question. I&#8217;d like to take a few moments and explore a few ways we can get some of this power in Ruby.</p>
<p>Unfortunately, or fortunately depending on how you look at it (I see it as a mixed blessing), there is no compiler in Ruby, so we don&#8217;t really have a good way of having the system yell at us if we don&#8217;t implement the methods we were supposed to. But, there is still plenty we can do to help those who are implementing our classes both know what they need to implement and to find out what they haven&#8217;t implemented when their program is executing.</p>
<p>Here is one implementation on we can gain a bit of that functionality back in Ruby:</p>
<div id="gist-815110" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="k">module</span> <span class="nn">AbstractInterface</span></div><div class='line' id='LC2'>&nbsp;&nbsp;</div><div class='line' id='LC3'>&nbsp;&nbsp;<span class="k">class</span> <span class="nc">InterfaceNotImplementedError</span> <span class="o">&lt;</span> <span class="no">NoMethodError</span></div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC5'>&nbsp;&nbsp;</div><div class='line' id='LC6'>&nbsp;&nbsp;<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">included</span><span class="p">(</span><span class="n">klass</span><span class="p">)</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">klass</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="ss">:include</span><span class="p">,</span> <span class="no">AbstractInterface</span><span class="o">::</span><span class="no">Methods</span><span class="p">)</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">klass</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="ss">:extend</span><span class="p">,</span> <span class="no">AbstractInterface</span><span class="o">::</span><span class="no">Methods</span><span class="p">)</span></div><div class='line' id='LC9'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC10'>&nbsp;&nbsp;</div><div class='line' id='LC11'>&nbsp;&nbsp;<span class="k">module</span> <span class="nn">Methods</span></div><div class='line' id='LC12'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">def</span> <span class="nf">api_not_implemented</span><span class="p">(</span><span class="n">klass</span><span class="p">)</span></div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">caller</span><span class="o">.</span><span class="n">first</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sr">/in \`(.+)\&#39;/</span><span class="p">)</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">method_name</span> <span class="o">=</span> <span class="vg">$1</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">raise</span> <span class="no">AbstractInterface</span><span class="o">::</span><span class="no">InterfaceNotImplementedError</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">#{</span><span class="n">klass</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2"> needs to implement &#39;</span><span class="si">#{</span><span class="n">method_name</span><span class="si">}</span><span class="s2">&#39; for interface </span><span class="si">#{</span><span class="nb">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">!&quot;</span><span class="p">)</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC19'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC20'>&nbsp;&nbsp;</div><div class='line' id='LC21'><span class="k">end</span></div><div class='line' id='LC22'><br/></div><div class='line' id='LC23'><span class="k">class</span> <span class="nc">Bicycle</span></div><div class='line' id='LC24'>&nbsp;&nbsp;<span class="kp">include</span> <span class="no">AbstractInterface</span></div><div class='line' id='LC25'>&nbsp;&nbsp;</div><div class='line' id='LC26'>&nbsp;&nbsp;<span class="c1"># Some documentation on the change_gear method</span></div><div class='line' id='LC27'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">change_gear</span><span class="p">(</span><span class="n">new_value</span><span class="p">)</span></div><div class='line' id='LC28'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="no">Bicycle</span><span class="o">.</span><span class="n">api_not_implemented</span><span class="p">(</span><span class="nb">self</span><span class="p">)</span></div><div class='line' id='LC29'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC30'>&nbsp;&nbsp;</div><div class='line' id='LC31'>&nbsp;&nbsp;<span class="c1"># Some documentation on the speed_up method</span></div><div class='line' id='LC32'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">speed_up</span><span class="p">(</span><span class="n">increment</span><span class="p">)</span></div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="no">Bicycle</span><span class="o">.</span><span class="n">api_not_implemented</span><span class="p">(</span><span class="nb">self</span><span class="p">)</span></div><div class='line' id='LC34'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC35'>&nbsp;&nbsp;</div><div class='line' id='LC36'>&nbsp;&nbsp;<span class="c1"># Some documentation on the apply_brakes method</span></div><div class='line' id='LC37'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">apply_brakes</span><span class="p">(</span><span class="n">decrement</span><span class="p">)</span></div><div class='line' id='LC38'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># do some work here</span></div><div class='line' id='LC39'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC40'>&nbsp;&nbsp;</div><div class='line' id='LC41'><span class="k">end</span></div><div class='line' id='LC42'><br/></div><div class='line' id='LC43'><span class="k">class</span> <span class="nc">AcmeBicycle</span> <span class="o">&lt;</span> <span class="no">Bicycle</span></div><div class='line' id='LC44'><span class="k">end</span></div><div class='line' id='LC45'><br/></div><div class='line' id='LC46'><span class="n">bike</span> <span class="o">=</span> <span class="no">AcmeBicycle</span><span class="o">.</span><span class="n">new</span></div><div class='line' id='LC47'><span class="n">bike</span><span class="o">.</span><span class="n">change_gear</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># AbstractInterface::InterfaceNotImplementedError: AcmeBicycle needs to implement &#39;change_gear&#39; for interface Bicycle!</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/815110/86499cb60e04a53989d06d3763c44ff3d9a99984/gistfile1.rb" style="float:right;">view raw</a>
            <a href="https://gist.github.com/815110#file_gistfile1.rb" style="float:right;margin-right:10px;color:#666">gistfile1.rb</a>
            <a href="https://gist.github.com/815110">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>What we&#8217;ve done here is to inject a Module into our <code>Bicycle</code> class to give it a nice error it can raise and a little bit of help building a nice error message for the user. Then in our <code>Bicycle</code> class we define all the methods we want and in the ones we need the end user to define we can call the <code>api_not_implemented</code> method and it will raise the <code>AbstractInterface::InterfaceNotImplementedError</code> error for us.</p>
<p>We could simplify this a bit by having a nice little helper macro that we can use to build these methods, like this:</p>
<div id="gist-815133" class="gist">

        <div class="gist-file">
          <div class="gist-data gist-syntax">
              <div class="highlight"><pre><div class='line' id='LC1'><span class="k">module</span> <span class="nn">AbstractInterface</span></div><div class='line' id='LC2'>&nbsp;&nbsp;</div><div class='line' id='LC3'>&nbsp;&nbsp;<span class="k">class</span> <span class="nc">InterfaceNotImplementedError</span> <span class="o">&lt;</span> <span class="no">NoMethodError</span></div><div class='line' id='LC4'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC5'>&nbsp;&nbsp;</div><div class='line' id='LC6'>&nbsp;&nbsp;<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">included</span><span class="p">(</span><span class="n">klass</span><span class="p">)</span></div><div class='line' id='LC7'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">klass</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="ss">:include</span><span class="p">,</span> <span class="no">AbstractInterface</span><span class="o">::</span><span class="no">Methods</span><span class="p">)</span></div><div class='line' id='LC8'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">klass</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="ss">:extend</span><span class="p">,</span> <span class="no">AbstractInterface</span><span class="o">::</span><span class="no">Methods</span><span class="p">)</span></div><div class='line' id='LC9'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">klass</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="ss">:extend</span><span class="p">,</span> <span class="no">AbstractInterface</span><span class="o">::</span><span class="no">ClassMethods</span><span class="p">)</span></div><div class='line' id='LC10'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC11'>&nbsp;&nbsp;</div><div class='line' id='LC12'>&nbsp;&nbsp;<span class="k">module</span> <span class="nn">Methods</span></div><div class='line' id='LC13'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC14'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">def</span> <span class="nf">api_not_implemented</span><span class="p">(</span><span class="n">klass</span><span class="p">,</span> <span class="n">method_name</span> <span class="o">=</span> <span class="kp">nil</span><span class="p">)</span></div><div class='line' id='LC15'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">if</span> <span class="n">method_name</span><span class="o">.</span><span class="n">nil?</span></div><div class='line' id='LC16'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">caller</span><span class="o">.</span><span class="n">first</span><span class="o">.</span><span class="n">match</span><span class="p">(</span><span class="sr">/in \`(.+)\&#39;/</span><span class="p">)</span></div><div class='line' id='LC17'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">method_name</span> <span class="o">=</span> <span class="vg">$1</span></div><div class='line' id='LC18'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC19'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">raise</span> <span class="no">AbstractInterface</span><span class="o">::</span><span class="no">InterfaceNotImplementedError</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">&quot;</span><span class="si">#{</span><span class="n">klass</span><span class="o">.</span><span class="n">class</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2"> needs to implement &#39;</span><span class="si">#{</span><span class="n">method_name</span><span class="si">}</span><span class="s2">&#39; for interface </span><span class="si">#{</span><span class="nb">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">!&quot;</span><span class="p">)</span></div><div class='line' id='LC20'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC21'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC22'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC23'>&nbsp;&nbsp;</div><div class='line' id='LC24'>&nbsp;&nbsp;<span class="k">module</span> <span class="nn">ClassMethods</span></div><div class='line' id='LC25'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC26'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">def</span> <span class="nf">needs_implementation</span><span class="p">(</span><span class="nb">name</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span></div><div class='line' id='LC27'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">self</span><span class="o">.</span><span class="n">class_eval</span> <span class="k">do</span></div><div class='line' id='LC28'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">define_method</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span> <span class="k">do</span> <span class="o">|*</span><span class="n">args</span><span class="o">|</span></div><div class='line' id='LC29'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="no">Bicycle</span><span class="o">.</span><span class="n">api_not_implemented</span><span class="p">(</span><span class="nb">self</span><span class="p">,</span> <span class="nb">name</span><span class="p">)</span></div><div class='line' id='LC30'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC31'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC32'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC33'>&nbsp;&nbsp;&nbsp;&nbsp;</div><div class='line' id='LC34'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC35'>&nbsp;&nbsp;</div><div class='line' id='LC36'><span class="k">end</span></div><div class='line' id='LC37'><br/></div><div class='line' id='LC38'><span class="k">class</span> <span class="nc">Bicycle</span></div><div class='line' id='LC39'>&nbsp;&nbsp;<span class="kp">include</span> <span class="no">AbstractInterface</span></div><div class='line' id='LC40'>&nbsp;&nbsp;</div><div class='line' id='LC41'>&nbsp;&nbsp;<span class="n">needs_implementation</span> <span class="ss">:change_gear</span><span class="p">,</span> <span class="ss">:new_value</span></div><div class='line' id='LC42'>&nbsp;&nbsp;<span class="n">needs_implementation</span> <span class="ss">:speed_up</span><span class="p">,</span> <span class="ss">:increment</span></div><div class='line' id='LC43'>&nbsp;&nbsp;</div><div class='line' id='LC44'>&nbsp;&nbsp;<span class="c1"># Some documentation on the apply_brakes method</span></div><div class='line' id='LC45'>&nbsp;&nbsp;<span class="k">def</span> <span class="nf">apply_brakes</span><span class="p">(</span><span class="n">decrement</span><span class="p">)</span></div><div class='line' id='LC46'>&nbsp;&nbsp;&nbsp;&nbsp;<span class="c1"># do some work here</span></div><div class='line' id='LC47'>&nbsp;&nbsp;<span class="k">end</span></div><div class='line' id='LC48'>&nbsp;&nbsp;</div><div class='line' id='LC49'><span class="k">end</span></div><div class='line' id='LC50'><br/></div><div class='line' id='LC51'><span class="k">class</span> <span class="nc">AcmeBicycle</span> <span class="o">&lt;</span> <span class="no">Bicycle</span></div><div class='line' id='LC52'><span class="k">end</span></div><div class='line' id='LC53'><br/></div><div class='line' id='LC54'><span class="n">bike</span> <span class="o">=</span> <span class="no">AcmeBicycle</span><span class="o">.</span><span class="n">new</span></div><div class='line' id='LC55'><span class="n">bike</span><span class="o">.</span><span class="n">change_gear</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1"># AbstractInterface::InterfaceNotImplementedError: AcmeBicycle needs to implement &#39;change_gear&#39; for interface Bicycle!</span></div></pre></div>
          </div>

          <div class="gist-meta">
            <a href="https://gist.github.com/raw/815133/aacc6defab9cfa8801a042ab386daf27685e3981/gistfile1.rb" style="float:right;">view raw</a>
            <a href="https://gist.github.com/815133#file_gistfile1.rb" style="float:right;margin-right:10px;color:#666">gistfile1.rb</a>
            <a href="https://gist.github.com/815133">This Gist</a> brought to you by <a href="http://github.com">GitHub</a>.
          </div>
        </div>
</div>

<p>That approach certainly makes our code look a bit cleaner, I&#8217;m not denying that, however it has one really big flaw, at least for me anyway, it doesn&#8217;t give us a good to place to hang our documentation hat. In the previous approach we had actual methods that we could then document and that documentation would then show up in RDoc when it&#8217;s outputted. With the latter approach, however, we can document the hell out of the <code>needs_implementation</code> calls we have in the <code>Bicycle</code> class, but they won&#8217;t ever show up in the documentation. That means that users of our library have to crack open the actual code itself to see what it they are expected to implement.</p>
<p>Another approach we could&#8217;ve taken, which I bother to demonstrate here as I don&#8217;t think it offers a better approach is to have the <code>needs_implementation</code> method collect up the names of those methods and use <code>method_missing</code> to report that the method needs to be implemented. I mention it here only for completeness, but it definitely is not the best solution to this problem.</p>
<p>Finally, I would like to note that, as far as I can see, there is no way in Ruby to create a callback hook for when a class has been defined. If there was in fact such a hook we could use to it immediately notify the end user that they have forgotten to implement certain methods. Perhaps in Ruby 2.0??? That&#8217;s just pure hope on my part.</p>
<p>That&#8217;s it. I hope you enjoyed our brief (*cough*) look through implementing Interface and Abstract Classes in Ruby. I hope you&#8217;ve enjoyed it.</p>
<p>* PS, yes, I&#8217;m aware I didn&#8217;t talk about multiple vs. single inheritance in either Java or Ruby, nor did I talk about the fact that in Ruby you can&#8217;t really have Abstract Classes. I thought that was all a bit much for an already rather lengthy post as it was. Perhaps another day. <img src='http://www.metabates.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.metabates.com/2011/02/07/building-interfaces-and-abstract-classes-in-ruby/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Becoming an &#8216;Expert&#8217; Developer</title>
		<link>http://www.metabates.com/2010/11/17/becoming-an-expert-developer/</link>
		<comments>http://www.metabates.com/2010/11/17/becoming-an-expert-developer/#comments</comments>
		<pubDate>Wed, 17 Nov 2010 15:50:16 +0000</pubDate>
		<dc:creator>Mark Bates</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[developer]]></category>
		<category><![CDATA[github.com]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.metabates.com/?p=387</guid>
		<description><![CDATA[Last week I received an email from someone who used to work at a company that I used to work with. I didn&#8217;t know him, but he knew me through my work at the company, and my other exploits. He sent me an email to say that after a short time with the company he [...]]]></description>
			<content:encoded><![CDATA[<p>Last week I received an email from someone who used to work at a company that I used to work with. I didn&#8217;t know him, but he knew me through my work at the company, and my other exploits. He sent me an email to say that after a short time with the company he had been laid off, along with half of the development team. He wasn&#8217;t looking for pity, but rather advice.</p>
<p>What kind of advice was he asking for, well, he quite simply needed to know how could he become an &#8216;expert&#8217; Ruby on Rails developer. First, let me say that this post won&#8217;t have anything to do with Ruby, Rails, or any other specific programming language. Everything I&#8217;ll talk about is valid in ANY language on ANY platform. With that disclaimer, let&#8217;s move on, shall we?</p>
<p><img class="alignleft" title="Monkey" src="http://herd.typepad.com/.a/6a00d83451e1dc69e2010536ad3deb970b-800wi" alt="" width="250" /></p>
<p>While at this company he got introduced to Ruby on Rails and really loved it, coming from a non-Rails background. Since being laid off he&#8217;s been trying to land another Rails gig, but everyone is looking for &#8216;expert&#8217; Rails developers. So the question was, how to become an &#8216;expert&#8217; developer?</p>
<p>I keep putting &#8216;expert&#8217; in quotes because, let&#8217;s be honest here, that&#8217;s a VERY subjective term. As someone who has hired many developers in his day, I can tell you that I&#8217;v</p>
<p>e hired newbies to &#8216;experts&#8217; and everywhere in between. Everyone has their merits and possibilities. I&#8217;ve met &#8216;experts&#8217; that I wouldn&#8217;t hire to take out my trash, let alone build my business. I&#8217;ve also met people right out of college that I would hire again and again. So your mileage my vary.</p>
<p>So&#8230; how do you build up that &#8216;expert&#8217; reputation? Let&#8217;s look at it. Below are some of things I&#8217;ve done, as well as some of the things that I look for as a hiring manager. Some are incredibly easy to do, others require work, but in the end they WILL pay off, and you&#8217;ll easily be at the head of the pack when going for that job.</p>
<h3>Build Something</h3>
<p>When you are looking for a job people want to see what it is you&#8217;ve actually built. If you haven&#8217;t built anything, then how are you an expert? Build a lot of different things and put them up on the web for perspective employers to find and play around with. Use these are a playground for trying out all those cool new technologies you keep hearing about. Want to give NoSQL a try? Great, build an app that uses it. Need to improve your testing chops? Write an application and write all the tests you can possibly think of!</p>
<h3>Get a GitHub Account</h3>
<p>I can&#8217;t tell you how important GitHub has become when trying to make a name for yourself. It seems like unless you&#8217;re on GitHub, you&#8217;re nobody. While that might not be true, it certainly hurts more than it helps to not have an account. You know those apps you&#8217;ve just been building and playing around with? Post them on GitHub! Then put your profile page link on your resume. Yep, you read that right. Give those looking at your resume a link to your code. Let them see how good a developer you actually are. Show them you know how to code all the things you&#8217;ve got on your resume. Listing a language, platform, or tool on resume is one thing, but actually showing your perspective employer is another! They&#8217;ll love it.</p>
<p>While you&#8217;re on GitHub, why not contribute to an open source project that&#8217;s up there. There are plenty of them, and they&#8217;re ALL looking for people to help out with their projects. Simply fork the projects, make some improvements, and then give those changes back to the projects owner. This looks great on a resume and really helps to show that you are interested and active in the community. Again, employers love this! Plus, you&#8217;ll be starting to build a name for yourself, and building a network, and a network is INCREDIBLY important when looking for work.</p>
<h3>Blog and Write</h3>
<p>I should probably heed my own advice here and blog more often, but do as I say, not as I do. <img src='http://www.metabates.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  With that said I wrote a book, which looks AMAZING on a resume, but might be a bit out of reach for most people, so I recommend blogging instead. Why should you blog? Well, it shows that you have good communications skills, again very important to most employers. It can also show that you have a deep understanding of whatever it is you blog about.</p>
<p>What should you write about? If you&#8217;re stuck on a topic, might I make a recommendation or two. First, when you&#8217;re building those applications I mentioned early if you run into a bug or something else that got you a bit stuck, blog about it! Others could really benefit from your experience. Explain the problem and how you went about solving it. Another great thing to write about is your favorite libraries or plugins. Pick a different one each week and dissect it. Write about how it works, what it does, etc&#8230; This is a great exercise in both writing and learning about how things work. Very valuable.</p>
<h3>Network</h3>
<p>I mentioned earlier that a good network is INCREDIBLY important when looking for work, and I wasn&#8217;t lying. It&#8217;s the most important thing. A good network will constantly be feeding you new opportunities, or putting you in touch with those who can. So how do you develop that network? A few ways, I mentioned contributing to open source earlier, that&#8217;s a great way. Another great way is through conferences, hackfests, rumbles, and whatever other local (and non-local) events are being held in your development community of choice. Attend these events, participate, introduce yourself, speak, buy drinks, whatever! Just get out there and NETWORK!!</p>
<h3>Conclusion</h3>
<p>The gentleman who emailed me said that he was reading a lot of books in hopes of becoming an &#8216;expert&#8217;. While I&#8217;m not going to tell you not to read books (you should!!), I will tell you that there is no substitute for doing. All of things I&#8217;ve talked about above are ALL about doing. Reading is not doing, it&#8217;s reading. It&#8217;s passive and will not get you further in your career. There&#8217;s no place on a resume for the books you&#8217;ve read. Take what you&#8217;ve read and put it into action, then you&#8217;ll be on your way to becoming an &#8216;expert&#8217; developer.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.metabates.com/2010/11/17/becoming-an-expert-developer/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to Become a Test-driven Developer</title>
		<link>http://www.metabates.com/2010/10/12/how-to-become-a-test-driven-developer/</link>
		<comments>http://www.metabates.com/2010/10/12/how-to-become-a-test-driven-developer/#comments</comments>
		<pubDate>Tue, 12 Oct 2010 16:31:01 +0000</pubDate>
		<dc:creator>Mark Bates</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[bdd]]></category>
		<category><![CDATA[rspec]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[tdd]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[tests]]></category>

		<guid isPermaLink="false">http://www.metabates.com/?p=367</guid>
		<description><![CDATA[In a previous post, Testing Is Not An Option, I talked a lot about why you should write tests, and the arguments you can put forth to your client, manager, or whoever it may be as to why you should write tests. What I didn&#8217;t talk about was how to start writing tests. So let&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p>In a previous post, <a href="http://www.metabates.com/2010/07/01/testing-is-not-an-option/" target="_blank">Testing Is Not An Option</a>, I talked a lot about why you should write tests, and the arguments you can put forth to your client, manager, or whoever it may be as to why you should write tests. What I didn&#8217;t talk about was how to start writing tests. So let&#8217;s talk about that for a bit, shall we?</p>
<p>When I&#8217;m talking with a potential client, well at least a client that has an existing code base, I always ask what their code coverage stats are. Now, I know at code coverage stats aren&#8217;t the be all end all of measuring how good your tests are, but they&#8217;re a basic enough metric to use as a guide. If they say they&#8217;re high, then I usually dig in more about how they&#8217;re testing; what frameworks, BDD, TDD, that sort of thing. Usually though I get a few minutes where they apologize and sheepishly give me their reasons for having little or no tests.</p>
<p>Here are few of those reasons:</p>
<ul>
<li>We don&#8217;t/didn&#8217;t have the time.</li>
<li>We don&#8217;t know how.</li>
<li>It was/is too complicated.</li>
<li>It was/is too overwhelming.</li>
</ul>
<p>Let&#8217;s talk about each of this points for a minute.</p>
<h3>&#8220;We don&#8217;t/didn&#8217;t have the time.&#8221;</h3>
<h3><span style="font-weight: normal; font-size: 13px;">I never accept time as an argument against testing. Testing ends up repaying it&#8217;s time investment, and will ultimately give you more time than if you didn&#8217;t write code. It&#8217;s a win-win. Again see my previous post in how to get the time signed off on as part of t he project timeline.</span></h3>
<h3>&#8220;We don&#8217;t know how.&#8221;</h3>
<p>Learn. There&#8217;s no better time than the present and no better way to learn than being thrown into the deep end. The web is crawling with documentation, screen casts, how to articles and tutorials, and there are plenty of books to get you going. In short the k knowledge is literally at your finger tips, and to be honest it&#8217;s easier than you think.</p>
<h3>&#8220;It was/is too complicated.&#8221;</h3>
<p>That usually means you&#8217;re doing it wrong. Take a step back and assess what it is you&#8217;re trying to do. You&#8217;re tests should be simple and concise. Don&#8217;t write tests that are hundreds of lines long. They&#8217;re tests, not entrance exams to MIT.</p>
<h3>&#8220;It was/is too overwhelming.&#8221;</h3>
<p>Certainly if you didn&#8217;t write tests as you went along it can get quite overwhelming thinking about all the tests you now need to write for your monolithic app. I&#8217;ll talk about how you can solve that problem in a minute.</p>
<h2>Making It Happen</h2>
<p>Ok, so now that we&#8217;ve identified a few of the excuses let&#8217;s talk about how you can starting writing tests today for your application. So, take a deep breath and let&#8217;s begin.</p>
<p>If you&#8217;re staring at an existing application, don&#8217;t try to tackle it all at once, you&#8217;ll just get overwhelmed, scared, and confused. Instead take it one file/class at a time. First start with your models, as this is where the majority of your application business logic should be. Alphabetically each day pick the next class (or a couple of them) in the list and start to fill our your test files.</p>
<p>What do I mean by fill out your tests files, I mean creating pending tests for each of the methods of your model. Here&#8217;s an example of a basic Ruby* class and what the pending RSpec spec file would look like:</p>
<pre><code># Class: class Entity def tax_id if self.person? # code here else # code here end end def person? # code here end end # Spec: describe Entity do describe "tax_id" do it "should return a Social Security number if the entity is a Person" do pending end it "should return a Tax ID number if the entity is a Corporation" do pending end end describe "person?" do it "should return true if the entity is a person" do pending end it "should return false if the entity is not a person" do pending end end end</code></pre>
<p>Notice how the method that has the if/else statement in it has two pending tests for it. We need to test each variation of the method.</p>
<p>Now when you run your tests you&#8217;ll see that you have a bunch of pending tests. Great! Now you just need to fill them in, but at least you know what should be filled in.</p>
<p>I also recommend that you do this every time you create a new method. As soon as you give your method a name go to your corresponding test and create a pending test for that method. This way you know that you have to test that method later. (In a perfect world I would love to see you write your test before returning to your class to fill in the method itself, but baby steps for now.)</p>
<p>Once you have all your pending tests setup each day try to fill in the details of each pending test for a whole class. If that&#8217;s too much, then try to set aside an hour a day and fill in as many pending tests as you can. Alternatively you can also fill in the tests during the course of the day as you use one of the methods without tests.</p>
<p>Another great way to start filling in your test suite is each time you get a new bug, write a test to reproduce it. This is a great habit to get into as you&#8217;ll eventually have a great suite of regression tests in place to help prevent those nasty bugs from returning. Write the test, see that it fails, then fix your bug. When your teat passes then you know you&#8217;ve fixed the bug!</p>
<p>Finally, start small. Start by writing unit tests. These are the types of tests I just described. They test a very particular part of your code base to ensure that it does what it should do. These tests are typically easy to write and act as a great corner stone to your test suite as a whole. Don&#8217;t try to jump right in with full integration tests. The frameworks typically have a steep learning curve, and are more complicated to get up and running. This will lead to frustration and the old feeling of being overwhelmed. You can add these tests in later as you gain experience.</p>
<p>Well, there you have it, a few simple tricks to help you get started testing today. I know this post was a bit on the lengthy side, but I&#8217;m glad you stuck with me. Your life will be better for it. When you have a large and expansive test suite life is just better. Food tastes better. The sky is bluer. There will be a skip in your step. And you can use your incredibly high code coverage stats as a pick up line in a bar. On second thought, scratch that last thought. I wrote a test to see if that would work and it failed. It failed miserably.</p>
<h6>* Please not that while I use Ruby as the example language here, the concept applies to whatever language you use.</h6>
]]></content:encoded>
			<wfw:commentRss>http://www.metabates.com/2010/10/12/how-to-become-a-test-driven-developer/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CoverMe – Code Coverage for Ruby 1.9 Reaches RC1</title>
		<link>http://www.metabates.com/2010/09/30/coverme-%e2%80%93-code-coverage-for-ruby-1-9-reaches-rc1/</link>
		<comments>http://www.metabates.com/2010/09/30/coverme-%e2%80%93-code-coverage-for-ruby-1-9-reaches-rc1/#comments</comments>
		<pubDate>Thu, 30 Sep 2010 16:09:25 +0000</pubDate>
		<dc:creator>Mark Bates</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Releases]]></category>
		<category><![CDATA[Updates]]></category>
		<category><![CDATA[cover_me]]></category>
		<category><![CDATA[gem]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rcov]]></category>
		<category><![CDATA[release]]></category>
		<category><![CDATA[rspec]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[tests]]></category>

		<guid isPermaLink="false">http://www.metabates.com/?p=363</guid>
		<description><![CDATA[In August I announced CoverMe a code coverage tool for Ruby 1.9. Well, today I announce that it has hit it&#8217;s first release candidate! I&#8217;ve very excited by the fact it&#8217;s getting close to an &#8216;official&#8217; release. The response to CoverMe has been great and through feedback from the community I&#8217;ve made a lot of [...]]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://www.metabates.com/2010/08/13/coverme-code-coverage-for-ruby-1-9/">August</a> I announced <a href="http://github.com/markbates/cover_me" target="_blank">CoverMe</a> a code coverage tool for Ruby 1.9. Well, today I announce that it has hit it&#8217;s first release candidate! I&#8217;ve very excited by the fact it&#8217;s getting close to an &#8216;official&#8217; release.</p>
<p>The response to CoverMe has been great and through feedback from the community I&#8217;ve made a lot of improvements and fixed a lot of issues.</p>
<p>While quite a few things have changed under the hood, not much has changed in how you use CoverMe.</p>
<h2>Installation</h2>
<p>The following are instructions for how you would configure CoverMe for a Rails 3 project, adjust to your local environment accordingly.</p>
<p>In  your Gemfile add the following:</p>
<pre>gem 'cover_me', '&gt;= 1.0.0.rc1', :group =&gt; :test</pre>
<p>Then run:</p>
<pre>$ bundle install</pre>
<p>After CoverMe is installed place the following line at the <strong><em>VERY TOP</em></strong> of your &#8216;test_helper.rb&#8217; or &#8216;spec_helper.rb&#8217; file (for Cucumber put it at the top of the &#8216;env.rb&#8217; file):</p>
<pre>require 'cover_me'</pre>
<p>I can&#8217;t emphasize enough how important it is that the require statement is at the <strong><em>VERY</em></strong> top of that file!</p>
<p>Finally (and optionally) run:</p>
<pre>$ rails g cover_me:install</pre>
<p>This will simply install a Rake task that will wrap both Test::Unit and RSpec tasks with CoverMe and will launch the results at the end of the test suites. I would recommend it. It&#8217;s kinda the whole point. <img src='http://www.metabates.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h2>That&#8217;s it!</h2>
<p>Enjoy the release candidate, and of course, please let me know if you find any issues with it. Issues can be reported on <a href="http://github.com/markbates/cover_me/issues" target="_blank">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.metabates.com/2010/09/30/coverme-%e2%80%93-code-coverage-for-ruby-1-9-reaches-rc1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

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

