<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/atom10full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en-US">
  <title>opensoul.org - Code</title>
  <id>tag:opensoul.org,2009:mephisto/code</id>
  <generator uri="http://mephistoblog.com" version="0.8.0">Mephisto Drax</generator>
  
  <link href="http://opensoul.org/code" rel="alternate" type="text/html" />
  <updated>2008-12-21T20:08:52Z</updated>
  <link rel="self" href="http://feeds.feedburner.com/opensoul/code" type="application/atom+xml" /><feedburner:browserFriendly></feedburner:browserFriendly><entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-12-21:10034</id>
    <published>2008-12-21T19:32:00Z</published>
    <updated>2008-12-21T20:08:52Z</updated>
    <category term="Code" />
    <category term="Life" />
    <category term="offshoring" />
    <category term="outsourcing" />
    <category term="rails" />
    <link href="http://opensoul.org/2008/12/21/outsourcing-vs-offshoring" rel="alternate" type="text/html" />
    <title>Outsourcing vs. Offshoring</title>
<content type="html">
            &lt;p&gt;My experience is that most people think of “outsourcing” and “offshoring” as synonyms.  We talk about the general category of outsourcing with slight repugnance, acknowledging that it is occasionally useful for more mundane and unskilled tasks, but it simply won’t work for the more creative tasks that require an American to do it well. (Maybe nobody blatantly says it requires an American, but we know what you’re implying.)&lt;/p&gt;


	&lt;p&gt;I don’t intend to address the “Americans are better at creative work” myth, but I will say this: my hypothesis is that any perceived difference in the quality of outsourced work has more to do with the size of the team, access to the stakeholders and end-user, and the ownership and responsibility felt by the people doing the work than it does their nationality, all factors which can also affect an internal team. But I have no experience with offshoring, so I can’t speak to that.&lt;/p&gt;


	&lt;p&gt;Instead, I want to clarify that &lt;em&gt;offshoring&lt;/em&gt; is but one category of &lt;em&gt;outsourcing&lt;/em&gt;.&lt;/p&gt;


	&lt;h3&gt;You may not call it “outsourcing”, but you do it all the time&lt;/h3&gt;


	&lt;p&gt;“Outsourcing” simply means paying someone else do work that you could do, usually because they can do it cheaper, better or faster, or any combination of those. We all outsource all of the time. As cofounder of Keepers Household, Inc., I could have our maintenance staff–a position currently held by yours truely–take the time to figure out why the washing machine sometimes doesn’t spin, but not only do I have no interest in this task, I can pay someone else that can diagnose the problem quicker and probably fix it better than I can. I’m exchanging a little money for a working washing machine and a few hours back to do what I’m good at and enjoy&lt;sup&gt;&lt;a href="#honeydo"&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;


	&lt;p&gt;In nearly three years of doing web application development at &lt;a href="http://collectiveidea.com"&gt;Collective Idea&lt;/a&gt;, I can only think of one or two small projects where we didn’t “outsource” parts of the project. On every other project, we’ve worked in conjunction with one or more companies or individuals on various aspects.&lt;/p&gt;


	&lt;h3&gt;It’s not just about getting it cheaper&lt;/h3&gt;


	&lt;p&gt;Design, for example, is an area that we often outsource. We believe strongly in the importance of good interface design, and doing it as &lt;a href="/2006/6/26/user-interface-first"&gt;early as possible&lt;/a&gt; in the project. We &lt;em&gt;can&lt;/em&gt; do design ourselves (or at least pretend to), but it is extremely inefficient for us. It is not a core competency, nor is it an area where we have a real competitive advantage.&lt;/p&gt;


	&lt;p&gt;So we have two options: hire someone that is good and efficient at design, or outsource it. Most companies choose to hire someone, assuming that they will get a better value and the direct access to the designer will yield quicker and higher quality results.&lt;/p&gt;


	&lt;p&gt;Instead, we outsource it to one of the designers that we know, and not only is the result much better than we could have managed, it is much cheaper. The result is better because we get to work with better designers—people that we couldn’t afford to employ—and they bring with them the experience of all the other projects that they’ve worked on, successes and failures. While the may bill us at a much higher rate than we could have done it ourselves, in the end, it’s still a better value because they make fewer mistakes and are more efficient.&lt;/p&gt;


	&lt;p&gt;But ultimately, it’s not about getting design done cheaper, it’s about getting it done better. Cheaper just happens to be a nice side effect.  We outsource design because we can’t afford to not do it well, so we want the most creative people we can find.&lt;/p&gt;


	&lt;h3&gt;Not just the mundane&lt;/h3&gt;


	&lt;p&gt;On one end of the spectrum of work is the repetitive, dull tasks that anybody can do. And on the other end is the highly creative or skilled work that only a handful of people can do. I disagree with the notion that only the mundane and uncreative tasks are the candidates for outsourcing. The closer the work is to either edge of that spectrum, the more it could benefit from outsourcing.&lt;/p&gt;


&lt;div class="figure"&gt;&lt;img src="http://opensoul.org/assets/2008/12/21/work-spectrum.png" alt="spectrum of mundane to creative work" /&gt;&lt;/div&gt;

	&lt;p&gt;Besides design, we’ve also outsourced things that require very specialized knowledge or skills.  Occasionally we have interest and can afford to pursue those areas ourselves, but usually it’s more cost-effective and productive to bring in someone that already has experience, for the same reasons we outsource design.&lt;/p&gt;


	&lt;p&gt;This post is partly inspired by &lt;a href="http://blog.awarelabs.com/?p=80"&gt;Outsourcing Killed By Django And Ruby On Rails&lt;/a&gt;, which argues that the Django and Rails web frameworks have allowed us to compete with the big guns because the frameworks eliminate the 80% of mundane tasks that would otherwise be offshored, allowing us to focus on the creative aspects.&lt;/p&gt;


	&lt;p&gt;While I agree with their argument that these frameworks eliminate the mundane tasks and allow us to be more efficient, I would argue that more efficiency comes from other factors which have more to do with the culture around these frameworks, such as smaller team sizes, open communication and releasing early which forces you to focus on core features needed by existing users instead of what potential users &lt;em&gt;might&lt;/em&gt; want. But I digress…&lt;/p&gt;


	&lt;p&gt;More importantly, I disagree with their premise that these frameworks have killed outsourcing. From my perspective, they have done exactly the opposite, and it is the ability of small specialized teams to outsource that gives them an even greater edge on the corporate competition.&lt;/p&gt;


	&lt;p&gt;If frameworks like Django and Rails are killing anything, I would hope that it is the culture of corporate software manufacturing, or the idea that we can just put more cheap labor on the software assembly line and get better results.&lt;/p&gt;


&lt;ol class="footnotes"&gt;
  &lt;li&gt;I’m writing this right now when I should be fixing the washing machine, but I’ve promised my cofounder/business partner that I’ll call someone to fix it.&lt;/li&gt;
&lt;/ol&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-12-13:9897</id>
    <published>2008-12-13T16:15:00Z</published>
    <updated>2008-12-13T16:16:56Z</updated>
    <category term="Code" />
    <category term="gem" />
    <category term="graticule" />
    <category term="mapquest" />
    <category term="ruby" />
    <link href="http://opensoul.org/2008/12/13/graticule-and-mapquest" rel="alternate" type="text/html" />
    <title>Graticule and MapQuest?</title>
<content type="html">
            &lt;p&gt;MapQuest has sent out several emails about their current geocoding &lt;span class="caps"&gt;API&lt;/span&gt; being discontinued. Here is the latest:&lt;/p&gt;


&lt;blockquote&gt;
Dear MapQuest Platform Customer,

	&lt;p&gt;At the start of the New Year, MapQuest will be retiring the MapQuest OpenAPI product, having launched the more feature rich MapQuest Platform: Free Edition product. Since the MapQuest OpenAPI does not use the same backend as our newer APIs, nor does it provide the breadth in functionality, we want to provide you with a better free experience.  Don’t wait – make the switch today!&lt;/p&gt;


	&lt;p&gt;If your application is currently being powered by the MapQuest OpenAPI product, you will need to migrate to one of 6 APIs available in the MapQuest Platform: Free Edition product prior to January 31, 2009.&lt;/p&gt;


	&lt;p&gt;Our MapQuest Platform: Free Edition product offers more flexibility and ease of development along with providing developer choice with six APIs:&lt;/p&gt;


	&lt;p&gt;&lt;span class="caps"&gt;SERVER SIDE&lt;/span&gt; APIs
 Java
 C++
 .NET&lt;/p&gt;


	&lt;p&gt;&lt;span class="caps"&gt;CLIENT SIDE&lt;/span&gt; APIs
 JavaScript
 AS3 (ActionScript 3: Flash, Flex, &lt;span class="caps"&gt;AIR&lt;/span&gt;)
 FUJAX (Write JavaScript, output Flash)&lt;/p&gt;


Our MapQuest Platform: Free Edition product includes many additional features including:
	&lt;ul&gt;
	&lt;li&gt;&lt;span class="caps"&gt;COLLECTIONS&lt;/span&gt;: Support for multiple and remote collections (KML and GeoRSS); allowing easier handling of shape collections.&lt;/li&gt;
		&lt;li&gt;&lt;span class="caps"&gt;ADVANCED SHAPE OVERLAYS&lt;/span&gt;: Build applications that allow users to create and interact with a variety of overlays on maps, including custom lines, polygons, rectangles, and ellipses.&lt;/li&gt;
		&lt;li&gt;&lt;span class="caps"&gt;CUSTOM TILE LAYER SUPPORT&lt;/span&gt;.&lt;/li&gt;
		&lt;li&gt;Add &lt;span class="caps"&gt;REAL&lt;/span&gt;-TIME &lt;span class="caps"&gt;TRAFFIC&lt;/span&gt; to your map.&lt;/li&gt;
		&lt;li&gt;&lt;span class="caps"&gt;GLOBE VIEW&lt;/span&gt;: http://globe.mapquest.com.&lt;/li&gt;
		&lt;li&gt;&lt;span class="caps"&gt;AERIAL IMAGERY&lt;/span&gt; and &lt;span class="caps"&gt;HYBRID VIEWS&lt;/span&gt;.&lt;/li&gt;
		&lt;li&gt;&lt;span class="caps"&gt;SMART ROLLOVERS&lt;/span&gt;: Rollover windows that adapt their size and positioning based on the content placed in the window.&lt;/li&gt;
		&lt;li&gt;&lt;span class="caps"&gt;ADVANCED MAP MARKERS&lt;/span&gt;: With the MapQuest “declutter mode,” automatically move collided markers to positions on the map with a leader link pointing to their original location.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;The MapQuest OpenAPI product servers will go offline on Saturday, January 31st, 2009. Please plan on migrating your application before this date or applications based on the MapQuest OpenAPI product will stop working.&lt;/p&gt;


	&lt;p&gt;You can find documentation and downloads for the MapQuest Platform: Free Edition product on our Developer Network: http://developer.mapquest.com.&lt;/p&gt;


	&lt;p&gt;Additional information can be found on: 
http://platform.mapquest.com &amp; http://devblog.mapquest.com.&lt;/p&gt;


	&lt;p&gt;Thank you,&lt;/p&gt;


MapQuest, Inc.
&lt;/blockquote&gt;

	&lt;p&gt;&lt;a href="http://github.com/collectiveidea/graticule"&gt;Graticule&lt;/a&gt;, a ruby wrapper around many popular geocoding APIs, uses the old MapQuest &lt;span class="caps"&gt;API&lt;/span&gt;. I don’t use it, and I don’t know if anyone else does, so I’m leaving it to you, lazyweb:  If you use the MapQuest &lt;span class="caps"&gt;API&lt;/span&gt;, or want to in the future, fork &lt;a href="http://github.com/collectiveidea/graticule"&gt;graticule  on GitHub&lt;/a&gt; and update the MapQuest wrapper.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-12-04:9829</id>
    <published>2008-12-04T23:33:00Z</published>
    <updated>2008-12-04T23:34:43Z</updated>
    <category term="Code" />
    <category term="facebook" />
    <category term="rails" />
    <category term="rspec" />
    <link href="http://opensoul.org/2008/12/4/testing-views-in-rspec-with-namespaced-elements" rel="alternate" type="text/html" />
    <title>Testing views in RSpec with namespaced elements</title>
<content type="html">
            &lt;p&gt;We’ve been working on a Facebook app (yeah, I know, I’m sorry) and have had all kinds of fun challenges. We wanted to test &lt;a href="http://wiki.developers.facebook.com/index.php/FBML"&gt;&lt;acronym title="Facebook Markup Language"&gt;&lt;span class="caps"&gt;FBML&lt;/span&gt;&lt;/acronym&gt; tags&lt;/a&gt; in the view, but the problem is that &lt;span class="caps"&gt;FBML&lt;/span&gt; uses namespaced elements.&lt;/p&gt;


	&lt;p&gt;It turns out, &lt;span class="caps"&gt;CSS&lt;/span&gt; selectors don’t work with namespaced elements.  There is a &lt;a href="http://www.w3.org/TR/css3-namespace/"&gt;&lt;span class="caps"&gt;CSS3&lt;/span&gt; namespace module&lt;/a&gt;, but Rails’ &lt;a href="http://api.rubyonrails.org/classes/ActionController/Assertions/SelectorAssertions.html#M000397"&gt;#assert_select&lt;/a&gt; and RSpec’s &lt;a href="http://rspec.rubyforge.org/rspec-rails/1.1.11/classes/Spec/Rails/Matchers.html#M000069"&gt;#have_tag&lt;/a&gt; (built on &lt;code&gt;#assert_select&lt;/code&gt;) don’t support them. We were going to have to turn to XPath, but &lt;code&gt;#have_tag&lt;/code&gt; only supports &lt;span class="caps"&gt;CSS&lt;/span&gt; selectors.&lt;/p&gt;


	&lt;p&gt;But &lt;a href="http://code.whytheluckystiff.net/hpricot/"&gt;Hpricot&lt;/a&gt; supports XPath.  A little searching revealed the &lt;a href="http://github.com/pd/rspec_hpricot_matchers"&gt;rspec_hpricot_matchers plugin&lt;/a&gt;, which replaces have_tag with an Hpricot-backed version.  The only problem is that the new version isn’t backwards compatible.  So we &lt;a href="http://github.com/collectiveidea/rspec_hpricot_matchers"&gt;forked it&lt;/a&gt; and renamed &lt;code&gt;#have_tag&lt;/code&gt; to &lt;code&gt;#match_element&lt;/code&gt;.&lt;/p&gt;


	&lt;h3&gt;Usage&lt;/h3&gt;


	&lt;p&gt;It’s pretty straight forward.  Install the &lt;a href="http://github.com/collectiveidea/rspec_hpricot_matchers"&gt;rspec_hpricot_matchers&lt;/a&gt; plugin, and include the module in the RSpec config in &lt;code&gt;spec_helper.rb&lt;/code&gt;.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;Spec::Runner.configure do |config|
  config.include RspecHpricotMatchers
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Our view had something similar to:&lt;/p&gt;


&lt;pre&gt;&lt;code class="erb"&gt;&amp;lt;fb:multi-friend-input prefill_ids=&amp;quot;&amp;lt;%= @friends.join(', ') %&amp;gt;&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And in the view spec, we use #match_element with an XPath expression.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;describe &amp;quot;things/edit.fbml.erb&amp;quot; do
  it &amp;quot;should prefill selected friends&amp;quot; do
    render &amp;quot;things/edit.fbml.erb&amp;quot;
    response.should match_element(&amp;quot;//fb:multi-friend-input[@prefill_ids='333,444,555']&amp;quot;)
  end
end&lt;/code&gt;&lt;/pre&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-11-17:9556</id>
    <published>2008-11-17T06:32:00Z</published>
    <updated>2008-11-17T12:14:25Z</updated>
    <category term="Code" />
    <category term="awesome_nested_set" />
    <category term="collectiveidea" />
    <category term="plugin" />
    <category term="rails" />
    <link href="http://opensoul.org/2008/11/17/making-nested-sets-cool" rel="alternate" type="text/html" />
    <title>awesome_nested_set: making nested sets cool</title>
<content type="html">
            &lt;p&gt;Yes, I’m making the assertion that preordered &lt;a href="http://en.wikipedia.org/wiki/Tree_traversal"&gt;tree traversal&lt;/a&gt; is now cool. And I don’t mean just “pocket protector” cool, because it’s always been that, but now it’s “show your friends” cool.&lt;/p&gt;


	&lt;p&gt;For those that have no idea what I’m talking about, and don’t really care, but still want to be cool, skip to the next section. For all three of you that want to understand all the gory details, check out this &lt;a href="http://dev.mysql.com/tech-resources/articles/hierarchical-data.html"&gt;MySQL DevZone article on managing hierarchical data&lt;/a&gt;.&lt;/p&gt;


	&lt;h3&gt;What are you talking about?&lt;/h3&gt;


	&lt;p&gt;I’m talking about putting hierarchical data into a relational database, and a plugin to make that easier. There are lots of reasons for trying to do this: organizational structures, genealogies, &lt;a href="http://en.wikipedia.org/wiki/Taxonomy"&gt;taxonomies&lt;/a&gt;, nested pages of a website, etc. It’s kinda like putting a square peg into a round hole, except that the square peg is made out of &lt;a href="http://weblog.jamisbuck.org/2008/11/9/legos-play-doh-and-programming"&gt;Play-Doh&lt;/a&gt;, so we can force it through the hole anyway, and we just have a little extra mess to deal with.&lt;/p&gt;


	&lt;p&gt;There were several Active Record plugins out there that tried to clean up the mess, but they were either buggy or incomplete.&lt;/p&gt;


	&lt;p&gt;We created &lt;a href="http://github.com/collectiveidea/awesome_nested_set"&gt;awesome_nested_set&lt;/a&gt; to try to remedy that.&lt;/p&gt;


	&lt;h3&gt;What makes this so awesome?&lt;/h3&gt;


	&lt;p&gt;There’s a lot of things that makes this awesome, but my personal favorite is that awesome_nested_set makes use of Rails 2.1’s named_scope features&lt;sup&gt;&lt;a href="#named_scope_backport"&gt;1&lt;/a&gt;&lt;/sup&gt;, so most of the nested set methods return a scope that works as a finder. You can call find methods on it or access other named scopes.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;class Department &amp;lt; ActiveRecord::Base
  acts_as_nested_set
  named_scope :in_need_of_review, :lambda =&amp;gt; {{
    :conditions =&amp;gt; {:reviewed_at &amp;gt; 1.year.ago
  }}
end

chancellor = Department.create(:name =&amp;gt; 'Chancellor')
aa = Department.create(:name =&amp;gt; 'Academic Affairs').move_to_child_of(chancellor)
Department.create(:name =&amp;gt; 'Admissions').move_to_child_of aa
Department.create(:name =&amp;gt; 'Student Services',
  :reviewed_at =&amp;gt; 3.months.ago).move_to_child_of aa

chancellor.descendants.in_need_of_review
rogue = chancellor.descendants.all(:conditions =&amp;gt; 'manager_id IS NULL')&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;There’s lots more info in the &lt;a href="http://github.com/collectiveidea/awesome_nested_set"&gt;&lt;span class="caps"&gt;README&lt;/span&gt; on GitHub&lt;/a&gt;, so check it out.  Let us know if you have any suggestions or feedback.&lt;/p&gt;


&lt;ol class="footnotes"&gt;
  &lt;li&gt;It also backports named_scope for those still on Rails 2.0&lt;/li&gt;
&lt;/ol&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-11-13:9492</id>
    <published>2008-11-13T16:43:00Z</published>
    <updated>2008-11-13T16:49:42Z</updated>
    <category term="Code" />
    <category term="capistrano" />
    <category term="deployment" />
    <category term="git" />
    <category term="rails" />
    <link href="http://opensoul.org/2008/11/13/capistrano-2-5-and-old-versions-of-git" rel="alternate" type="text/html" />
    <title>Capistrano 2.5 and older versions of git</title>
<content type="html">
            &lt;p&gt;Git support in &lt;a href="http://capify.org"&gt;Capistrano&lt;/a&gt; 2.5 got a little lovin’, but as a result, it may have broke your deploys.  By default, Capistrano now uses the &lt;code&gt;-q&lt;/code&gt; flag to tell git to not be so chatty.  But older versions of git (1.4.x and maybe some early 1.5.x versions) don’t support the &lt;code&gt;-q&lt;/code&gt; flag.  If upgrading git isn’t an option, the solution is simple.  Just tell Capistrano to take the muzzle off of git:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;set :scm_verbose, true&lt;/code&gt;&lt;/pre&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-11-12:9479</id>
    <published>2008-11-12T17:32:00Z</published>
    <updated>2008-11-12T17:42:26Z</updated>
    <category term="Code" />
    <category term="collectiveidea" />
    <category term="rails" />
    <category term="training" />
    <link href="http://opensoul.org/2008/11/12/rails-training-january-20-23-san-antonio-tx" rel="alternate" type="text/html" />
    <title>Rails Training: January 20–23 in San Antonio, TX</title>
<content type="html">
            &lt;div class="figure"&gt;&lt;img src="http://opensoul.org/assets/2008/11/12/venue_san_antonio.jpg" alt="San Antonio, Texas" /&gt;&lt;/div&gt;

	&lt;p&gt;&lt;a href="http://collectiveidea.com"&gt;We’ve&lt;/a&gt; been
providing highly-praised Ruby on Rails training all over the world,
and now we’re bringing it to &lt;strong&gt;San Antonio, Texas&lt;/strong&gt;. We will be offering hands-on
&lt;a href="http://training.collectiveidea.com/ruby-on-rails"&gt;Ruby on Rails training in downtown San Antonio on &lt;strong&gt;January 20-23, 2009&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;I’ve never been to San Antonio, so I’m really exited for this class. Any recommendations for things to check out?&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-11-10:9450</id>
    <published>2008-11-10T03:07:00Z</published>
    <updated>2008-11-11T16:28:00Z</updated>
    <category term="Code" />
    <category term="rspec" />
    <category term="ruby" />
    <link href="http://opensoul.org/2008/11/10/making-rspec-concise" rel="alternate" type="text/html" />
    <title>Making RSpec concise</title>
<content type="html">
            &lt;p&gt;A common criticism of &lt;a href="http://rspec.info"&gt;RSpec&lt;/a&gt; is that it is very verbose. I don’t necessarily agree (or care), but I thought it would be fun to see how concise I could make my specs.&lt;/p&gt;


	&lt;p&gt;Here are some simple specs from a client project:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;describe Company do
  before do
    @company = Company.new
  end

  it &amp;quot;should have many classifications&amp;quot; do
    @company.should have_many(:classifications)
  end

  it &amp;quot;should have many industries through companies&amp;quot; do
    @company.should have_many(:industries, :through =&amp;gt; :classifications)
  end

  it &amp;quot;should have many locations&amp;quot; do
    @company.should have_many(:locations)
  end

  it &amp;quot;should have many leads&amp;quot; do
    @company.should have_many(:leads)
  end

  it &amp;quot;should have many jobs&amp;quot; do
    @company.should have_many(:jobs)
  end

  it &amp;quot;should have many notes&amp;quot; do
    @company.should have_many(:notes)
  end

  it &amp;quot;should have many phones ordered by phone type position&amp;quot; do
    @company.should have_many(:phones, :as =&amp;gt; :phonable,
      :include =&amp;gt; :phone_type, :order =&amp;gt; 'phone_types.position')
  end

  it &amp;quot;should have many events&amp;quot; do
    @company.should have_many(:events)
  end

  it &amp;quot;should have many interests&amp;quot; do
    @company.should have_many(:interests)
  end

  it &amp;quot;should belong_to an exchange&amp;quot; do
    @company.should belong_to(:exchange)
  end

  it 'should belong_to a primary_contact' do
    @company.should belong_to(:primary_contact, :class_name =&amp;gt; 'Job')
  end

  it 'should have many articles' do
    @company.should have_many(:articles,
      :order =&amp;gt; 'articles.date DESC, articles.created_at DESC')
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;These specs check the declared associations on our company model &lt;a href="http://github.com/brandon/rspec-on-rails-matchers"&gt;using some custom matchers&lt;/a&gt;. They are not very complicated, but are somewhat repetitive. Each example has a description that is basically a duplication of the implementation.&lt;/p&gt;


	&lt;h3&gt;Step 1: remove the description&lt;/h3&gt;


	&lt;p&gt;For a while now, RSpec has had the ability for matchers to be self describing. If you don’t pass a block to &lt;code&gt;#it&lt;/code&gt;, it uses the description provided by the matcher.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;it do
  @company.should have_many(:jobs)
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;When that spec is run, it gives the output &lt;em&gt;“should have a has_many association called :jobs”&lt;/em&gt;. Depending on what you’re speccing, the built in description isn’t always clear, but in this case it’s great.&lt;/p&gt;


	&lt;p&gt;See &lt;a href="http://rspec.rubyforge.org/rspec/1.1.11/classes/Spec/Matchers.html#M000441"&gt;#simple_matcher&lt;/a&gt; if you want to create custom matchers with useful error messages.&lt;/p&gt;


	&lt;h3&gt;Step 2: remove the subject&lt;/h3&gt;


	&lt;p&gt;So the duplication within each example is gone, but if you look at the full spec above, each example calls &lt;code&gt;@company.should&lt;/code&gt;. Accessing an instance variable isn’t what I would consider “duplication”, but thanks to a &lt;a href="http://github.com/dchelimsky/rspec/commit/dc51a976280b7d9638e9b87c3c7b3c13d3d0b207"&gt;nifty new feature added to RSpec today&lt;/a&gt;, it’s now unnecessary noise.  We can simply call &lt;code&gt;#should&lt;/code&gt; within our example, and it will use a new instance of the described type as the “subject”.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;describe Company do
  it do
    should have_many(:jobs)
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;You can customize the subject if you don’t simply want a new instance.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;describe Company, 'validations' do
  subject { Company.new(valid_company_attributes) }

  it do
    should be_valid
  end
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;&lt;ins&gt;Note: As &lt;a href="#comment-9459"&gt;David Chelimsky points out in the comments&lt;/a&gt;, this is not released yet and is subject to change.&lt;/ins&gt;&lt;/p&gt;


	&lt;h3&gt;Step 3: One-liner&lt;/h3&gt;


	&lt;p&gt;Lastly, we can use the one line block:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;describe Company do
  it { should have_many(:classifications) }
  it { should have_many(:events) }
  it { should have_many(:interests) }
  it { should have_many(:jobs) }
  it { should have_many(:leads) }
  it { should have_many(:locations) }
  it { should have_many(:notes) }
  it { should have_many(:articles, :order =&amp;gt; 'articles.date DESC, articles.created_at DESC') }
  it { should have_many(:industries, :through =&amp;gt; :classifications) }
  it { should have_many(:phones, :as =&amp;gt; :phonable, :include =&amp;gt; :phone_type, :order =&amp;gt; 'phone_types.position') }
  it { should belong_to(:exchange) }
  it { should belong_to(:primary_contact, :class_name =&amp;gt; 'Job') }
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;That’s pretty sexy. I wasn’t able to do this with all of the specs in my app, but it worked with quite a few of them.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-11-08:9434</id>
    <published>2008-11-08T20:03:00Z</published>
    <updated>2008-11-10T01:18:38Z</updated>
    <category term="Code" />
    <category term="javascript" />
    <category term="jquery" />
    <category term="json" />
    <category term="merb" />
    <category term="ruby" />
    <category term="search" />
    <category term="sinatra" />
    <link href="http://opensoul.org/2008/11/8/it-s-a-search-party" rel="alternate" type="text/html" />
    <title>It's a search party!</title>
<content type="html">
            &lt;p&gt;While chatting with Dr. &lt;a href="http://railstips.org"&gt;John Nunemaker&lt;/a&gt; at &lt;a href="http://rubyconf.org"&gt;RubyConf&lt;/a&gt;, I realized that I have several problems. Ignoring the many character flaws that are beyond the scope of this post, my problems are:&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;I tag things I find useful on &lt;a href="http://delicious.com/bkeepers"&gt;Delicious&lt;/a&gt;. But I rarely look back to delicious because it’s just easier to search Google, resorting to Delicious if I can’t find something that I remember tagging.&lt;/li&gt;
		&lt;li&gt;It’s easier to search Google because not everything that I find useful is in Delicious. I don’t want to have to think about &lt;em&gt;where&lt;/em&gt; useful things are, I just want to search for them.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;I want a search engine that prioritizes things that I’ve found useful in the past. Ideally, google would let me tag things and take that into account when calculating page rank. But, in the mean time…&lt;/p&gt;


	&lt;h3&gt;Let’s have a search party!&lt;/h3&gt;


	&lt;p&gt;I threw together a &lt;a href="http://search.collectiveidea.com"&gt;simple search interface&lt;/a&gt; that pulls in results from Google, Delicious, and just for fun, &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;. It shows primarily Google results, but then in the sidebar, it shows results from Delicious, with my bookmarks highlighted at the top, and also results from GitHub. &lt;a href="http://search.collectiveidea.com"&gt;Check it out.&lt;/a&gt;&lt;/p&gt;


&lt;div class="figure"&gt;&lt;a href="http://search.collectiveidea.com"&gt;&lt;img title="SearchParty" src="http://opensoul.org/assets/2008/11/8/Picture_3.png" /&gt;&lt;/a&gt;&lt;/div&gt;

	&lt;p&gt;And if you use Firefox, you can add it as your search provider:&lt;/p&gt;


&lt;div class="figure"&gt;&lt;img title="Firefox Search Provider" src="http://opensoul.org/assets/2008/11/8/searchparty-opensearch.png" /&gt;&lt;/div&gt;

	&lt;p&gt;It is an extremely simple app that has 2 pages and uses JavaScript to read in &lt;span class="caps"&gt;JSON&lt;/span&gt; from all of the services.  There is one Ruby class that does screen-scraping since Delicious doesn’t provide an &lt;span class="caps"&gt;API&lt;/span&gt; to their full search.&lt;/p&gt;


	&lt;p&gt;I first implemented it in &lt;a href="http://merbivore.com"&gt;Merb&lt;/a&gt;, but upon realizing how simplistic it is, I switched it over to &lt;a href="http://sinatra.rubyforge.org"&gt;Sinatra&lt;/a&gt;.  And I used &lt;a href="http://jquery.com"&gt;jQuery&lt;/a&gt; to do the &lt;span class="caps"&gt;JSON&lt;/span&gt; and other JavaScripty goodness. Thanks to &lt;a href="http://mutuallyhuman.com/"&gt;Mark Van Holstyn&lt;/a&gt; for helping implement it.&lt;/p&gt;


	&lt;p&gt;The code is available on &lt;a href="http://github.com/collectiveidea/searchparty"&gt;GitHub&lt;/a&gt;, so check it out, fork it, and make it more awesome.&lt;/p&gt;


	&lt;p&gt;I will be making a few other posts about specific things I learned when building this, including deploying sinatra apps and using jQuery to do &lt;span class="caps"&gt;JSON&lt;/span&gt; with Merb and Sinatra.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-10-24:9067</id>
    <published>2008-10-24T04:52:00Z</published>
    <updated>2008-10-24T04:53:13Z</updated>
    <category term="Code" />
    <category term="csrf" />
    <category term="javascript" />
    <category term="rails" />
    <link href="http://opensoul.org/2008/10/24/ajax-and-request-forgery-protection" rel="alternate" type="text/html" />
    <title>Ajax and Request Forgery Protection</title>
<content type="html">
            &lt;p&gt;Rails 2.1 added protection for &lt;a href="http://en.wikipedia.org/wiki/Cross-site_request_forgery"&gt;cross-site request forgery&lt;/a&gt; by embedding a session-based token in generated forms. Rails will not process a POSTed request without the token. For the most part, this protection is transparent. But occasionally, an Ajax request request gets left out in the cold without a token.&lt;/p&gt;


	&lt;p&gt;If your Ajax request is tied to a form on the page, then all is good because the form already has the authenticity token in it. It only happens when your Ajax request is not tied to a form but makes a &lt;code&gt;POST&lt;/code&gt; request, which is a rare but occasionally useful.&lt;/p&gt;


	&lt;p&gt;So how do we let those Ajax requests in on the fun? We came up with the ingenious idea of just embedding the authenticity token in a meta tag on every page, which can then be used in the Javascript.&lt;/p&gt;


&lt;pre&gt;&lt;code class="erb"&gt;&amp;lt;meta name=&amp;quot;authenticity-token&amp;quot; id=&amp;quot;authenticity-token&amp;quot; content=&amp;quot;&amp;lt;%= form_authenticity_token %&amp;gt;&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The authenticity token is unique for each visitor, and already included in other parts of the page, so this doesn’t defeat the purpose of the request forgery protection.&lt;/p&gt;


	&lt;p&gt;We usually add a couple convenience methods for accessing the token in Javascript.&lt;/p&gt;


&lt;pre&gt;&lt;code class="javascript"&gt;var Application = {
  authenticityToken: function() {
    return $('authenticity-token').content;
  },

  authenticityTokenParameter: function(){
   return 'authenticity_token=' + encodeURIComponent(Application.authenticityToken());
  }
}&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now, we have easy access to it whenever we need it.&lt;/p&gt;


&lt;pre&gt;&lt;code class="javascript"&gt;new Ajax.Request(url, {
  parameters: Application.authenticityTokenParameter()
});&lt;/code&gt;&lt;/pre&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-10-22:8998</id>
    <published>2008-10-22T04:18:00Z</published>
    <updated>2008-10-22T04:22:25Z</updated>
    <category term="Code" />
    <category term="community" />
    <category term="patch" />
    <category term="ruby" />
    <link href="http://opensoul.org/2008/10/22/push-upstream" rel="alternate" type="text/html" />
    <title>Push Upstream</title>
<content type="html">
            &lt;p&gt;Scenario 1: You’re half way through a really productive day on a wicked new feature for an app and everything is going smoothly. Then, from out of nowhere…SMACK! A nasty bug in a library you depend on splatters right in your face. “Seriously, nobody has come across this before?” you mumble.&lt;/p&gt;


	&lt;p&gt;Scenario 2: You’re using some fancy library and you think to yourself, “Geez, wouldn’t it be sweet if it did &lt;em&gt;&amp;lt;insert fancy feature here&amp;gt;&lt;/em&gt; for you?”&lt;/p&gt;


	&lt;p&gt;The temptation, especially with Ruby, is to solve both of these problems in your app’s code base by modifying your copy of the library. This may seem like the path of least resistance and the quickest way to move forward in the short term, but in the long term all you are doing is delaying the cost of properly solving that problem. You are incurring debt, which over time compounds and will end up costing you more to fix.&lt;/p&gt;


	&lt;p&gt;First, when you’re making the change just for yourself, you’re less likely to solve the problem properly or do the appropriate testing. You’ll do some hack job for the problem you have, without considering how it might affect other scenarios.&lt;/p&gt;


	&lt;p&gt;Second, if you found a bug or have a desired feature, chances are that someone else has or will run into the same situation. Fixing it locally doesn’t help everyone else.&lt;/p&gt;


	&lt;p&gt;Lastly, fixing the bug or adding a new feature directly in your app makes it nearly impossible to upgrade the library. I spent over 4 hours this week trying to upgrade an open source app to the latest version of Ruby on Rails, and still have over 100 failing tests.  The biggest problem isn’t Rails itself, but all the plugins that also need upgraded, many of which had been patched in some form.&lt;/p&gt;


	&lt;p&gt;At Collective Idea, we use git submodules for as many external libraries as possible. While submodules have their own issues, and probably aren’t a recommended approach, the positive side-effect is that it strongly discourages us from patching libraries in place. If we do need to make a change, each library is already its own git repository, so we can push our changes and send a pull request to the original maintainer.&lt;/p&gt;


	&lt;p&gt;If you need to modify an open source library, don’t just do it in place. Push your changes upstream. Irresponsible patching hurts us all.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-10-18:8883</id>
    <published>2008-10-18T20:26:00Z</published>
    <updated>2008-10-18T20:31:33Z</updated>
    <category term="Code" />
    <category term="fork" />
    <category term="gem" />
    <category term="github" />
    <category term="money" />
    <category term="ruby" />
    <link href="http://opensoul.org/2008/10/18/money-with-precision" rel="alternate" type="text/html" />
    <title>Money with precision</title>
<content type="html">
            &lt;p&gt;I’ve been working on a project that needs to store mileage reimbursement rates to the nearest tenth of a cent. We were using the &lt;code&gt;money&lt;/code&gt; gem, which stores money amounts in cents, so it looked like it was going to be a pain.&lt;/p&gt;


	&lt;p&gt;But without too much suffering, I &lt;a href="http://github.com/collectiveidea/money"&gt;modified the money gem&lt;/a&gt; to take a precision (in powers of 10), which defaults to 2. It can now store amounts in any precision.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;&amp;gt;&amp;gt; amount = 20.to_money + 0.505.to_money
=&amp;gt; #&amp;lt;Money @precision=3, @currency=&amp;quot;USD&amp;quot;, @cents=20505&amp;gt;
&amp;gt;&amp;gt; amount.to_s
=&amp;gt; &amp;quot;20.505&amp;quot;
&amp;gt;&amp;gt; amount.format
=&amp;gt; &amp;quot;$20.51&amp;quot;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;You can also store amounts in negative precisions, like millions:&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;&amp;gt;&amp;gt; amount = Money.new(50, 'USD', -6)
&amp;gt;&amp;gt; amount.to_s
=&amp;gt; &amp;quot;50&amp;quot;
&amp;gt;&amp;gt; amount.format
=&amp;gt; &amp;quot;$50000000.00&amp;quot;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Check out our &lt;a href="http://github.com/collectiveidea/money"&gt;fork of the money gem on github&lt;/a&gt;. There are lots of other goodies in there.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-10-14:8730</id>
    <published>2008-10-14T04:14:00Z</published>
    <updated>2008-10-15T03:06:20Z</updated>
    <category term="Code" />
    <category term="bdd" />
    <category term="cucumber" />
    <category term="presentation" />
    <category term="rails" />
    <category term="ruby" />
    <category term="slides" />
    <category term="testing" />
    <link href="http://opensoul.org/2008/10/14/behavior-driven-development-with-cucumber" rel="alternate" type="text/html" />
    <title>Behavior Driven Development with Cucumber</title>
<content type="html">
            &lt;p&gt;The &lt;a href="http://greatlakesrubybash.org"&gt;Great Lakes Ruby Bash&lt;/a&gt; was a good time. There were several quality presentations, including Jim Weirich’s talk “Playing it Safe – How to write library friendly code in Ruby”, Larry Karnowski’s talk “Usability on Rails”, and Brandon Dimcheff’s “Metawhat? A look into the mysterious metaclass”.&lt;/p&gt;


	&lt;p&gt;I presented a talk titled “Behavior Driven Development with Cucumber”. Despite the fact that half of the audience didn’t know what the hell I was talking about, I think it went well. I &lt;a href="http://www.slideshare.net/bkeepers/behavior-driven-development-with-cucumber-presentation"&gt;uploaded the slides from my talk to slideshare&lt;/a&gt; if you’re interested. I’m not sure that they’ll really be very helpful, but I may try to record audio to go with them at some point.&lt;/p&gt;


	&lt;p&gt;As far as I know, no audio or video was captured at the conference.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-10-13:8704</id>
    <published>2008-10-13T02:10:00Z</published>
    <updated>2008-10-15T03:06:15Z</updated>
    <category term="Code" />
    <category term="acts_as_audited" />
    <category term="plugin" />
    <link href="http://opensoul.org/2008/10/13/acts_as_audited-in-development" rel="alternate" type="text/html" />
    <title>acts_as_audited in development</title>
<content type="html">
            &lt;p&gt;Thanks to &lt;a href="http://github.com/metatribe"&gt;metatribe&lt;/a&gt;, a huge annoyance in &lt;a href="http://github.com/collectiveidea/acts_as_audited"&gt;acts_as_audited&lt;/a&gt; is now fixed: it works in development mode.  Due to it’s dependance on Rails’ cache sweepers, which are only enabled when caching is, acts_as_audited didn’t work in development mode.&lt;/p&gt;


	&lt;p&gt;metatribe has a &lt;a href="http://github.com/collectiveidea/acts_as_audited/commit/0f7bce2fec364762fef2662ee8abd72ab6be2672"&gt;crafty solution&lt;/a&gt;, which took me a few minutes to believe it would even work.  So &lt;a href="http://github.com/collectiveidea/acts_as_audited"&gt;pull&lt;/a&gt; the latest version and happy auditing.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-09-04:7811</id>
    <published>2008-09-04T00:37:00Z</published>
    <updated>2008-10-15T03:06:10Z</updated>
    <category term="Code" />
    <category term="javascript" />
    <link href="http://opensoul.org/2008/9/4/the-importance-of-var-in-javascript" rel="alternate" type="text/html" />
    <title>The importance of var in JavaScript</title>
<content type="html">
            &lt;p&gt;I would consider myself proficient at JavaScript. Not a rockstar, but I can hold my own. But I didn’t learn it out of a book; I picked it up slowly over several years. So occasionally I come across something that I probably would have learned in the first couple chapters of a decent JavaScript book.&lt;/p&gt;


	&lt;p&gt;Today, I experienced the importance of declaring variables with &lt;code&gt;var&lt;/code&gt;.&lt;/p&gt;


	&lt;p&gt;For the unenlightened like myself, JavaScript basically has two scopes for variables: global and local. Variables assigned outside of a function are global, and variables assigned inside of a function, using the &lt;code&gt;var&lt;/code&gt; keyword, are local (not rocket surgery). However, if you leave the &lt;code&gt;var&lt;/code&gt; keyword off, it assigns a global variable, regardless of where it’s declared.&lt;/p&gt;


	&lt;p&gt;Here’s a bit of code that demonstrates this:&lt;/p&gt;


&lt;pre&gt;&lt;code class="javascript"&gt;function fail() {
  date = new Date();
  console.log('Before: ' + Number(date));
  setTimeout(function() {
    console.log('After: ' + Number(date));
  }, 1000);
}

fail();
fail();&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The code defines a function that sets a variable, logs the variable, then defines a callback that logs the variable again on second later. If you call the function twice in a row, you can see the effect:&lt;/p&gt;


&lt;pre&gt;
Before: 1220487263486
Before: 1220487263499
After: 1220487263499 &amp;lt;- This should be 1220487263486
After: 1220487263499
&lt;/pre&gt;

	&lt;p&gt;Declaring the &lt;code&gt;date&lt;/code&gt; variable with &lt;code&gt;var&lt;/code&gt; gives us this output:&lt;/p&gt;


&lt;pre&gt;
Before: 1220487287985
Before: 1220487287994
After: 1220487287985 &amp;lt;- see, this is the same as the first line
After: 1220487287994
&lt;/pre&gt;

	&lt;p&gt;So remember kids, declare local variables with &lt;code&gt;var&lt;/code&gt;!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://opensoul.org/">
    <author>
      <name>brandon</name>
    </author>
    <id>tag:opensoul.org,2008-08-22:7233</id>
    <published>2008-08-22T11:00:00Z</published>
    <updated>2008-10-15T03:06:03Z</updated>
    <category term="Code" />
    <category term="autotest" />
    <category term="gem" />
    <category term="ruby" />
    <category term="testing" />
    <link href="http://opensoul.org/2008/8/22/autotest-mapping-for-rails-test-conventions" rel="alternate" type="text/html" />
    <title>Autotest mapping for Rails test conventions</title>
<content type="html">
            &lt;p&gt;A while ago I posted a configuration for getting &lt;a href="http://opensoul.org/2007/12/6/autotest-without-rails"&gt;autotest to work with &lt;code&gt;Test::Unit&lt;/code&gt; outside of Rails&lt;/a&gt;. Ryan Davis, author of &lt;a href="http://www.zenspider.com/ZSS/Products/ZenTest/"&gt;autotest&lt;/a&gt;, commented on that post saying that it should “Just Work™” without any custom configuration. I was perplexed because I’ve never been able to get it to work on my gems and Rails plugins.&lt;/p&gt;


	&lt;p&gt;I finally took time to look into the issue, and realized it’s because I always use the Rails naming conventions for my test files. I name them &lt;code&gt;foo_test.rb&lt;/code&gt;, instead of &lt;code&gt;test_foo.rb&lt;/code&gt;, which is what Autotest looks for.&lt;/p&gt;


	&lt;p&gt;That’s easily solvable.  Here’s an Autotest configuration, tested with ZenTest 3.10.0, that should make it work for either naming convention.  You can throw this in your &lt;code&gt;~/.autotest&lt;/code&gt; file, or in a &lt;code&gt;.autotest&lt;/code&gt; file inside your project.&lt;/p&gt;


&lt;pre&gt;&lt;code class="ruby"&gt;Autotest.add_hook :initialize do |at|
  at.clear_mappings

  at.add_mapping %r%/^lib/(.*)\.rb$% do |_, m|
    possible = File.basename(m[1])
    files_matching %r%^test/.*(#{possible}_test|test_#{possible})\.rb$%
  end

  at.add_mapping(%r%^test/.*\.rb$%) {|filename, _| filename }
end&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Happy autotesting.&lt;/p&gt;
          </content>  </entry>
</feed>
