<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title>A Single Programmer's Blog</title>
  <subtitle>A really swell blog built with Webby</subtitle>
  <link href="http://blog.teksol.info/" rel="alternate" type="text/html" />
  
  <link href="http://feeds.feedburner.com/teksol" rel="alternate" type="application/atom+xml" />
  <author>
    <name>François Beausoleil</name>
    <email>francois@teksol.info</email>
  </author>
  <id>http://blog.teksol.info/</id>
  <updated>2009-06-21T01:55:29Z</updated>
  <link rel="self" href="http://feeds.feedburner.com/teksol" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry>
    <title>We've Been Doing TDD for Centuries, You Know..</title>
    <link href="http://blog.teksol.info/2009/06/20/weve-been-doing-tdd-for-centuries-you-know-dot.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-06-20:20090620215529</id>
    <updated>2009-06-20T21:55:29-04:00</updated>
    <content type="html">&lt;p&gt;Today, I was working on my lawn.  Spreading new soil to sow new grass.  I was looking at the ground, and I was pretty sure drainage wasn&amp;#8217;t going to be good.  I decided to make a test: I got out the garden hose and let it flow.  Sure enough, water was pooling instead of draining.  Back to the drawing board (or at least, a couple more rakes to spread things around).&lt;/p&gt;
&lt;p&gt;As I was working the soil, a thought hit me:  I&amp;#8217;d say nearly every profession has been doing test driven design (not development) since pretty much the dawn of time:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;the toolsmith in the ancient tribes would hit the stone, see if it did work or not, and repeat as appropriate;&lt;/li&gt;
	&lt;li&gt;the chef tastes his food before letting other people eat it;&lt;/li&gt;
	&lt;li&gt;the plumber tests the pipes before letting the water flow in;&lt;/li&gt;
	&lt;li&gt;the soldier tests his equipment before setting off on the battlefield;&lt;/li&gt;
	&lt;li&gt;naval engineers are &lt;a href="http://www.foxnews.com/story/0,2933,526833,00.html"&gt;simulation testing their latest aircraft carrier&lt;/a&gt; in an effort to ensure nothing is out of place;&lt;/li&gt;
	&lt;li&gt;certain programmers write automated tests for their code, to ensure it works as designed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If nearly every profession has been doing it for thousands of years, why aren&amp;#8217;t you doing it today?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/TmM6ihURm0Q" height="1" width="1"/&gt;</content>
    
    <category term="tdd" label="Tdd" />
    
    <category term="test-driven-design" label="Test-driven-design" />
      </entry>
  <entry>
    <title>Piston on Windows: Some Pointers</title>
    <link href="http://blog.teksol.info/2009/06/07/piston-on-windows-some-pointers.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-06-07:20090607073420</id>
    <updated>2009-06-07T07:34:20-04:00</updated>
    <content type="html">&lt;p&gt;If you need to run Piston on Windows, &lt;a href="http://boxcycle.com"&gt;BoxCycle&lt;/a&gt; wrote some information about it at: &lt;a href="http://blog.boxcycle.com/2009/05/plugin-updates-svn-piston-windows-git/"&gt;Rails Plugin Updates, SVN, and Piston 2.0.2 on Windows&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/PRUhmeKQxYQ" height="1" width="1"/&gt;</content>
    
    <category term="piston" label="Piston" />
    
    <category term="windows" label="Windows" />
      </entry>
  <entry>
    <title>How to Parse HTML Documents Under JRuby Using XOM, TagSoup and Nux</title>
    <link href="http://blog.teksol.info/2009/05/01/how-to-parse-html-documents-under-jruby-using-xom-tagsoup-and-nux.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-05-01:20090501160316</id>
    <updated>2009-05-01T16:03:16-04:00</updated>
    <content type="html">&lt;p&gt;It&amp;#8217;s not that hard, but it still took me 2 hours to do it.  I had a couple of false starts, and I pored over documentation for a while until I hit upon the excellent &lt;a href="http://acs.lbl.gov/nux/"&gt;Nux&lt;/a&gt; library.&lt;/p&gt;
&lt;p&gt;I won&amp;#8217;t let you go through the same failures I had.  Here&amp;#8217;s the code:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="c"&gt;# Demonstrates how to parse a local HTML document using XOM,&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt; &lt;span class="c"&gt;# TagSoup and Nux, under JRuby.&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt; &lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt; &lt;span class="c"&gt;# http://www.xom.nu/&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; &lt;span class="c"&gt;# http://home.ccil.org/~cowan/XML/tagsoup/&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt; &lt;span class="c"&gt;# http://acs.lbl.gov/nux/&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt; 
&lt;span class="no"&gt; 8&lt;/span&gt; include &lt;span class="co"&gt;Java&lt;/span&gt;
&lt;span class="no"&gt; 9&lt;/span&gt; mydir = &lt;span class="co"&gt;File&lt;/span&gt;.expand_path(&lt;span class="co"&gt;File&lt;/span&gt;.dirname(&lt;span class="pc"&gt;__FILE__&lt;/span&gt;))
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt;11&lt;/span&gt; &lt;span class="c"&gt;# This is how you require libraries without touching your&lt;/span&gt;
&lt;span class="no"&gt;12&lt;/span&gt; &lt;span class="c"&gt;# CLASSPATH from JRuby. I put the required files in vendor/.&lt;/span&gt;
&lt;span class="no"&gt;13&lt;/span&gt; &lt;span class="c"&gt;# Nux includes it's dependencies (XOM and saxon), so I didn't&lt;/span&gt;
&lt;span class="no"&gt;14&lt;/span&gt; &lt;span class="c"&gt;# have any other libraries to add.&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt; require &lt;span class="co"&gt;File&lt;/span&gt;.join(mydir, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;vendor&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;tagsoup.jar&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="no"&gt;16&lt;/span&gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;%w(&lt;/span&gt;&lt;span class="k"&gt;nux.jar saxon8.jar xom.jar&lt;/span&gt;&lt;span class="dl"&gt;)&lt;/span&gt;&lt;/span&gt;.each &lt;span class="r"&gt;do&lt;/span&gt; |filename|
&lt;span class="no"&gt;17&lt;/span&gt;   require &lt;span class="co"&gt;File&lt;/span&gt;.join(mydir, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;vendor&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;nux&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;lib&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, filename)
&lt;span class="no"&gt;18&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;19&lt;/span&gt; 
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt; import &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;org.ccil.cowan.tagsoup.Parser&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;21&lt;/span&gt; import &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;nu.xom.Builder&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;22&lt;/span&gt; 
&lt;span class="no"&gt;23&lt;/span&gt; builder = &lt;span class="co"&gt;Builder&lt;/span&gt;.new(&lt;span class="co"&gt;Parser&lt;/span&gt;.new)
&lt;span class="no"&gt;24&lt;/span&gt; 
&lt;span class="no"&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;/span&gt; &lt;span class="c"&gt;# XOM's Builder expects a full URL, so tell it where to find the&lt;/span&gt;
&lt;span class="no"&gt;26&lt;/span&gt; &lt;span class="c"&gt;# document.&lt;/span&gt;
&lt;span class="no"&gt;27&lt;/span&gt; doc = builder.build(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;file://&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;File&lt;/span&gt;.expand_path(&lt;span class="co"&gt;File&lt;/span&gt;.join(mydir, &lt;span class="pc"&gt;ARGV&lt;/span&gt;[&lt;span class="i"&gt;0&lt;/span&gt;]))&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="no"&gt;28&lt;/span&gt; puts doc.toXML

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;h3&gt;Extra!  Add XPath querying&lt;/h3&gt;
&lt;p&gt;Continuing from above, you can add XPath querying:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; import &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;nux.xom.xquery.XQueryUtil&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt; 
&lt;span class="no"&gt;3&lt;/span&gt; &lt;span class="c"&gt;# Must use '*:p'.  '*' stands for any/default namespace.&lt;/span&gt;
&lt;span class="no"&gt;4&lt;/span&gt; results = &lt;span class="co"&gt;XQueryUtil&lt;/span&gt;.xquery(doc, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;//*:p&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; p results.size
&lt;span class="no"&gt;6&lt;/span&gt; results.size.times &lt;span class="r"&gt;do&lt;/span&gt; |index|
&lt;span class="no"&gt;7&lt;/span&gt;   puts results.get(index).toXML
&lt;span class="no"&gt;8&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; 

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Why am I going through these motions?  Because I wanted to use my 20% for fun.  Besides, I need to process large quantities of HTML as quickly as possible for a cool project I&amp;#8217;m working on, and JRuby seems to be the &lt;a href="http://twitter.com/fbeausoleil/status/1670082272"&gt;fastest implementation&lt;/a&gt;, according to my unscientific benchmark.&lt;/p&gt;
&lt;p&gt;But the real reason was that both &lt;a href="http://nokogiri.rubyforge.org/nokogiri/"&gt;Nokogiri&lt;/a&gt; and &lt;a href="http://wiki.github.com/why/hpricot"&gt;Hpricot&lt;/a&gt; wouldn&amp;#8217;t load/run under JRuby 1.2.0.&lt;/p&gt;
&lt;p&gt;Actually, let me rephrase that:  Nokogiri did load, but crashed while requiring the library:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="er"&gt;$&lt;/span&gt; jruby -w test.rb data.html 
&lt;span class="no"&gt; 2&lt;/span&gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;Users&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;francois/&lt;span class="co"&gt;Library&lt;/span&gt;/&lt;span class="co"&gt;Java&lt;/span&gt;/&lt;span class="co"&gt;JRuby&lt;/span&gt;/jruby-&lt;span class="fl"&gt;1.2&lt;/span&gt;.&lt;span class="i"&gt;0&lt;/span&gt;/lib/ruby/gems/&lt;span class="fl"&gt;1.8&lt;/span&gt;/gems/nokogiri-&lt;span class="fl"&gt;1.2&lt;/span&gt;.&lt;span class="i"&gt;3&lt;/span&gt;-java/lib/nokogiri/xml/node.rb:&lt;span class="i"&gt;180&lt;/span&gt;: undefined method &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;next_sibling' for class &lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class="co"&gt;Nokogiri&lt;/span&gt;::&lt;span class="co"&gt;XML&lt;/span&gt;::&lt;span class="co"&gt;Node&lt;/span&gt;&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt; (NameError)
&lt;span class="no"&gt; 3&lt;/span&gt;         from /Users/francois/Library/Java/JRuby/jruby-1.2.0/lib/ruby/gems/1.8/gems/nokogiri-1.2.3-java/lib/nokogiri/xml/node.rb:31:in `require&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;         from &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;Users&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;francois/&lt;span class="co"&gt;Library&lt;/span&gt;/&lt;span class="co"&gt;Java&lt;/span&gt;/&lt;span class="co"&gt;JRuby&lt;/span&gt;/current/lib/ruby/site_ruby/&lt;span class="fl"&gt;1.8&lt;/span&gt;/rubygems/custom_require.rb:&lt;span class="i"&gt;31&lt;/span&gt;&lt;span class="sy"&gt;:in&lt;/span&gt; &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;require'
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;         from /Users/francois/Library/Java/JRuby/jruby-1.2.0/lib/ruby/gems/1.8/gems/nokogiri-1.2.3-java/lib/nokogiri/xml.rb:3
&lt;span class="no"&gt; 6&lt;/span&gt;         from /Users/francois/Library/Java/JRuby/jruby-1.2.0/lib/ruby/gems/1.8/gems/nokogiri-1.2.3-java/lib/nokogiri/xml.rb:31:in &lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;require&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;
&lt;span class="no"&gt; 7&lt;/span&gt;         from /Users/francois/Library/Java/JRuby/current/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 8&lt;/span&gt;         from &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;Users&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;francois/&lt;span class="co"&gt;Library&lt;/span&gt;/&lt;span class="co"&gt;Java&lt;/span&gt;/&lt;span class="co"&gt;JRuby&lt;/span&gt;/jruby-&lt;span class="fl"&gt;1.2&lt;/span&gt;.&lt;span class="i"&gt;0&lt;/span&gt;/lib/ruby/gems/&lt;span class="fl"&gt;1.8&lt;/span&gt;/gems/nokogiri-&lt;span class="fl"&gt;1.2&lt;/span&gt;.&lt;span class="i"&gt;3&lt;/span&gt;-java/lib/nokogiri.rb:&lt;span class="i"&gt;10&lt;/span&gt;
&lt;span class="no"&gt; 9&lt;/span&gt;         from &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;Users&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;francois/&lt;span class="co"&gt;Library&lt;/span&gt;/&lt;span class="co"&gt;Java&lt;/span&gt;/&lt;span class="co"&gt;JRuby&lt;/span&gt;/jruby-&lt;span class="fl"&gt;1.2&lt;/span&gt;.&lt;span class="i"&gt;0&lt;/span&gt;/lib/ruby/gems/&lt;span class="fl"&gt;1.8&lt;/span&gt;/gems/nokogiri-&lt;span class="fl"&gt;1.2&lt;/span&gt;.&lt;span class="i"&gt;3&lt;/span&gt;-java/lib/nokogiri.rb:&lt;span class="i"&gt;36&lt;/span&gt;&lt;span class="sy"&gt;:in&lt;/span&gt; &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;require'
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;         from /Users/francois/Library/Java/JRuby/current/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:36:in &lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;require&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;
&lt;span class="no"&gt;11&lt;/span&gt;         from test.rb:2
&lt;span class="no"&gt;12&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;I have reported this &lt;a href="http://github.com/tenderlove/nokogiri/issues#issue/31"&gt;bug to the proper authorities&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hpricot is another matter entirely.  When I tried to use it earlier, I hit a roadblock because JRuby couldn&amp;#8217;t install the native extensions.  I tried again just now, and if you specify the version to be &lt;code&gt;~&amp;gt; 0.6.1&lt;/code&gt;, it works.  Specify any other version, and you&amp;#8217;re a sitting duck:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="er"&gt;$&lt;/span&gt; jruby -&lt;span class="co"&gt;S&lt;/span&gt; gem install -v &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;~&amp;gt; 0.6&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; hpricot
&lt;span class="no"&gt; 2&lt;/span&gt; &lt;span class="co"&gt;Building&lt;/span&gt; native extensions.  &lt;span class="co"&gt;This&lt;/span&gt; could take a &lt;span class="r"&gt;while&lt;/span&gt;...
&lt;span class="no"&gt; 3&lt;/span&gt; &lt;span class="co"&gt;ERROR&lt;/span&gt;:  &lt;span class="co"&gt;Error&lt;/span&gt; installing hpricot:
&lt;span class="no"&gt; 4&lt;/span&gt;         &lt;span class="co"&gt;ERROR&lt;/span&gt;: &lt;span class="co"&gt;Failed&lt;/span&gt; to build gem native extension.
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt; 6&lt;/span&gt; /&lt;span class="co"&gt;Users&lt;/span&gt;/francois/&lt;span class="co"&gt;Library&lt;/span&gt;/&lt;span class="co"&gt;Java&lt;/span&gt;/&lt;span class="co"&gt;JRuby&lt;/span&gt;/current/bin/jruby extconf.rb install -v ~&amp;gt; &lt;span class="fl"&gt;0.6&lt;/span&gt; hpricot
&lt;span class="no"&gt; 7&lt;/span&gt; 
&lt;span class="no"&gt; 8&lt;/span&gt; 
&lt;span class="no"&gt; 9&lt;/span&gt; &lt;span class="co"&gt;Gem&lt;/span&gt; files will remain installed &lt;span class="r"&gt;in&lt;/span&gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;Users&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;francois/&lt;span class="co"&gt;Library&lt;/span&gt;/&lt;span class="co"&gt;Java&lt;/span&gt;/&lt;span class="co"&gt;JRuby&lt;/span&gt;/jruby-&lt;span class="fl"&gt;1.2&lt;/span&gt;.&lt;span class="i"&gt;0&lt;/span&gt;/lib/ruby/gems/&lt;span class="fl"&gt;1.8&lt;/span&gt;/gems/hpricot-&lt;span class="fl"&gt;0.8&lt;/span&gt;.&lt;span class="i"&gt;1&lt;/span&gt; &lt;span class="r"&gt;for&lt;/span&gt; inspection.
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; &lt;span class="co"&gt;Results&lt;/span&gt; logged to &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;Users&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;francois/&lt;span class="co"&gt;Library&lt;/span&gt;/&lt;span class="co"&gt;Java&lt;/span&gt;/&lt;span class="co"&gt;JRuby&lt;/span&gt;/jruby-&lt;span class="fl"&gt;1.2&lt;/span&gt;.&lt;span class="i"&gt;0&lt;/span&gt;/lib/ruby/gems/&lt;span class="fl"&gt;1.8&lt;/span&gt;/gems/hpricot-&lt;span class="fl"&gt;0.8&lt;/span&gt;.&lt;span class="i"&gt;1&lt;/span&gt;/ext/hpricot_scan/gem_make.out
&lt;span class="no"&gt;11&lt;/span&gt; 
&lt;span class="no"&gt;12&lt;/span&gt; &lt;span class="er"&gt;$&lt;/span&gt; jruby -&lt;span class="co"&gt;S&lt;/span&gt; gem install -v &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;~&amp;gt; 0.6.1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; hpricot
&lt;span class="no"&gt;13&lt;/span&gt; &lt;span class="co"&gt;Successfully&lt;/span&gt; installed hpricot-&lt;span class="fl"&gt;0.6&lt;/span&gt;.&lt;span class="i"&gt;164&lt;/span&gt;-java
&lt;span class="no"&gt;14&lt;/span&gt; &lt;span class="i"&gt;1&lt;/span&gt; gem installed
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt; &lt;span class="co"&gt;Installing&lt;/span&gt; ri documentation &lt;span class="r"&gt;for&lt;/span&gt; hpricot-&lt;span class="fl"&gt;0.6&lt;/span&gt;.&lt;span class="i"&gt;164&lt;/span&gt;-java...

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/myB-MHbRExk" height="1" width="1"/&gt;</content>
    
    <category term="jruby" label="Jruby" />
      </entry>
  <entry>
    <title>Keeping Yourself DRY in Shoulda Tests</title>
    <link href="http://blog.teksol.info/2009/04/29/keeping-yourself-dry-in-shoulda-tests.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-04-29:20090429220242</id>
    <updated>2009-04-29T22:02:42-04:00</updated>
    <content type="html">&lt;p&gt;When I&amp;#8217;m testing admin controllers, I often have tests that follow this form:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;test/functional/admin/orders_controller_test.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;OrdersControllerTest&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActionController&lt;/span&gt;::&lt;span class="co"&gt;TestCase&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   logged_in_as &lt;span class="sy"&gt;:active_user&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     context &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;on GET to :index&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;       setup &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;         get &lt;span class="sy"&gt;:index&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;       &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt; 
&lt;span class="no"&gt; 8&lt;/span&gt;       should_deny_access
&lt;span class="no"&gt; 9&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt; 
&lt;span class="no"&gt;12&lt;/span&gt;   not_logged_in &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt;13&lt;/span&gt;     context &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;on GET to :index&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt;14&lt;/span&gt;       setup &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt;         get &lt;span class="sy"&gt;:index&lt;/span&gt;
&lt;span class="no"&gt;16&lt;/span&gt;       &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;17&lt;/span&gt; 
&lt;span class="no"&gt;18&lt;/span&gt;       should_deny_access
&lt;span class="no"&gt;19&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;21&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Well, this is all Ruby, right?  And Ruby has wonderful blocks, and blocks can be passed around&amp;#8230;&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;test/functional/admin/orders_controller_test.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;OrdersControllerTest&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActionController&lt;/span&gt;::&lt;span class="co"&gt;TestCase&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   deny_access_tests = lambda &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     context &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;on GET to :index&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;       setup &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;         get &lt;span class="sy"&gt;:index&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;       &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt; 
&lt;span class="no"&gt; 8&lt;/span&gt;       should_deny_access
&lt;span class="no"&gt; 9&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt; 
&lt;span class="no"&gt;12&lt;/span&gt;   logged_in_as &lt;span class="sy"&gt;:active_user&lt;/span&gt;, &amp;amp;deny_access_tests
&lt;span class="no"&gt;13&lt;/span&gt;   not_logged_in, &amp;amp;deny_access_tests
&lt;span class="no"&gt;14&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This is valid for any block of code that you want to test again and again:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;test/functional/admin/orders_controller_test.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;OrdersControllerTest&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActionController&lt;/span&gt;::&lt;span class="co"&gt;TestCase&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   successful_index_render = lambda &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     should_respond_with &lt;span class="sy"&gt;:success&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;     should_render_template &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;     should_assign_to &lt;span class="sy"&gt;:orders&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt; 
&lt;span class="no"&gt; 8&lt;/span&gt;   logged_in_as &lt;span class="sy"&gt;:admin&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 9&lt;/span&gt;     context &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &amp;amp;successful_index_render
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt; 
&lt;span class="no"&gt;12&lt;/span&gt;   logged_in_as &lt;span class="sy"&gt;:sub_admin&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt;13&lt;/span&gt;     context &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &amp;amp;successful_index_render
&lt;span class="no"&gt;14&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Alternatively, and it might be easier in the end, you could use methods:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;test/functional/admin/orders_controller_test.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;OrdersControllerTest&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActionController&lt;/span&gt;::&lt;span class="co"&gt;TestCase&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.should_render_successful_index_response
&lt;span class="no"&gt; 3&lt;/span&gt;     should_respond_with &lt;span class="sy"&gt;:success&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;     should_render_template &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;     should_assign_to &lt;span class="sy"&gt;:orders&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt;     
&lt;span class="no"&gt; 8&lt;/span&gt;   logged_in_as &lt;span class="sy"&gt;:admin&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 9&lt;/span&gt;     should_render_successful_index_response
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt; 
&lt;span class="no"&gt;12&lt;/span&gt;   logged_in_as &lt;span class="sy"&gt;:sub_admin&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt;13&lt;/span&gt;     should_render_successful_index_response
&lt;span class="no"&gt;14&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Note thought that you must define your methods at the top of your test case.  Remember that Ruby executes a class definition, so when you suddenly call &lt;code&gt;should_render_successful_index_response&lt;/code&gt;, the method definition has to be available, or else Ruby will complain with a &lt;code&gt;NoMethodError&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Ain&amp;#8217;t Ruby sweet?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/FTAjRCM-KFs" height="1" width="1"/&gt;</content>
    
    <category term="unit-testing" label="Unit-testing" />
      </entry>
  <entry>
    <title>What if You Didn't Have Access to If/Then/Else?</title>
    <link href="http://blog.teksol.info/2009/04/17/what-if-you-didnt-have-access-to-if-then-else.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-04-17:20090417113316</id>
    <updated>2009-04-17T11:33:16-04:00</updated>
    <content type="html">&lt;p&gt;Image a Ruby where &lt;code&gt;if/then/else&lt;/code&gt; isn&amp;#8217;t available:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Account&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt;   &lt;span class="c"&gt;# This method returns the balance in words, negative or positive, ready for display in the UI&lt;/span&gt;
&lt;span class="no"&gt;3&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;balance_in_words&lt;/span&gt;
&lt;span class="no"&gt;4&lt;/span&gt;     &lt;span class="c"&gt;# Err...  How do I do that?&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;6&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If you were a strict Object-Oriented person, you&amp;#8217;d do it this way:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;PositiveBalanceAccount&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;balance_in_words&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Positive&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt; 
&lt;span class="no"&gt; 7&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;NegativeBalanceAccount&lt;/span&gt;
&lt;span class="no"&gt; 8&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;balance_in_words&lt;/span&gt;
&lt;span class="no"&gt; 9&lt;/span&gt;     &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Negative&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;But then, your objects would have to change class whily-nilly.  Pretty darn hard.  But multi-method dispatching gives us a nice solution:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Account&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;initialize&lt;/span&gt;(balance)
&lt;span class="no"&gt; 3&lt;/span&gt;     &lt;span class="iv"&gt;@balance&lt;/span&gt; = balance
&lt;span class="no"&gt; 4&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt; 6&lt;/span&gt;   defmulti &lt;span class="sy"&gt;:balance_in_words&lt;/span&gt;,
&lt;span class="no"&gt; 7&lt;/span&gt;     lambda { &lt;span class="iv"&gt;@balance&lt;/span&gt; &amp;lt; &lt;span class="i"&gt;0&lt;/span&gt; } =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Negative&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;span class="no"&gt; 8&lt;/span&gt;     lambda { &lt;span class="iv"&gt;@balance&lt;/span&gt; &amp;gt; &lt;span class="i"&gt;0&lt;/span&gt; } =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Positive&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 9&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt;11&lt;/span&gt; &lt;span class="co"&gt;Account&lt;/span&gt;.new(&lt;span class="i"&gt;15&lt;/span&gt;).balance_in_words &lt;span class="c"&gt;# =&amp;gt; &amp;quot;Positive&amp;quot;&lt;/span&gt;
&lt;span class="no"&gt;12&lt;/span&gt; &lt;span class="co"&gt;Account&lt;/span&gt;.new(&lt;span class="i"&gt;-5&lt;/span&gt;).balance_in_words &lt;span class="c"&gt;# =&amp;gt; &amp;quot;Negative&amp;quot;&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;For the observant amongst you, you might have noticed I forgot the nil balance case.  This is really a programming error, so it should be treated as such:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="co"&gt;Account&lt;/span&gt;.new(&lt;span class="i"&gt;0&lt;/span&gt;).balance_in_words
&lt;span class="no"&gt;2&lt;/span&gt; lib/defmulti.rb:&lt;span class="i"&gt;46&lt;/span&gt;&lt;span class="sy"&gt;:in&lt;/span&gt; &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;balance_in_words': #&amp;lt;Account:0x197222c @balance=0&amp;gt; received balance_in_words but did not have a guard clause that matched and no else clause. (Defmulti::MissingGuardClause)
&lt;span class="no"&gt;3&lt;/span&gt;         from test.rb:16
&lt;span class="no"&gt;4&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;For the even more observant, yes, there exists an implementation that does exactly what I have described above.  It&amp;#8217;s called defmulti, it&amp;#8217;s a gem, and it&amp;#8217;s on GitHub:  http://github.com/francois/defmulti.&lt;/p&gt;
&lt;h2&gt;What is this useful for?&lt;/h2&gt;
&lt;p&gt;This library is a thought experiment.  When you lose the familiar tools, what can you do?  Of course, this library works atop the existing Ruby implementation and to be truly useful, syntax would have to be provided to make this much less verbose.  It&amp;#8217;s interesting nonetheless to see what can be done without the syntax extensions.&lt;/p&gt;
&lt;p&gt;Anyway, what would you use this for?  Multi-method dispatching is a tool that helps writing code without conditionals.  The conditionals are specified outside the block of code that executes.  The examples above are pretty thin, but looking at &lt;a href="http://blog.thinkrelevance.com/2008/8/26/java-next-3-dispatch-2"&gt;Java.next #3: Dispatch&lt;/a&gt;, I can provide another solution to his Ruby example:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; defmulti &lt;span class="sy"&gt;:letter_grade&lt;/span&gt;,
&lt;span class="no"&gt; 2&lt;/span&gt;   lambda {|grade| (&lt;span class="i"&gt;90&lt;/span&gt;..&lt;span class="i"&gt;100&lt;/span&gt;).include?(grade) || grade == &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;} =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;span class="no"&gt; 3&lt;/span&gt;   lambda {|grade| (&lt;span class="i"&gt;80&lt;/span&gt;...&lt;span class="i"&gt;90&lt;/span&gt;).include?(grade) || grade == &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;} =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;span class="no"&gt; 4&lt;/span&gt;   lambda {|grade| (&lt;span class="i"&gt;70&lt;/span&gt;...&lt;span class="i"&gt;80&lt;/span&gt;).include?(grade) || grade == &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;} =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;C&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;   lambda {|grade| (&lt;span class="i"&gt;60&lt;/span&gt;...&lt;span class="i"&gt;70&lt;/span&gt;).include?(grade) || grade == &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;} =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;D&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;span class="no"&gt; 6&lt;/span&gt;   lambda {|grade| ( &lt;span class="i"&gt;0&lt;/span&gt;...&lt;span class="i"&gt;60&lt;/span&gt;).include?(grade) || grade == &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;F&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;} =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;F&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt; 
&lt;span class="no"&gt; 8&lt;/span&gt; letter_grade &lt;span class="i"&gt;60&lt;/span&gt;  &lt;span class="c"&gt;# =&amp;gt; &amp;quot;D&amp;quot;&lt;/span&gt;
&lt;span class="no"&gt; 9&lt;/span&gt; letter_grade &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="c"&gt;# =&amp;gt; &amp;quot;A&amp;quot;&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; letter_grade &lt;span class="pc"&gt;nil&lt;/span&gt; &lt;span class="c"&gt;# =&amp;gt; Defmulti::MissingGuardClause&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Again, I&amp;#8217;m struck by the clunky syntax, but if we ignore that for a second, could this be even better than Stuart Halloway&amp;#8217;s example?  Ruby&amp;#8217;s case statement is very, very powerful and very easy to use.  Is this useful?  Not at the moment.  But it&amp;#8217;s a thought experiment I thought I&amp;#8217;d throw out there.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/1ak1zdaCU4k" height="1" width="1"/&gt;</content>
    
    <category term="language-design" label="Language-design" />
      </entry>
  <entry>
    <title>Beware of Git's Content Tracking</title>
    <link href="http://blog.teksol.info/2009/04/15/beware-of-gits-content-tracking.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-04-15:20090415003152</id>
    <updated>2009-04-15T00:31:52-04:00</updated>
    <content type="html">&lt;p&gt;A while ago, I was wondering how rename tracking in Git worked.  I was told that renames didn&amp;#8217;t really exist in Git, as Git tracked content, not files themselves.  Fair enough.&lt;/p&gt;
&lt;p&gt;But, I just stumbled upon something:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; $ gdc vendor/plugins/acts_as_money/LICENSE 
&lt;span class="no"&gt; 2&lt;/span&gt; diff --git a/vendor/plugins/acts_as_money/LICENSE b/vendor/plugins/acts_as_money/LICENSE
&lt;span class="no"&gt; 3&lt;/span&gt; index e69de29..a273c73 100644
&lt;span class="no"&gt; 4&lt;/span&gt; --- a/vendor/plugins/acts_as_money/LICENSE
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; +++ b/vendor/plugins/acts_as_money/LICENSE
&lt;span class="no"&gt; 6&lt;/span&gt; @@ -0,0 +1,4 @@
&lt;span class="no"&gt; 7&lt;/span&gt; +one:
&lt;span class="no"&gt; 8&lt;/span&gt; +  user: active
&lt;span class="no"&gt; 9&lt;/span&gt; +  name: name
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; +  description: description

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Tell me, does that look right?  I&amp;#8217;ll manually fix that file, but that just decreased my confidence level in Git.&lt;/p&gt;
&lt;p&gt;The original LICENSE file was empty, and there apparently was another file (a fixture file) that was empty too, and the latter saw some content added.&lt;/p&gt;
&lt;p&gt;Why did this happen?  LICENSE was updated as part of a merge&amp;mdash;from a branch in which the LICENSE file doesn&amp;#8217;t exist.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/9AdHpwq6dA4" height="1" width="1"/&gt;</content>
    
    <category term="git" label="Git" />
      </entry>
  <entry>
    <title>Returning CSV data to the browser - revisited</title>
    <link href="http://blog.teksol.info/2009/04/06/returning-csv-data-to-the-browser-revisited.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-04-06:20090406102330</id>
    <updated>2009-04-06T10:23:30-04:00</updated>
    <content type="html">&lt;p&gt;Back in 2006, I wrote &lt;a href="http://blog.teksol.info/2006/03/23/returning-csv-data-to-the-browser"&gt;Returning CSV data to the browser&lt;/a&gt;.  The method I was using back then is way obsolete.  Let&amp;#8217;s use the correct way to do it.  If you want to follow along, just browse over to &lt;a href="http://github.com/francois/blog.teksol.info/tree/master/content/2009/04/06/returning-csv-data-to-the-browser-revisited"&gt;returning-csv-data-to-the-browser-revisited&lt;/a&gt; and read on.&lt;/p&gt;
&lt;p&gt;First of all, the correct way to return non HTML data to the browser is to use &lt;a href="http://api.rubyonrails.org/classes/ActionController/MimeResponds/InstanceMethods.html#M000368"&gt;respond_to&lt;/a&gt;.  Let&amp;#8217;s do so here:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;app/controllers/reports/timelines_controller.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Reports::TimelinesController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ApplicationController&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;show&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     &lt;span class="iv"&gt;@timelines&lt;/span&gt; = &lt;span class="co"&gt;Timeline&lt;/span&gt;.all
&lt;span class="no"&gt; 4&lt;/span&gt;     respond_to &lt;span class="r"&gt;do&lt;/span&gt; |format|
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;       format.csv &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;         response.headers[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]        = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;text/csv; charset=UTF-8; header=present&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt;         response.headers[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Content-Disposition&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;] = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;attachment; filename=timeline-report.csv&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 8&lt;/span&gt;       &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; 9&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The rest is pretty easy.  Generating the data is easy enough:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;app/models/timeline.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; require &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;fastercsv&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt; 
&lt;span class="no"&gt; 3&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Timeline&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;   default_scope &lt;span class="sy"&gt;:order&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;started_at ASC&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt; 6&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;to_csv&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt;     &lt;span class="co"&gt;FasterCSV&lt;/span&gt;.generate_line([
&lt;span class="no"&gt; 8&lt;/span&gt;           started_at.to_s(&lt;span class="sy"&gt;:db&lt;/span&gt;),
&lt;span class="no"&gt; 9&lt;/span&gt;           ended_at.to_s(&lt;span class="sy"&gt;:db&lt;/span&gt;),
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;           project_id]).chomp
&lt;span class="no"&gt;11&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;12&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;And rendering the view?  Look how easy this gets:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;app/views/reports/timelines/show.csv.erb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="co"&gt;Started&lt;/span&gt; &lt;span class="co"&gt;At&lt;/span&gt;,&lt;span class="co"&gt;Ended&lt;/span&gt; &lt;span class="co"&gt;At&lt;/span&gt;,&lt;span class="co"&gt;Project&lt;/span&gt; &lt;span class="co"&gt;ID&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt; &amp;lt;&lt;span class="s"&gt;&lt;span class="dl"&gt;%=&lt;/span&gt;&lt;span class="k"&gt; render :partial &lt;/span&gt;&lt;span class="dl"&gt;=&lt;/span&gt;&lt;/span&gt;&amp;gt; &lt;span class="iv"&gt;@timelines&lt;/span&gt; %&amp;gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Notice the file&amp;#8217;s name?  &lt;code&gt;show.csv.erb&lt;/code&gt;?  The &lt;code&gt;csv&lt;/code&gt; in the filename is what connects the respond_to call with the view.&lt;/p&gt;
&lt;p&gt;And the final piece, the timeline partial:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;app/views/reports/timelines/_timeline.csv.erb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &amp;lt;&lt;span class="s"&gt;&lt;span class="dl"&gt;%=&lt;/span&gt;&lt;span class="k"&gt; timeline.to_csv %&amp;gt;
&lt;span class="no"&gt;2&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Now, on to the next obsolete article in the bunch&amp;#8230;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/-1FwRW8nnZY" height="1" width="1"/&gt;</content>
      </entry>
  <entry>
    <title>Building the SQL WHERE Clause Dynamically - Updated</title>
    <link href="http://blog.teksol.info/2009/04/02/building-the-sql-where-clause-dynamically-updated.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-04-02:20090402092911</id>
    <updated>2009-04-02T09:29:11-04:00</updated>
    <content type="html">&lt;p&gt;Back in October 2005, I wrote an article entitled &lt;a href="http://blog.teksol.info/2005/10/31/building-the-sql-where-clause-dynamically-in-rails"&gt;Building the SQL WHERE Clause Dynamically&lt;/a&gt;.  This article is obsolete and I&amp;#8217;m replacing it with this one instead.&lt;/p&gt;
&lt;p&gt;What do you do with a FORM that has multiple conditions?  Something like this:&lt;/p&gt;
&lt;form action="#" method="get"&gt;
&lt;p&gt;
    &lt;label for="region"&gt;Region:&lt;/label&gt;
&lt;select id="region" name="region"&gt;
      &lt;option&gt;All&lt;/option&gt;
      &lt;option&gt;North&lt;/option&gt;
      &lt;option&gt;East&lt;/option&gt;
      &lt;option&gt;West&lt;/option&gt;
      &lt;option&gt;South&lt;/option&gt;
&lt;/select&gt;
&lt;/p&gt;
&lt;p&gt;
    &lt;label for="salary"&gt;Salary:&lt;/label&gt;
&lt;select id="salary" name="salary"&gt;
      &lt;option&gt;All&lt;/option&gt;
      &lt;option&gt;0-10K&lt;/option&gt;
      &lt;option&gt;10K-20K&lt;/option&gt;
      &lt;option&gt;20K-50K&lt;/option&gt;
      &lt;option&gt;50K+&lt;/option&gt;
&lt;/select&gt;
&lt;/p&gt;
&lt;p&gt;
    &lt;label for="tags"&gt;Tags:&lt;/label&gt;
&lt;input id="tags" name="tags"/&gt;
&lt;/p&gt;
&lt;/form&gt;
&lt;p&gt;The way I would do it today is using named scopes:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;app/models/person.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Person&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   is_taggable
&lt;span class="no"&gt; 3&lt;/span&gt; 
&lt;span class="no"&gt; 4&lt;/span&gt;   named_scope &lt;span class="sy"&gt;:in_region&lt;/span&gt;,
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;     lambda {|region| {&lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt; {&lt;span class="sy"&gt;:region&lt;/span&gt; =&amp;gt; region}}}
&lt;span class="no"&gt; 6&lt;/span&gt;   named_scope &lt;span class="sy"&gt;:with_salary&lt;/span&gt;,
&lt;span class="no"&gt; 7&lt;/span&gt;     lambda {|lower, upper| {&lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt;
&lt;span class="no"&gt; 8&lt;/span&gt;       {&lt;span class="sy"&gt;:salary&lt;/span&gt; =&amp;gt; (lower .. upper)}}}
&lt;span class="no"&gt; 9&lt;/span&gt; 
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   &lt;span class="c"&gt;# Elided, but something similar to the above&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt;   named_scope &lt;span class="sy"&gt;:tagged_with&lt;/span&gt;,
&lt;span class="no"&gt;12&lt;/span&gt;     lambda {|tags| {&lt;span class="sy"&gt;:conditions&lt;/span&gt; =&amp;gt;
&lt;span class="no"&gt;13&lt;/span&gt;       ...}}
&lt;span class="no"&gt;14&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then you need your controller to translate between what the view provides and what the model expects:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;app/controllers/searches_controller.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;SearchesController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ApplicationController&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;show&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     root = &lt;span class="co"&gt;Person&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;     root = root.in_region(params[&lt;span class="sy"&gt;:region&lt;/span&gt;]) &lt;span class="r"&gt;unless&lt;/span&gt; params[&lt;span class="sy"&gt;:region&lt;/span&gt;] =~ &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="mod"&gt;i&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;     &lt;span class="r"&gt;unless&lt;/span&gt; params[&lt;span class="sy"&gt;:salary&lt;/span&gt;] =~ &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;all&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="mod"&gt;i&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;       params[&lt;span class="sy"&gt;:salary&lt;/span&gt;].gsub!(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;K&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;000&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="no"&gt; 7&lt;/span&gt;       lower, upper = params[&lt;span class="sy"&gt;:salary&lt;/span&gt;].split(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;-&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="no"&gt; 8&lt;/span&gt;       root = root.with_salary(lower, upper)
&lt;span class="no"&gt; 9&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;     root = root.tagged_with(&lt;span class="co"&gt;Tag&lt;/span&gt;.parse(params[&lt;span class="sy"&gt;:tags&lt;/span&gt;])) &lt;span class="r"&gt;unless&lt;/span&gt; params[&lt;span class="sy"&gt;:tags&lt;/span&gt;].blank?
&lt;span class="no"&gt;11&lt;/span&gt;     &lt;span class="iv"&gt;@people&lt;/span&gt; = root.paginate(&lt;span class="sy"&gt;:page&lt;/span&gt; =&amp;gt; params[&lt;span class="sy"&gt;:page&lt;/span&gt;])
&lt;span class="no"&gt;12&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;13&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;For simpler forms, the approach above would be sufficient.  For more complex forms, I suggest you look at plugins that aim to provide more structure around your SQL clauses, such as:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://ambition.rubyforge.org/"&gt;Ambition&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://agilewebdevelopment.com/plugins/criteria_query"&gt;criteria_query&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://agilewebdevelopment.com/plugins/ez_where"&gt;ez_where&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also suggest looking at &lt;a href="http://agilewebdevelopment.com/plugins/category/4"&gt;Searching and Queries Plugins &amp;#8211; Agile Web Development&lt;/a&gt; to find other plugins.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/Xs8sAvTz9aA" height="1" width="1"/&gt;</content>
    
    <category term="tips" label="Tips" />
      </entry>
  <entry>
    <title>Actions With Dashes - Updated</title>
    <link href="http://blog.teksol.info/2009/04/02/actions-with-dashes-updated.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-04-02:20090402092259</id>
    <updated>2009-04-02T09:00:00-04:00</updated>
    <content type="html">&lt;p&gt;Back in October 2005, I wrote an article entitled &lt;a href="http://blog.teksol.info/2005/10/25/actions-with-dashes"&gt;Actions with Dashes&lt;/a&gt;.  This article is perfectly obsolete and uses a trick instead of the router as it was intended.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s say you want an action where the URL is &lt;code&gt;http://myproject.com/contact-us&lt;/code&gt;.  The best way to do that currently is to use Rails&amp;#8217; router:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;config/routes.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; map.contact_us &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/contact-us&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:controller&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;pages&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:action&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;show&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:page&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;contact_us&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="code"&gt;
&lt;h5&gt;app/controllers/pages_controller.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;PagesController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActionController&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;show&lt;/span&gt;
&lt;span class="no"&gt;3&lt;/span&gt;     render &lt;span class="sy"&gt;:action&lt;/span&gt; =&amp;gt; params[&lt;span class="sy"&gt;:page&lt;/span&gt;]
&lt;span class="no"&gt;4&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code class="class"&gt;PagesController&lt;/code&gt; above is also good for any other static pages you want to serve on your site.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/8vzxfhkX3cI" height="1" width="1"/&gt;</content>
    
    <category term="tips" label="Tips" />
      </entry>
  <entry>
    <title>I'm Updating and Obsolescing Articles on My Blog</title>
    <link href="http://blog.teksol.info/2009/04/02/im-updating-and-obsolescing-articles-on-my-blog.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-04-02:20090402100836</id>
    <updated>2009-04-02T08:00:00-04:00</updated>
    <content type="html">&lt;p&gt;A couple of days ago, &lt;a href="http://twitter.com/jfcouture"&gt;@jfcouture&lt;/a&gt; tweeted:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://twitter.com/cmercier"&gt;@cmercier&lt;/a&gt; People with stuff older than 6 months in the Rails world on their blog should do the same!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style="text-align:right"&gt;&lt;a href="http://twitter.com/jfcouture/status/1415694931"&gt;@jfcouture&lt;/a&gt; via &lt;a href="http://twitter.com/"&gt;Twitter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This was in response to Carl&amp;#8217;s rant that obsolete Merb tutorials should be removed / deprecated.&lt;/p&gt;
&lt;p&gt;I decided to follow their advice.  I&amp;#8217;m revisiting all my old posts and saying they are either obsolete, or providing links to replacements.  Expect to see at least a post a day for the next couple of weeks as I revisit my old posts.  This is interesting!  I had forgotten about a lot of things I had written about.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/AM5dY150fvk" height="1" width="1"/&gt;</content>
    
    <category term="general" label="General" />
      </entry>
  <entry>
    <title>Piston 2.0 Finally Released: With Git, Subversion and Ruby 1.9</title>
    <link href="http://blog.teksol.info/2009/04/01/piston-2-dot-0-finally-released-with-git-subversion-and-ruby-1-dot-9.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-04-01:20090401182758</id>
    <updated>2009-04-01T18:27:58-04:00</updated>
    <content type="html">&lt;p&gt;It&amp;#8217;s been a long time coming, I know.  Believe me when I say so.  But the good news first:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Piston 2.0 supports Git repositories and working copies&lt;/li&gt;
	&lt;li&gt;Piston 2.0 supports Subversion repositories and working copies&lt;/li&gt;
	&lt;li&gt;Piston 2.0 is Ruby 1.9.1 compliant&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Get it&lt;/h3&gt;
&lt;p&gt;(Allow a couple of hours for the gem to propagate)&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; $ sudo gem install piston

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;h3&gt;What is Piston?&lt;/h3&gt;
&lt;p&gt;Piston eases your vendor branch management worries.  It copies vendor/upstream code into your own repository, preserving local patches.&lt;/p&gt;
&lt;h3&gt;The new website&lt;/h3&gt;
&lt;p&gt;Yes, I have a new look to go along with the website.  &lt;a href="http://piston.rubyforge.org/"&gt;http://piston.rubyforge.org/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There is also an avenue for asking questions and getting help about Piston.  Register to the &lt;a href="http://groups.google.com/group/piston-discussion"&gt;piston-discussion Google Group&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Please have fun and enjoy yourselves.&lt;/p&gt;
&lt;p&gt;NOTE: This is not an April&amp;#8217;s Fool joke (although it would have been really cool to do it if I had thought so!)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/oW-xlXqJUno" height="1" width="1"/&gt;</content>
      </entry>
  <entry>
    <title>ArgumentError on #Sum When Using Classifier::Bayes</title>
    <link href="http://blog.teksol.info/2009/03/27/argumenterror-on-number-sum-when-using-classifier-bayes.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-03-27:20090327220424</id>
    <updated>2009-03-27T22:04:24-04:00</updated>
    <content type="html">&lt;p&gt;If you want to use the &lt;a href="http://classifier.rubyforge.org/"&gt;Classifier&lt;/a&gt; gem within a &lt;a href="http://rubyonrails.org/"&gt;Rails&lt;/a&gt; project, you&amp;#8217;re in for a surprise:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;Library&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="co"&gt;Ruby&lt;/span&gt;/&lt;span class="co"&gt;Gems&lt;/span&gt;/&lt;span class="fl"&gt;1.8&lt;/span&gt;/gems/activerecord-&lt;span class="fl"&gt;2.3&lt;/span&gt;.&lt;span class="i"&gt;2&lt;/span&gt;/lib/active_record/attribute_methods.rb:&lt;span class="i"&gt;102&lt;/span&gt;&lt;span class="sy"&gt;:in&lt;/span&gt; &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;sum': wrong number of arguments (1 for 0) (ArgumentError)
&lt;span class="no"&gt; 2&lt;/span&gt;         from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:102:in &lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;instance_method_already_implemented?&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;         from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:72:in `define_attribute_methods&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;         from &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;Library&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="co"&gt;Ruby&lt;/span&gt;/&lt;span class="co"&gt;Gems&lt;/span&gt;/&lt;span class="fl"&gt;1.8&lt;/span&gt;/gems/activerecord-&lt;span class="fl"&gt;2.3&lt;/span&gt;.&lt;span class="i"&gt;2&lt;/span&gt;/lib/active_record/attribute_methods.rb:&lt;span class="i"&gt;71&lt;/span&gt;&lt;span class="sy"&gt;:in&lt;/span&gt; &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;each'
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;         from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:71:in &lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;define_attribute_methods&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;         from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/attribute_methods.rb:351:in `respond_to?&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt;         from &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;Library&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="co"&gt;Ruby&lt;/span&gt;/&lt;span class="co"&gt;Gems&lt;/span&gt;/&lt;span class="fl"&gt;1.8&lt;/span&gt;/gems/activerecord-&lt;span class="fl"&gt;2.3&lt;/span&gt;.&lt;span class="i"&gt;2&lt;/span&gt;/lib/active_record/associations/association_proxy.rb:&lt;span class="i"&gt;219&lt;/span&gt;&lt;span class="sy"&gt;:in&lt;/span&gt; &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;method_missing'
&lt;span class="no"&gt; 8&lt;/span&gt;         from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/associations/association_proxy.rb:219:in &lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;each&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;
&lt;span class="no"&gt; 9&lt;/span&gt;         from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/associations/association_proxy.rb:219:in `send&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;         from &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;Library&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="co"&gt;Ruby&lt;/span&gt;/&lt;span class="co"&gt;Gems&lt;/span&gt;/&lt;span class="fl"&gt;1.8&lt;/span&gt;/gems/activerecord-&lt;span class="fl"&gt;2.3&lt;/span&gt;.&lt;span class="i"&gt;2&lt;/span&gt;/lib/active_record/associations/association_proxy.rb:&lt;span class="i"&gt;219&lt;/span&gt;&lt;span class="sy"&gt;:in&lt;/span&gt; &lt;span class="sh"&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;span class="k"&gt;method_missing'
&lt;span class="no"&gt;11&lt;/span&gt;         from /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/associations/association_collection.rb:364:in &lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;method_missing_without_paginate&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;
&lt;span class="no"&gt;12&lt;/span&gt;         from /Users/francois/Projects/family_budget/vendor/gems/mislav-will_paginate-2.3.5/lib/will_paginate/finder.rb:167:in `method_missing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;13&lt;/span&gt;         from script/classifier:&lt;span class="i"&gt;8&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This is because the Classifier gem implements &lt;code&gt;Array#sum&lt;/code&gt;.  Unfortunately, Classifier is loaded after Rails, which means ActiveSupport&amp;#8217;s own &lt;code&gt;#sum&lt;/code&gt; is replaced.  The solution?  Use either &lt;a href="http://github.com/yury/classifier"&gt;Yury&amp;#8217;s fork&lt;/a&gt;, or &lt;a href="http://github.com/francois/classifier"&gt;my own&lt;/a&gt;.  Both use ActiveSupport&amp;#8217;s #sum instead of a custom implementation.&lt;/p&gt;
&lt;p&gt;The only difference between my version and Yury&amp;#8217;s is I use &lt;a href="http://github.com/technicalpickles/jeweler"&gt;Jeweler&lt;/a&gt; to maintain and package the gem.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/ndTHvGOxoX4" height="1" width="1"/&gt;</content>
    
    <category term="tips" label="Tips" />
      </entry>
  <entry>
    <title>Know How to Use Your Tools: ResourceController</title>
    <link href="http://blog.teksol.info/2009/03/10/know-how-to-use-your-tools-resourcecontroller.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-03-10:20090310151208</id>
    <updated>2009-03-10T15:12:08-04:00</updated>
    <content type="html">&lt;p&gt;Today, I was building a controller action that was polymorphically finding and associating an object.  I could have used a &lt;del&gt;simple&lt;/del&gt; dumb solution, such as this:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;app/controllers/watches_controller.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;WatchesController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ApplicationController&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;create&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     &lt;span class="iv"&gt;@watch&lt;/span&gt; = &lt;span class="co"&gt;Watch&lt;/span&gt;.build(&lt;span class="sy"&gt;:watcher&lt;/span&gt; =&amp;gt; current_person)
&lt;span class="no"&gt; 4&lt;/span&gt;     &lt;span class="iv"&gt;@watch&lt;/span&gt;.subject = &lt;span class="r"&gt;case&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;                      &lt;span class="r"&gt;when&lt;/span&gt; params[&lt;span class="sy"&gt;:person_id&lt;/span&gt;]
&lt;span class="no"&gt; 6&lt;/span&gt;                        &lt;span class="co"&gt;Person&lt;/span&gt;.find(params[&lt;span class="sy"&gt;:person_id&lt;/span&gt;])
&lt;span class="no"&gt; 7&lt;/span&gt;                      &lt;span class="r"&gt;when&lt;/span&gt; params[&lt;span class="sy"&gt;:event_id&lt;/span&gt;]
&lt;span class="no"&gt; 8&lt;/span&gt;                        &lt;span class="co"&gt;Event&lt;/span&gt;.find(params[&lt;span class="sy"&gt;:event_id&lt;/span&gt;])
&lt;span class="no"&gt; 9&lt;/span&gt;                      &lt;span class="r"&gt;else&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;                        raise &lt;span class="co"&gt;ArgumentError&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Don't know how to handle other keys... &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;params.keys.inspect&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt;                      &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;12&lt;/span&gt;     &lt;span class="iv"&gt;@watch&lt;/span&gt;.save!
&lt;span class="no"&gt;13&lt;/span&gt;     flash[&lt;span class="sy"&gt;:notice&lt;/span&gt;] = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;You're watching &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@watch&lt;/span&gt;.subject.name&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;14&lt;/span&gt;     redirect_to root_url
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;16&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;That sucked.  Really bad.  Why did I have to have a &lt;code class="keyword"&gt;case&lt;/code&gt;/&lt;code class="keyword"&gt;switch&lt;/code&gt; statement in my controller?  Why not use a simpler alternative?  I could have gone the full polymorphic route too:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;app/controllers/watches_controller.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;WatchesController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ApplicationController&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;create&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     &lt;span class="iv"&gt;@watch&lt;/span&gt; = &lt;span class="co"&gt;Watch&lt;/span&gt;.build(&lt;span class="sy"&gt;:watcher&lt;/span&gt; =&amp;gt; current_person)
&lt;span class="no"&gt; 4&lt;/span&gt; 
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;     &lt;span class="c"&gt;# For illustration purposes, this is fine, but INSECURE!!!&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;     &lt;span class="iv"&gt;@watch&lt;/span&gt;.subject_type = params[&lt;span class="sy"&gt;:subject_type&lt;/span&gt;]
&lt;span class="no"&gt; 7&lt;/span&gt;     &lt;span class="iv"&gt;@watch&lt;/span&gt;.subject_id   = params[&lt;span class="sy"&gt;:subject_id&lt;/span&gt;]
&lt;span class="no"&gt; 8&lt;/span&gt;     &lt;span class="iv"&gt;@watch&lt;/span&gt;.save!
&lt;span class="no"&gt; 9&lt;/span&gt; 
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;     flash[&lt;span class="sy"&gt;:notice&lt;/span&gt;] = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;You're watching &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;@watch&lt;/span&gt;.subject.name&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt;     redirect_to root_url
&lt;span class="no"&gt;12&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;13&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then, I remembered that my controller was already a &lt;a href="http://jamesgolick.com/resource_controller"&gt;ResourceController&lt;/a&gt; implementation.  I opened up the code and used this instead:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;app/controllers/watches_controller.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;WatchesController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ResourceController&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt;   belongs_to &lt;span class="sy"&gt;:person&lt;/span&gt;, &lt;span class="sy"&gt;:event&lt;/span&gt;
&lt;span class="no"&gt;3&lt;/span&gt; 
&lt;span class="no"&gt;4&lt;/span&gt;   create.before &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;     &lt;span class="iv"&gt;@watch&lt;/span&gt;.watcher = current_person
&lt;span class="no"&gt;6&lt;/span&gt;     &lt;span class="iv"&gt;@watch&lt;/span&gt;.subject = parent_object
&lt;span class="no"&gt;7&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;8&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;I needed to add a bit of infrastructure (some routes and has_many declarations in my models), but those were benefits (I know I&amp;#8217;ll need them later anyway).  My controller code is simpler, and the intention is clearer, I think.&lt;/p&gt;
&lt;p&gt;In the same vein, are you following &lt;a href="http://search.twitter.com/search?q=%23standup"&gt;#standup&lt;/a&gt; on Twitter?&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/ZjXEqfH-L8A" height="1" width="1"/&gt;</content>
    
    <category term="plugins" label="Plugins" />
      </entry>
  <entry>
    <title>How to Get Your Autotest Output Directly in Your Editor</title>
    <link href="http://blog.teksol.info/2009/03/06/how-to-get-your-autotest-output-directly-in-your-editor.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-03-06:20090306162627</id>
    <updated>2009-03-06T16:26:27-05:00</updated>
    <content type="html">&lt;p&gt;While discussing in &lt;a href="http://campfirenow.com/"&gt;Campfire&lt;/a&gt; with &lt;a href="http://jamesgolick.com/"&gt;James Golick&lt;/a&gt; today, James said he would prefer to have his output directly in &lt;a href="http://www.vim.org/"&gt;Vim&lt;/a&gt;, our editor of choice.  I initially said that since Vim isn&amp;#8217;t &lt;a href="http://www.gnu.org/software/emacs/"&gt;Emacs&lt;/a&gt; and can&amp;#8217;t support a live console, it wouldn&amp;#8217;t work.  James told me to think outside the box.&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; $ autotest &amp;amp;&amp;gt;tmp/autotest.out &amp;amp;
&lt;span class="no"&gt;2&lt;/span&gt; $ vim
&lt;span class="no"&gt;3&lt;/span&gt; # :e tmp/autotest.out

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Yes, thinking outside the box, and &lt;strong&gt;knowing your tools&lt;/strong&gt; makes it much easier.  So far, I&amp;#8217;m liking autotest output in Vim very much.  It&amp;#8217;s easy to navigate the output using Vim movement commands:  &lt;tt&gt;/Person&lt;/tt&gt; finds the errors in person, &lt;tt&gt;gf&lt;/tt&gt; opens the named file, etc.  All in all, this is a pretty good experience.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/kgH6N8VFflY" height="1" width="1"/&gt;</content>
    
    <category term="autotest" label="Autotest" />
    
    <category term="tips" label="Tips" />
      </entry>
  <entry>
    <title>Getting Started with Autotest</title>
    <link href="http://blog.teksol.info/2009/03/06/getting-started-with-autotest.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-03-06:20090306105913</id>
    <updated>2009-03-06T10:59:13-05:00</updated>
    <content type="html">&lt;p&gt;Since yesterday, I read a bit more about &lt;a href="http://www.zenspider.com/ZSS/Products/ZenTest/"&gt;autotest&lt;/a&gt;.  I stumbled on &lt;a href="http://ph7spot.com/articles/getting_started_with_autotest"&gt;Getting Started with Autotest&lt;/a&gt; which you should read immediately.  The article talks about setting up your plugins and doing all kinds of interesting things.&lt;/p&gt;
&lt;p&gt;Getting more proficient with my tools now!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/NY0XTIvYF3Q" height="1" width="1"/&gt;</content>
    
    <category term="autotest" label="Autotest" />
    
    <category term="testing" label="Testing" />
      </entry>
  <entry>
    <title>How I Wasted an Hour on Something Git did in 10 seconds?</title>
    <link href="http://blog.teksol.info/2009/03/05/how-i-wasted-an-hour-on-something-git-did-in-10-seconds.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-03-05:20090305130017</id>
    <updated>2009-03-05T13:00:17-05:00</updated>
    <content type="html">&lt;p&gt;&lt;a href="http://git-scm.com/"&gt;Git&lt;/a&gt; is a wonderful system.  It has all kinds of nooks and crannies that one forgets about.  Anyway, I was doing client work this morning, and my build server (&lt;a href="http://github.com/foca/integrity"&gt;Integrity&lt;/a&gt;, but this isn&amp;#8217;t about Integrity) didn&amp;#8217;t fail, although my local tests were failing.  I began investigating, and &lt;code class="path"&gt;vendor/plugins&lt;/code&gt; wasn&amp;#8217;t even on the build server.  Uh?  I began investigating, and found &lt;code class="path"&gt;vendor/plugins&lt;/code&gt; had turned into a &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"&gt;git submodule&lt;/a&gt; a while back.  I even had the commit&amp;#8217;s SHA1 of when that happened.  I found myself in the unenvious position of having to find and install every plugin we had before that commit back into the application.&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; # 04f7e1 is the commit when the submodule was born
&lt;span class="no"&gt;2&lt;/span&gt; # Checkout the commit before that error occured
&lt;span class="no"&gt;3&lt;/span&gt; $ git checkout 04f7e1^
&lt;span class="no"&gt;4&lt;/span&gt; $ ls vendor/plugins &amp;gt; plugins
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; $ git checkout master
&lt;span class="no"&gt;6&lt;/span&gt; $ cat plugins
&lt;span class="no"&gt;7&lt;/span&gt; $ script/plugin install git://github.com/giraffesoft/timeline_fu.git
&lt;span class="no"&gt;8&lt;/span&gt; # And so on, for the 9 other plugins

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;And then, there was this one plugin which we haven&amp;#8217;t released yet which I was missing.  It&amp;#8217;s called configurable_mailer, and allows us to configure &lt;a href="http://api.rubyonrails.org/classes/ActionMailer/Base.html"&gt;ActionMailer::Base&lt;/a&gt; from tests and from some environment variables.  Anyway, I again checked out the code from &lt;code class="sha1"&gt;04f7e1^&lt;/code&gt;, copied &lt;code class="path"&gt;vendor/plugins/configurable_mailer&lt;/code&gt; outside the repository, checked out master again, and moved the plugin back into place.  As you can imagine, this was painful.  And error-prone.  Then I ran my tests, and immediately had errors.  This application is based off of &lt;a href="http://github.com/giraffesoft/blank"&gt;Blank&lt;/a&gt;, and was using slightly modified versions of certain plugins.  So I added Blank as a remote, fetched and merged.  Ran my tests again.  Still had errors.  And lots of them:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; $ rake test:units
&lt;span class="no"&gt; 2&lt;/span&gt; (in /Users/francois/Projects/project)
&lt;span class="no"&gt; 3&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -Ilib:test &amp;quot;/Library/Ruby/Gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader.rb&amp;quot; &amp;quot;test/unit/account_activation_mailer_test.rb&amp;quot; &amp;quot;test/unit/company_test.rb&amp;quot; &amp;quot;test/unit/event_test.rb&amp;quot; &amp;quot;test/unit/fanship_test.rb&amp;quot; &amp;quot;test/unit/internal_message_test.rb&amp;quot; &amp;quot;test/unit/job_application_test.rb&amp;quot; &amp;quot;test/unit/job_creation_presenter_test.rb&amp;quot; &amp;quot;test/unit/job_suggestion_test.rb&amp;quot; &amp;quot;test/unit/job_test.rb&amp;quot; &amp;quot;test/unit/media_test.rb&amp;quot; &amp;quot;test/unit/message_mailer_test.rb&amp;quot; &amp;quot;test/unit/message_test.rb&amp;quot; &amp;quot;test/unit/password_reset_mailer_test.rb&amp;quot; &amp;quot;test/unit/person_test.rb&amp;quot; &amp;quot;test/unit/profile_url_test.rb&amp;quot; &amp;quot;test/unit/recommendation_mailer_test.rb&amp;quot; &amp;quot;test/unit/recommendation_presenter_test.rb&amp;quot; &amp;quot;test/unit/recommendation_test.rb&amp;quot; &amp;quot;test/unit/relationship_test.rb&amp;quot; &amp;quot;test/unit/timeline_event_test.rb&amp;quot; 
&lt;span class="no"&gt; 4&lt;/span&gt; Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; Started
&lt;span class="no"&gt; 6&lt;/span&gt; ............FFF.........EEEEEEEEEEEEE........................FFFFFFFFFFFFFFFFFFFF.F....F.....EF..EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.................................................................................................................................................................................................................................................................................................................................................................................................
&lt;span class="no"&gt; 7&lt;/span&gt; Finished in 45.235105 seconds.
&lt;span class="no"&gt; 8&lt;/span&gt; 
&lt;span class="no"&gt; 9&lt;/span&gt; 542 tests, 762 assertions, 26 failures, 73 errors

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Bad, I&amp;#8217;m telling you.  Then I remembered something about &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-checkout.html"&gt;git checkout&lt;/a&gt; being able to checkout certain paths.  I read about this somewhere but I can&amp;#8217;t find the source, anymore.  Sorry!  Without even reading the manual, I set out to work.&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; $ get checkout -b fix
&lt;span class="no"&gt;2&lt;/span&gt; $ git rm -r vendor/plugins
&lt;span class="no"&gt;3&lt;/span&gt; $ git checkout -m &amp;quot;Removing submodule'd vendor/plugins (how did that happen?)&amp;quot;
&lt;span class="no"&gt;4&lt;/span&gt; $ git checkout 04f7e1^ -- vendor/plugins

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Wall clock time?  10 seconds.  I was ready to add and commit.&lt;/p&gt;
&lt;p&gt;This is a post to remind you to know your tools, and know them well.  Sorry I can&amp;#8217;t stay anymore.  I&amp;#8217;m off to read &lt;a href="http://www.zenspider.com/ZSS/Products/ZenTest/"&gt;autotest&lt;/a&gt;&amp;#8217;s source and documentation, again.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/brZqRupveJk" height="1" width="1"/&gt;</content>
    
    <category term="git" label="Git" />
      </entry>
  <entry>
    <title>Announcing XLsuite Open Source</title>
    <link href="http://blog.teksol.info/2009/02/18/announcing-xlsuite-open-source.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-02-18:20090218022934</id>
    <updated>2009-02-18T02:29:34-05:00</updated>
    <content type="html">&lt;p&gt;Would you believe we just GPL&amp;#8217;d nearly 40,000 lines of code?  &lt;a href="http://xlsuite.com/blogs/francois/2009/2/18/announcing-xlsuite-open-source/3311"&gt;Yes we did&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/-ntHDBhARTE" height="1" width="1"/&gt;</content>
    
    <category term="opensource" label="Opensource" />
      </entry>
  <entry>
    <title>Nonexistent When Using Phusion Passenger</title>
    <link href="http://blog.teksol.info/2009/02/18/nonexistent-when-using-phusion-passenger.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-02-18:20090218021159</id>
    <updated>2009-02-18T02:11:59-05:00</updated>
    <content type="html">&lt;p&gt;This evening, I was fooling around with mod_passenger for XLsuite.  I ran into a little problem where Passenger was telling me &amp;#8220;No such file or directory &amp;#8211; /nonexistent&amp;#8221;.  A quick search on Google revealed &lt;a href="http://blog.scopeport.org/ruby-on-rails/phusion-passenger-error-file-directory-nonexistent/"&gt;Phusion Passenger error “No such file or directory &amp;#8211; /nonexistent”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That post really made my day.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/K1HGgdKzKhM" height="1" width="1"/&gt;</content>
    
    <category term="tips" label="Tips" />
      </entry>
  <entry>
    <title>GiraffeSoft FLOSS Week: Begins Today!</title>
    <link href="http://blog.teksol.info/2009/02/16/giraffesoft-floss-week-begins-today.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-02-16:20090216163303</id>
    <updated>2009-02-16T16:33:03-05:00</updated>
    <content type="html">&lt;p&gt;&lt;a href="http://jamesgolick.com/"&gt;James Golick&lt;/a&gt; just opened our company blog by adding &lt;a href="http://giraffesoft.com/blog/2009/02/16/floss-week.html"&gt;FLOSS week&lt;/a&gt;.  Over the next few days we&amp;#8217;ll release a couple of plugins that we&amp;#8217;ve been working on/with for the past few projects.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Only problem is, we never get around to releasing this stuff. Starting a blog seemed like a good excuse to spend some time polishing up some code and, you know, writing READMEs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Go on over and enjoy the view!  Don&amp;#8217;t forget the RSS feed:  &lt;a href="http://feeds.giraffesoft.ca/giraffesoft-the-blog"&gt;GiraffeSoft: The Blog&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/y2iROeOnCoc" height="1" width="1"/&gt;</content>
    
    <category term="links" label="Links" />
      </entry>
  <entry>
    <title>ib_outlet Doesn't Create Accessors</title>
    <link href="http://blog.teksol.info/2009/02/16/ib-outlet-doesnt-create-accessors.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-02-16:20090216083456</id>
    <updated>2009-02-16T08:34:56-05:00</updated>
    <content type="html">&lt;p&gt;Lately, I&amp;#8217;ve been having fun with RubyCocoa while reading &lt;a href="http://www.exampler.com/blog/"&gt;Brian Marick&lt;/a&gt;&amp;#8216;s &lt;a href="http://pragprog.com/titles/bmrc/rubycocoa"&gt;RubyCocoa&lt;/a&gt;.  It&amp;#8217;s an entertaining book, and I really like RubyCocoa itself.  But I hit a little gotcha.  Take the following code:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;PathController.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;osx/cocoa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt; 
&lt;span class="no"&gt; 3&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;PathController&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;OSX&lt;/span&gt;::&lt;span class="co"&gt;NSObject&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;   ib_outlet &lt;span class="sy"&gt;:path&lt;/span&gt;, &lt;span class="sy"&gt;:events&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;   ib_action &lt;span class="sy"&gt;:choosePath&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;   
&lt;span class="no"&gt; 7&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;choosePath&lt;/span&gt;(sender)
&lt;span class="no"&gt; 8&lt;/span&gt;     panel = &lt;span class="co"&gt;OSX&lt;/span&gt;::&lt;span class="co"&gt;NSOpenPanel&lt;/span&gt;.openPanel
&lt;span class="no"&gt; 9&lt;/span&gt;     panel.canChooseFiles          = &lt;span class="pc"&gt;false&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;     panel.canChooseDirectories    = &lt;span class="pc"&gt;true&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt;     panel.allowsMultipleSelection = &lt;span class="pc"&gt;false&lt;/span&gt;
&lt;span class="no"&gt;12&lt;/span&gt; 
&lt;span class="no"&gt;13&lt;/span&gt;     result = panel.runModal
&lt;span class="no"&gt;14&lt;/span&gt;     &lt;span class="r"&gt;if&lt;/span&gt; result == &lt;span class="co"&gt;OSX&lt;/span&gt;::&lt;span class="co"&gt;NSFileHandlingPanelOKButton&lt;/span&gt; &lt;span class="r"&gt;then&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt;       &lt;span class="pc"&gt;self&lt;/span&gt;.path.title = panel.filename
&lt;span class="no"&gt;16&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;17&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;18&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;What could be wrong with this?  Turns out &lt;code class="method"&gt;#ib_oulet&lt;/code&gt; does not define accessors for the instance variables it defines.  Look at the exception:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; OSX::OCMessageSendException: Can't get Objective-C method signature for selector 'events' of receiver #&amp;lt;PathController:0x2297be class='PathController' id=0x534ec0&amp;gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   /Library/Frameworks/RubyCocoa.framework/Resources/ruby/osx/objc/oc_wrapper.rb:50:in `ocm_send'
&lt;span class="no"&gt; 3&lt;/span&gt;   /Library/Frameworks/RubyCocoa.framework/Resources/ruby/osx/objc/oc_wrapper.rb:50:in `method_missing'
&lt;span class="no"&gt; 4&lt;/span&gt;   /Users/francois/Projects/fsevtest/build/Debug/fsevtest.app/Contents/Resources/PathController.rb:27:in `choosePath'
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;   /Users/francois/Projects/fsevtest/build/Debug/fsevtest.app/Contents/Resources/rb_main.rb:22:in `NSApplicationMain'
&lt;span class="no"&gt; 6&lt;/span&gt;   /Users/francois/Projects/fsevtest/build/Debug/fsevtest.app/Contents/Resources/rb_main.rb:22
&lt;span class="no"&gt; 7&lt;/span&gt; /Library/Frameworks/RubyCocoa.framework/Resources/ruby/osx/objc/oc_wrapper.rb:50:in `ocm_send': Can't get Objective-C method signature for selector 'events' of receiver #&amp;lt;PathController:0x2297be class='PathController' id=0x534ec0&amp;gt; (OSX::OCMessageSendException)
&lt;span class="no"&gt; 8&lt;/span&gt;   from /Library/Frameworks/RubyCocoa.framework/Resources/ruby/osx/objc/oc_wrapper.rb:50:in `method_missing'
&lt;span class="no"&gt; 9&lt;/span&gt;   from /Users/francois/Projects/fsevtest/build/Debug/fsevtest.app/Contents/Resources/PathController.rb:27:in `choosePath'
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   from /Users/francois/Projects/fsevtest/build/Debug/fsevtest.app/Contents/Resources/rb_main.rb:22:in `NSApplicationMain'
&lt;span class="no"&gt;11&lt;/span&gt;   from /Users/francois/Projects/fsevtest/build/Debug/fsevtest.app/Contents/Resources/rb_main.rb:22

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;From the obscure message, I gathered this was some kind of &lt;a href="http://www.ruby-doc.org/core/classes/NoMethodError.html"&gt;NoMethodError&lt;/a&gt; (why couldn&amp;#8217;t they use an exception with a good name?)  That was Sunday morning.  Sunday evening, I suddenly had a flash that ib_outlet wouldn&amp;#8217;t define an accessor.  Changed my code to use the instance variable instead:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;PathController.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="r"&gt;if&lt;/span&gt; result == &lt;span class="co"&gt;OSX&lt;/span&gt;::&lt;span class="co"&gt;NSFileHandlingPanelOKButton&lt;/span&gt; &lt;span class="r"&gt;then&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt;   &lt;span class="iv"&gt;@path&lt;/span&gt;.title = panel.filename
&lt;span class="no"&gt;3&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Lo and behold!  It worked beautifully.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/HNEpUV7N9fg" height="1" width="1"/&gt;</content>
    
    <category term="rubycocoa" label="Rubycocoa" />
      </entry>
  <entry>
    <title>Productivity Tip: Read Your Blogs in the Afternoon</title>
    <link href="http://blog.teksol.info/2009/02/16/productivity-tip-read-your-blogs-in-the-afternoon.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-02-16:20090216081858</id>
    <updated>2009-02-16T08:18:58-05:00</updated>
    <content type="html">&lt;p&gt;If you&amp;#8217;re in any way, shape or form like me, you usually have more energy in the morning (if you don&amp;#8217;t, skip this post).  My regular schedule puts me in my office around 9 AM every weekday.  First thing I do is pop open &lt;a href="http://google.com/reader"&gt;Google Reader&lt;/a&gt;, and start reading blogs.  What an utter waste of time&amp;#8230;  I waste perfectly good coding time to do an activity that&amp;#8217;s similar to watching television.  I can &lt;em&gt;waste&lt;/em&gt; my time in the afternoon, when I have less energy.  I say &lt;em&gt;waste&lt;/em&gt; but I really mean &lt;strong&gt;relax&lt;/strong&gt;.  Don&amp;#8217;t take me wrong: reading blogs is a very important time, but I should just do it when it&amp;#8217;s OK to do, not when I have the most energy.&lt;/p&gt;
&lt;p&gt;Yesterday evening, I was pondering on the why of the above.  Turns out I can procrastinate just as well as anyone else&amp;#8230;&lt;/p&gt;
&lt;p style="text-align:center"&gt;&lt;a href="http://media.photobucket.com/image/procrastinate/darkjustice2600/procrastinate.jpg"&gt;&lt;img src="http://i63.photobucket.com/albums/h133/darkjustice2600/procrastinate.jpg" width="400" height="320" alt="Procrastination is like masturbation&amp;hellip; it's good in the beginning, but in the end, you realize you've just fucked yourself"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/xsT2XeV7FOY" height="1" width="1"/&gt;</content>
    
    <category term="productivity" label="Productivity" />
      </entry>
  <entry>
    <title>How to Paste Without Indenting in Vim</title>
    <link href="http://blog.teksol.info/2009/02/11/how-to-paste-without-indenting-in-vim.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-02-11:20090211084032</id>
    <updated>2009-02-11T08:40:32-05:00</updated>
    <content type="html">&lt;p&gt;I wanted to paste some HTML into Vim, and I was having a hard time getting something that preserved existing indentation.&lt;/p&gt;
&lt;p&gt;After doing &lt;tt&gt;:help autoindent&lt;/tt&gt;, I found out about smartindent.  So, I turned both smartindent and autoindent off before doing my paste.  That worked wonders!&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; :set nosmartindent
&lt;span class="no"&gt;2&lt;/span&gt; :set noautoindent
&lt;span class="no"&gt;3&lt;/span&gt; i
&lt;span class="no"&gt;4&lt;/span&gt; &amp;lt;CMD&amp;gt;-V
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; &amp;lt;ESC&amp;gt;
&lt;span class="no"&gt;6&lt;/span&gt; :set smartindent
&lt;span class="no"&gt;7&lt;/span&gt; :set autoindent

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Voilà, a correctly pasted, non-indented version of whatever was in the clipboard!&lt;/p&gt;
&lt;p&gt;UPDATE: 2 minutes after I &lt;a href="http://twitter.com/fbeausoleil/status/1198970122"&gt;posted&lt;/a&gt; the link to this article on Twitter, &lt;a href="http://twitter.com/jpalardy"&gt;@jpalardy&lt;/a&gt; replied:&lt;/p&gt;
&lt;p&gt;&lt;iframe width="500" height="200" frameborder="0" src="http://tweetpaste.net/script/?t=1198983486" style="overflow: hidden; display: block; width: 500px; height: 200px;"&gt;&lt;p&gt;&lt;a href="http://twitter.com/jpalardy/statuses/1198983486" target="_blank"&gt;View jpalardy&amp;rsquo;s tweet&lt;/p&gt;&lt;/iframe&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/qC8GL1SlRFo" height="1" width="1"/&gt;</content>
    
    <category term="tips" label="Tips" />
    
    <category term="vim" label="Vim" />
      </entry>
  <entry>
    <title>Setting Up Passenger on Mac OS X Using Passenger Prefs Pane</title>
    <link href="http://blog.teksol.info/2009/02/09/setting-up-passenger-on-mac-os-x-using-passenger-prefs-pane.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-02-09:20090209111301</id>
    <updated>2009-02-09T11:13:01-05:00</updated>
    <content type="html">&lt;p&gt;Before today, I was using Thin to host my development servers.  This was a bother because I had to remember to start/stop Thins as required when I switched tasks.  Well, not anymore&amp;#8230;&lt;/p&gt;
&lt;p&gt;Reading my feeds today, I found &lt;a href="http://www.fngtps.com/passenger-preference-pane"&gt;Passenger Preference Pane&lt;/a&gt;, by &lt;a href="http://www.fngtps.com/"&gt;Fingertips&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download the preference pane itself&lt;/li&gt;
&lt;li&gt;Untar&lt;/li&gt;
&lt;li&gt;Follow the directives in the README about RubyCocoa (either Leopard 10.5.2 or install RubyCocoa yourself from source)&lt;/li&gt;
&lt;li&gt;Double click the prefpane: this will install the preference pane&lt;/li&gt;
&lt;li&gt;Open System Preferences, then Passenger in Other&lt;/li&gt;
&lt;li&gt;Drag and drop your Rails (or Rack-based) application folder into the list&lt;/li&gt;
&lt;li&gt;Click Apply&lt;/li&gt;
&lt;li&gt;Go back to System Preferences, and open Sharing&lt;/li&gt;
&lt;li&gt;Stop and start Apache using the checkbox for Web Sharing&lt;/li&gt;
&lt;li&gt;Visit http://your-apps-base-name.local/ and enjoy!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;One caveat I found was that my home directory had to change permissions.  I had to grant &lt;tt&gt;a+rx&lt;/tt&gt; before it would work:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt;  $ ls -ld ~
&lt;span class="no"&gt;2&lt;/span&gt; drwxr-xr-x+ 78 francois  staff  2652  9 fév 11:13 /Users/francois

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Of course, if you have a multi-user machine, that opens an interesting can of worms for security.  A quick fix would be:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; $ chmod a-rx * &amp;amp;&amp;amp; chmod a+rx the-apps-base-name

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Modify  as needed.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/on7tuiJktuM" height="1" width="1"/&gt;</content>
    
    <category term="passenger" label="Passenger" />
      </entry>
  <entry>
    <title>Another Productivity Tip: Use iTerm and Vim</title>
    <link href="http://blog.teksol.info/2009/02/05/another-productivity-tip-use-iterm-and-vim.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-02-05:20090205112941</id>
    <updated>2009-02-05T11:29:41-05:00</updated>
    <content type="html">&lt;p&gt;I was pairing with &lt;a href="http://jamesgolick.com/"&gt;James Golick&lt;/a&gt; the other day, and he told me he was using &lt;a href="http://iterm.sourceforge.net/"&gt;iTerm&lt;/a&gt; in fullscreen mode.  I was pretty excited by that, and I immediately downloaded and installed it.&lt;/p&gt;
&lt;p&gt;I was already a &lt;a href="http://www.vim.org/"&gt;Vim&lt;/a&gt; user, through the excellent &lt;a href="http://code.google.com/p/macvim/"&gt;MacVim&lt;/a&gt;, but I started using Vim from the console instead.  My main screen is an &lt;a href="http://global.acer.com/products/monitor/X_series.htm"&gt;Acer X243w&lt;/a&gt;, and with Vim in full screen, I have more than enough space to do all my coding.  Splitting vertically is now a real pleasure, and I can even have a 4 way split that&amp;#8217;s not too claustrophobic.&lt;/p&gt;
&lt;p&gt;The other benefit of using iTerm instead of the default &lt;a href="http://www.apple.com/macosx/"&gt;Mac OS X&lt;/a&gt; Terminal is that iTerm can be used in 256 colors, enabling Vim to do even more syntax highlighting.  That wasn&amp;#8217;t a problem in MacVim though.&lt;/p&gt;
&lt;p&gt;Only caveat?  Scrolling is a bit slow.  Me and James both wonder about this&amp;#8230;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/syHZHRgcCw4" height="1" width="1"/&gt;</content>
    
    <category term="productivity" label="Productivity" />
      </entry>
  <entry>
    <title>Duplicate Bug #5404556: Git on Snow Leopard</title>
    <link href="http://blog.teksol.info/2009/02/04/duplicate-bug-number-5404556-git-on-snow-leopard.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-02-04:20090204203202</id>
    <updated>2009-02-04T20:32:02-05:00</updated>
    <content type="html">&lt;p&gt;Just received an email from Apple today:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;From: devbugs@apple.com&lt;br/&gt;Subject: Re: Bug ID 6543251: Git is not available by default on Leopard&lt;/p&gt;
&lt;p&gt;Hello François,&lt;/p&gt;
&lt;p&gt;This is a follow up to Bug ID# 6543251.  After further investigation it has been determined that this is a known issue, which is currently being investigated by engineering.  This issue has been filed in our bug database under the original Bug ID# 5404556. The original bug number being used to track this duplicate issue can be found in the State column, in this format:  Duplicate/OrigBug#.&lt;/p&gt;
&lt;p&gt;Thank you for submitting this bug report. We truly appreciate your assistance in helping us discover and isolate bugs.&lt;/p&gt;
&lt;p&gt;Best Regards,&lt;/p&gt;
&lt;p&gt;Kit Cheung&lt;br/&gt;Apple Developer Connection&lt;br/&gt;Worldwide Developer Relations&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a followup to &lt;a href="http://github.com/blog/327-want-git-preinstalled-on-next-mac-os-x"&gt;Want Git preinstalled on next Mac OS X?&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/iaI7jyhazsI" height="1" width="1"/&gt;</content>
    
    <category term="scm" label="Scm" />
    
    <category term="git" label="Git" />
    
    <category term="apple" label="Apple" />
      </entry>
  <entry>
    <title>Beware of the Habit Creature</title>
    <link href="http://blog.teksol.info/2009/01/23/beware-of-the-habit-creature.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-01-23:20090123101203</id>
    <updated>2009-01-23T10:12:03-05:00</updated>
    <content type="html">&lt;p&gt;You know, I write controller tests day in, day out.  I&amp;#8217;m used to seeing this:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; should &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;be valid&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt;   assert assigns(&lt;span class="sy"&gt;:user&lt;/span&gt;).valid?
&lt;span class="no"&gt;3&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;So, when I write a Rake task and I render some data, I need my assigns:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;lib/tasks/ssl.rake&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; namespace &lt;span class="sy"&gt;:ssl&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   task &lt;span class="sy"&gt;:build&lt;/span&gt; =&amp;gt; &lt;span class="sy"&gt;:environment&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     rm_rf &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;config/sites/&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;     mkdir &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;config/sites&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt; 6&lt;/span&gt;     &lt;span class="co"&gt;Dir&lt;/span&gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;config/ssl/*&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;].each &lt;span class="r"&gt;do&lt;/span&gt; |path|
&lt;span class="no"&gt; 7&lt;/span&gt;       site = &lt;span class="co"&gt;File&lt;/span&gt;.basename(path)
&lt;span class="no"&gt; 8&lt;/span&gt;       parts = site.split(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="no"&gt; 9&lt;/span&gt; 
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;       puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Processing &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;site&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt;       assigns = {
&lt;span class="no"&gt;12&lt;/span&gt;         &lt;span class="sy"&gt;:wildcard_domain&lt;/span&gt;           =&amp;gt; parts[&lt;span class="i"&gt;0&lt;/span&gt;] == &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,
&lt;span class="no"&gt;13&lt;/span&gt;         &lt;span class="sy"&gt;:domain_name&lt;/span&gt;               =&amp;gt; parts[&lt;span class="i"&gt;-2&lt;/span&gt;..&lt;span class="i"&gt;-1&lt;/span&gt;].join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;),
&lt;span class="no"&gt;14&lt;/span&gt;         &lt;span class="sy"&gt;:ssl_key_file_path&lt;/span&gt;         =&amp;gt; &lt;span class="co"&gt;File&lt;/span&gt;.expand_path(&lt;span class="co"&gt;File&lt;/span&gt;.join(&lt;span class="co"&gt;Dir&lt;/span&gt;.pwd, path, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;site&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.key&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)),
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt;         &lt;span class="sy"&gt;:ssl_certificate_file_path&lt;/span&gt; =&amp;gt; &lt;span class="co"&gt;File&lt;/span&gt;.expand_path(&lt;span class="co"&gt;File&lt;/span&gt;.join(&lt;span class="co"&gt;Dir&lt;/span&gt;.pwd, path, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;site&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.crt&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;))}
&lt;span class="no"&gt;16&lt;/span&gt; 
&lt;span class="no"&gt;17&lt;/span&gt;       &lt;span class="r"&gt;next&lt;/span&gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Skipping &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;site&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;assigns(&lt;span class="sy"&gt;:ssl_key_file_path&lt;/span&gt;)&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; does not exist or is unreadable&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;unless&lt;/span&gt; &lt;span class="co"&gt;File&lt;/span&gt;.file?(assigns(&lt;span class="sy"&gt;:ssl_key_file_path&lt;/span&gt;))
&lt;span class="no"&gt;18&lt;/span&gt;       &lt;span class="r"&gt;next&lt;/span&gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Skipping &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;site&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;assigns(&lt;span class="sy"&gt;:ssl_certificate_file_path&lt;/span&gt;)&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; does not exist or is unreadable&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;unless&lt;/span&gt; &lt;span class="co"&gt;File&lt;/span&gt;.file?(assigns(&lt;span class="sy"&gt;:ssl_certificate_file_path&lt;/span&gt;))
&lt;span class="no"&gt;19&lt;/span&gt; 
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt;       view = &lt;span class="co"&gt;ActionView&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;.new([&lt;span class="co"&gt;File&lt;/span&gt;.dirname(&lt;span class="pc"&gt;__FILE__&lt;/span&gt;)], assigns)
&lt;span class="no"&gt;21&lt;/span&gt; 
&lt;span class="no"&gt;22&lt;/span&gt;       &lt;span class="co"&gt;File&lt;/span&gt;.open(&lt;span class="co"&gt;File&lt;/span&gt;.join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;config&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;sites&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;site&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.ssl.conf&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;), &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;w&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class="r"&gt;do&lt;/span&gt; |site_config|
&lt;span class="no"&gt;23&lt;/span&gt;         puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Writing config/sites/&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;site&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;.ssl.conf&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;24&lt;/span&gt;         site_config.write view.render(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;ssl.conf.erb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="no"&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;/span&gt;       &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;26&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;27&lt;/span&gt; 
&lt;span class="no"&gt;28&lt;/span&gt;     view = &lt;span class="co"&gt;ActionView&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;.new([&lt;span class="co"&gt;File&lt;/span&gt;.dirname(&lt;span class="pc"&gt;__FILE__&lt;/span&gt;)], {})
&lt;span class="no"&gt;29&lt;/span&gt;     &lt;span class="co"&gt;File&lt;/span&gt;.open(&lt;span class="co"&gt;File&lt;/span&gt;.join(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;config&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;sites&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;default.conf&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;), &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;w&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class="r"&gt;do&lt;/span&gt; |site_config|
&lt;span class="no"&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;/span&gt;       site_config.write view.render(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;default.conf.erb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="no"&gt;31&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;32&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;33&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Can you spot the error on lines 17 and 18?  Go on, I&amp;#8217;ll wait&amp;#8230;&lt;/p&gt;
&lt;p&gt;You want some help?  Here&amp;#8217;s the backtrace:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; ** Invoke ssl:build (first_time)
&lt;span class="no"&gt; 2&lt;/span&gt; ** Invoke environment (first_time)
&lt;span class="no"&gt; 3&lt;/span&gt; ** Execute environment
&lt;span class="no"&gt; 4&lt;/span&gt; ** Execute ssl:build
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; rm -rf config/sites/
&lt;span class="no"&gt; 6&lt;/span&gt; mkdir config/sites
&lt;span class="no"&gt; 7&lt;/span&gt; Processing _.xlsuite.com
&lt;span class="no"&gt; 8&lt;/span&gt; rake aborted!
&lt;span class="no"&gt; 9&lt;/span&gt; undefined method `assigns' for #&amp;lt;Object:0x389a0&amp;gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; /Users/francois/Documents/work/xlsuite-stable.svn/lib/tasks/ssl.rake:17

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Yes, took me a while too.  I was calling a method named assigns, not using the Hash named assigns.&lt;/p&gt;
&lt;p&gt;Habit, when you take hold of me&amp;#8230;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/qDwMkWkex6A" height="1" width="1"/&gt;</content>
    
    <category term="testing" label="Testing" />
      </entry>
  <entry>
    <title>Using Cucumber for Writing Stories for Command-Line Applications</title>
    <link href="http://blog.teksol.info/2009/01/18/using-cucumber-for-writing-stories-for-command-line-applications.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-01-18:20090118131956</id>
    <updated>2009-01-18T13:19:56-05:00</updated>
    <content type="html">&lt;p&gt;I just started using &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt; to write acceptance tests for a new command-line application I&amp;#8217;m writing.  I used the wonderful &lt;a href="http://newgem.rubyforge.org/"&gt;newgem&lt;/a&gt; to generate the basics for me.&lt;/p&gt;
&lt;p&gt;Then I wrote my first stories:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;features/command_line_client.feature&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; Feature: Command Line Client
&lt;span class="no"&gt; 2&lt;/span&gt;   In order to use Nestor
&lt;span class="no"&gt; 3&lt;/span&gt;   A developer
&lt;span class="no"&gt; 4&lt;/span&gt;   Wants an interface to the program
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;   So that he can use it
&lt;span class="no"&gt; 6&lt;/span&gt; 
&lt;span class="no"&gt; 7&lt;/span&gt;   Scenario: Getting Help
&lt;span class="no"&gt; 8&lt;/span&gt;     When I start nestor with &amp;quot;--help&amp;quot;
&lt;span class="no"&gt; 9&lt;/span&gt;     Then I should see &amp;quot;Usage: nestor [options]&amp;quot;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt;11&lt;/span&gt;   Scenario: Getting the version number
&lt;span class="no"&gt;12&lt;/span&gt;     When I start nestor with &amp;quot;--version&amp;quot;
&lt;span class="no"&gt;13&lt;/span&gt;     Then I should find &amp;quot;nestor \d+\.\d+\.\d+&amp;quot;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;After writing those, I ran them:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; ~/nestor (master) $ rake features
&lt;span class="no"&gt; 2&lt;/span&gt; (in /Users/francois/nestor)
&lt;span class="no"&gt; 3&lt;/span&gt; ...F
&lt;span class="no"&gt; 4&lt;/span&gt; 
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt; 6&lt;/span&gt; Failed:
&lt;span class="no"&gt; 7&lt;/span&gt; 
&lt;span class="no"&gt; 8&lt;/span&gt; 1)
&lt;span class="no"&gt; 9&lt;/span&gt; &amp;lt;&amp;quot;nestor: version unknown\n&amp;quot;&amp;gt; expected to be =~
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; &amp;lt;/nestor \d+\.\d+\.\d+/&amp;gt;.
&lt;span class="no"&gt;11&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/test/unit/assertions.rb:48:in `assert_block'
&lt;span class="no"&gt;12&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/test/unit/assertions.rb:500:in `_wrap_assertion'
&lt;span class="no"&gt;13&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/test/unit/assertions.rb:46:in `assert_block'
&lt;span class="no"&gt;14&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/test/unit/assertions.rb:229:in `assert_match'
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/test/unit/assertions.rb:495:in `_wrap_assertion'
&lt;span class="no"&gt;16&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/1.8/test/unit/assertions.rb:221:in `assert_match'
&lt;span class="no"&gt;17&lt;/span&gt; ./features/step_definitions/assertions.rb:8:in `Then /^I should find &amp;quot;(.*)&amp;quot;$/'
&lt;span class="no"&gt;18&lt;/span&gt; features/command_line_client.feature:13:in `Then I should find &amp;quot;nestor \d+\.\d+\.\d+&amp;quot;'
&lt;span class="no"&gt;19&lt;/span&gt; rake aborted!
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt; Command failed with status (1): [/System/Library/Frameworks/Ruby.framework/...]
&lt;span class="no"&gt;21&lt;/span&gt; 
&lt;span class="no"&gt;22&lt;/span&gt; (See full trace by running task with --trace)

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Haha!  So, Cucumber caught the fact that newgem didn&amp;#8217;t set the new gem to return the version number immediately! Interesting.&lt;/p&gt;
&lt;p&gt;Anyway, here are my step definitions, for the curious:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;features/support/env.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; require &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;test/unit&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt; 
&lt;span class="no"&gt;3&lt;/span&gt; &lt;span class="co"&gt;World&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt;4&lt;/span&gt;   include &lt;span class="co"&gt;Test&lt;/span&gt;::&lt;span class="co"&gt;Unit&lt;/span&gt;::&lt;span class="co"&gt;Assertions&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="code"&gt;
&lt;h5&gt;features/step_definitions/nestor.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="co"&gt;When&lt;/span&gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;^I start nestor with &amp;quot;(.*)&amp;quot;$&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |args|
&lt;span class="no"&gt;2&lt;/span&gt;   &lt;span class="sh"&gt;&lt;span class="dl"&gt;%x&amp;quot;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;NESTOR_APP_ROOT&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;/bin/nestor &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;args&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; &amp;gt; &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;NESTOR_LOG_ROOT&lt;/span&gt;&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;/nestor.log 2&amp;gt;&amp;amp;1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;3&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="code"&gt;
&lt;h5&gt;features/step_definitions/assertions.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="co"&gt;Then&lt;/span&gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;^I should see &amp;quot;(.*)&amp;quot;$&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |data|
&lt;span class="no"&gt; 2&lt;/span&gt;   stdout = &lt;span class="co"&gt;File&lt;/span&gt;.read(&lt;span class="co"&gt;File&lt;/span&gt;.join(&lt;span class="co"&gt;NESTOR_LOG_ROOT&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;nestor.log&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;))
&lt;span class="no"&gt; 3&lt;/span&gt;   assert_match &lt;span class="co"&gt;Regexp&lt;/span&gt;.new(&lt;span class="co"&gt;Regexp&lt;/span&gt;.escape(data)), stdout
&lt;span class="no"&gt; 4&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt; 6&lt;/span&gt; &lt;span class="co"&gt;Then&lt;/span&gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;^I should find &amp;quot;(.*)&amp;quot;$&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |regexp|
&lt;span class="no"&gt; 7&lt;/span&gt;   stdout = &lt;span class="co"&gt;File&lt;/span&gt;.read(&lt;span class="co"&gt;File&lt;/span&gt;.join(&lt;span class="co"&gt;NESTOR_LOG_ROOT&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;nestor.log&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;))
&lt;span class="no"&gt; 8&lt;/span&gt;   assert_match &lt;span class="co"&gt;Regexp&lt;/span&gt;.new(regexp), stdout
&lt;span class="no"&gt; 9&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Notice that I really run the nestor binary to assert against the gem&amp;#8217;s STDOUT.  Redirecting the output to a log file I can open and search in really makes things easier.  I had a bit of difficulty wrapping my head around this idea (of starting the binary from Cucumber), so I hope that helps other people too.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/GiETrAefekY" height="1" width="1"/&gt;</content>
      </entry>
  <entry>
    <title>I Seem to Have Broken My RubyGems?</title>
    <link href="http://blog.teksol.info/2009/01/16/i-seem-to-have-broken-my-rubygems.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-01-16:20090116164305</id>
    <updated>2009-01-16T16:43:05-05:00</updated>
    <content type="html">&lt;p&gt;I really don&amp;#8217;t know how I did this.  I&amp;#8217;d like to say it&amp;#8217;s the &lt;a href="http://www.imdb.com/title/tt0087363/"&gt;Gremlins&lt;/a&gt; in the machine, but it must be some kind of human error.&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; ~ $ gem --version
&lt;span class="no"&gt; 2&lt;/span&gt; 1.2.0
&lt;span class="no"&gt; 3&lt;/span&gt; ~ $ gem env
&lt;span class="no"&gt; 4&lt;/span&gt; RubyGems Environment:
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;   - RUBYGEMS VERSION: 1.2.0
&lt;span class="no"&gt; 6&lt;/span&gt;   - RUBY VERSION: 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0]
&lt;span class="no"&gt; 7&lt;/span&gt;   - INSTALLATION DIRECTORY: /Library/Ruby/Gems/1.8
&lt;span class="no"&gt; 8&lt;/span&gt;   - RUBY EXECUTABLE: /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
&lt;span class="no"&gt; 9&lt;/span&gt;   - EXECUTABLE DIRECTORY: /usr/bin
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   - RUBYGEMS PLATFORMS:
&lt;span class="no"&gt;11&lt;/span&gt;     - ruby
&lt;span class="no"&gt;12&lt;/span&gt;     - universal-darwin-9
&lt;span class="no"&gt;13&lt;/span&gt;   - GEM PATHS:
&lt;span class="no"&gt;14&lt;/span&gt;      - /Library/Ruby/Gems/1.8
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt;      - /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/lib/ruby/gems/1.8
&lt;span class="no"&gt;16&lt;/span&gt;   - GEM CONFIGURATION:
&lt;span class="no"&gt;17&lt;/span&gt;      - :update_sources =&amp;gt; true
&lt;span class="no"&gt;18&lt;/span&gt;      - :verbose =&amp;gt; true
&lt;span class="no"&gt;19&lt;/span&gt;      - :benchmark =&amp;gt; false
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt;      - :backtrace =&amp;gt; false
&lt;span class="no"&gt;21&lt;/span&gt;      - :bulk_threshold =&amp;gt; 1000
&lt;span class="no"&gt;22&lt;/span&gt;      - &amp;quot;install&amp;quot; =&amp;gt; &amp;quot;--env-shebang&amp;quot;
&lt;span class="no"&gt;23&lt;/span&gt;      - &amp;quot;update&amp;quot; =&amp;gt; &amp;quot;--env-shebang&amp;quot;
&lt;span class="no"&gt;24&lt;/span&gt;      - :sources =&amp;gt; [&amp;quot;http://gems.rubyforge.org&amp;quot;, &amp;quot;http://gems.github.com/&amp;quot;]
&lt;span class="no"&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;/span&gt;   - REMOTE SOURCES:
&lt;span class="no"&gt;26&lt;/span&gt;      - http://gems.rubyforge.org
&lt;span class="no"&gt;27&lt;/span&gt;      - http://gems.github.com/
&lt;span class="no"&gt;28&lt;/span&gt; ~ $ sudo gem update --system
&lt;span class="no"&gt;29&lt;/span&gt; Password:
&lt;span class="no"&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;/span&gt; Updating RubyGems
&lt;span class="no"&gt;31&lt;/span&gt; Nothing to update
&lt;span class="no"&gt;32&lt;/span&gt; ~ $ rails newapp
&lt;span class="no"&gt;33&lt;/span&gt;       create  
&lt;span class="no"&gt;34&lt;/span&gt;       create  app/controllers
&lt;span class="no"&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;/span&gt;       ...
&lt;span class="no"&gt;36&lt;/span&gt;       create  log/test.log
&lt;span class="no"&gt;37&lt;/span&gt; ~ $ cd newapp/
&lt;span class="no"&gt;38&lt;/span&gt; ~/newapp $ script/generate model person
&lt;span class="no"&gt;39&lt;/span&gt; Rails requires RubyGems &amp;gt;= 1.3.1 (you have 1.2.0). Please `gem update --system` and try again.
&lt;span class="no"&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt;41&lt;/span&gt; $ ls -d /Library/Ruby/Gems/1.8/gems/rubygems*
&lt;span class="no"&gt;42&lt;/span&gt; /Library/Ruby/Gems/1.8/gems/rubygems-update-1.2.0  /Library/Ruby/Gems/1.8/gems/rubygems-update-1.3.1
&lt;span class="no"&gt;43&lt;/span&gt; /Library/Ruby/Gems/1.8/gems/rubygems-update-1.3.0

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;What&amp;#8217;s going on?  Anybody has an idea?  A quick Google search didn&amp;#8217;t turn up anything interesting.  Probably I&amp;#8217;m not searching for the right thing.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/CS-FhUQLzPE" height="1" width="1"/&gt;</content>
    
    <category term="strange" label="Strange" />
      </entry>
  <entry>
    <title>Productivity Tip: A Simple Change to ~/.bash_profile</title>
    <link href="http://blog.teksol.info/2009/01/12/productivity-tip-a-simple-change-to.html" type="text/html" />
    <id>tag:blog.teksol.info,2009-01-12:20090112101612</id>
    <updated>2009-01-12T10:16:12-05:00</updated>
    <content type="html">&lt;p&gt;I put everything I code into &lt;code class="dir"&gt;~/Documents/work&lt;/code&gt;.  Could be called projects, same thing.  Anyway, everytime I opened Terminal, I would have to type &lt;code class="dir"&gt;cd Documents/work&lt;/code&gt;.  Of course, with tab completion, it&amp;#8217;s not so bad.  I&amp;#8217;m a bit stupid though, and it takes me eons before I added &lt;code class="dir"&gt;cd ~/Documents/work&lt;/code&gt; to the end of my &lt;code class="path"&gt;~/.bash_profile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Whenever I open a Terminal, I&amp;#8217;m really going to start doing something in this folder.  Now, why didn&amp;#8217;t I think of that earlier?  Next: retrain myself to not cd anywhere when I open a new Terminal&amp;hellip;&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s my full &lt;code class="path"&gt;~/.bash_profile:&lt;/code&gt;&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;~/.bash_profile&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; #!/usr/bin/sh
&lt;span class="no"&gt; 2&lt;/span&gt; 
&lt;span class="no"&gt; 3&lt;/span&gt; # Installed by Git OSX Installer from
&lt;span class="no"&gt; 4&lt;/span&gt; # http://code.google.com/p/git-osx-installer/
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home
&lt;span class="no"&gt; 6&lt;/span&gt; export ANT_HOME=/usr/share/ant
&lt;span class="no"&gt; 7&lt;/span&gt; export JRUBY_HOME=~/Library/Java/JRuby/current
&lt;span class="no"&gt; 8&lt;/span&gt; export MYSQL_PATH=/usr/local/mysql
&lt;span class="no"&gt; 9&lt;/span&gt; export PATH=~/bin:/opt/local/sphinx/bin:/usr/local/git/bin:$MYSQL_PATH/bin:$PATH:$JRUBY_HOME/bin
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; export MANPATH=/usr/local/git/man:$MANPATH
&lt;span class="no"&gt;11&lt;/span&gt; export EDITOR=vim
&lt;span class="no"&gt;12&lt;/span&gt; 
&lt;span class="no"&gt;13&lt;/span&gt; # And this is from:
&lt;span class="no"&gt;14&lt;/span&gt; # http://code.google.com/p/git-osx-installer/
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt; export PS1='\w$(git branch &amp;amp;&amp;gt;/dev/null; if [ $? -eq 0 ]; then echo &amp;quot; (\[\033[00m\]$(git branch | grep ^*|sed s/\*\ //))&amp;quot;; fi) \$\[\033[00m\] '
&lt;span class="no"&gt;16&lt;/span&gt; 
&lt;span class="no"&gt;17&lt;/span&gt; export VISUALWORKS=~/Applications/vw7.6nc
&lt;span class="no"&gt;18&lt;/span&gt; export AWS_ACCESS_KEY_ID= # your AWS access key, for cliaws gem
&lt;span class="no"&gt;19&lt;/span&gt; export AWS_SECRET_ACCESS_KEY= # your AWS secret access key, for cliaws gem again
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt;21&lt;/span&gt; # http://www.macosxhints.com/article.php?story=20060502160527780&amp;amp;query=terminal%2Btitle
&lt;span class="no"&gt;22&lt;/span&gt; function settitle() { echo -ne &amp;quot;\e]2;$@\a\e]1;$@\a&amp;quot;; }
&lt;span class="no"&gt;23&lt;/span&gt; 
&lt;span class="no"&gt;24&lt;/span&gt; if [ -f ~/.bash_aliases ]; then
&lt;span class="no"&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;/span&gt;   source ~/.bash_aliases
&lt;span class="no"&gt;26&lt;/span&gt; fi
&lt;span class="no"&gt;27&lt;/span&gt; 
&lt;span class="no"&gt;28&lt;/span&gt; cd ~/Documents/work

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/PUQesjXKWnE" height="1" width="1"/&gt;</content>
    
    <category term="tips" label="Tips" />
      </entry>
  <entry>
    <title>MySQL's MEMORY Engine Barely Faster than InnoDB's?</title>
    <link href="http://blog.teksol.info/2008/12/12/mysqls-memory-engine-barely-faster-than-innodbs.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-12-12:20081212080423</id>
    <updated>2008-12-12T08:04:23-05:00</updated>
    <content type="html">&lt;p&gt;Yesterday, I read &lt;a href="http://cardarella.blogspot.com/2008/12/case-against-mocking-and-stubbing.html"&gt;Brian Cardarella&lt;/a&gt;&amp;#8216;s post entitled &lt;a href="http://cardarella.blogspot.com/"&gt;Brian Cardarella&lt;/a&gt;&amp;#8217;s post entitled &lt;a href="http://cardarella.blogspot.com/2008/12/case-against-mocking-and-stubbing.html"&gt;A case against Mocking and Stubbing&lt;/a&gt;.  In the article, Brian says:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;SQLite3 can be an in-memory database. Problem solved, right? Not quite. SQLite3 is pretty limited. Most people are probably using MySQL and rely upon many of the SQL functions that are included.&lt;/p&gt; 
&lt;p&gt; What would be nice (and well beyond my ability) is to have a Gem that simulated the database you use, only it is in-memory. Optimized for small data sets. No need to go through a heavy hashing algorithm. Keep it light. Keep it fast.&lt;/p&gt;
&lt;p class="signature"&gt;Brian Cardarella in &lt;a href="http://cardarella.blogspot.com/2008/12/case-against-mocking-and-stubbing.html"&gt;A case against Mocking and Stubbing&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;MySQL already has the &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/memory-storage-engine.html"&gt;MEMORY&lt;/a&gt; storage engine, and I wanted to see if that would help for testing purposes.  Since we&amp;#8217;re staying in MySQL-land, this should have been a simple matter.&lt;/p&gt;
&lt;p&gt;First, the good news.  I had to change only a couple of lines:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; diff --git a/vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/vendor/rails/activerecor
&lt;span class="no"&gt; 2&lt;/span&gt; index 1e452ae..c207080 100644
&lt;span class="no"&gt; 3&lt;/span&gt; --- a/vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
&lt;span class="no"&gt; 4&lt;/span&gt; +++ b/vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; @@ -442,7 +442,13 @@ module ActiveRecord
&lt;span class="no"&gt; 6&lt;/span&gt;        end
&lt;span class="no"&gt; 7&lt;/span&gt;  
&lt;span class="no"&gt; 8&lt;/span&gt;        def create_table(table_name, options = {}) #:nodoc:
&lt;span class="no"&gt; 9&lt;/span&gt; -        super(table_name, options.reverse_merge(:options =&amp;gt; &amp;quot;ENGINE=InnoDB&amp;quot;))
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; +        engine = case Rails.env
&lt;span class="no"&gt;11&lt;/span&gt; +        when &amp;quot;test&amp;quot;
&lt;span class="no"&gt;12&lt;/span&gt; +          &amp;quot;MEMORY&amp;quot;
&lt;span class="no"&gt;13&lt;/span&gt; +        else
&lt;span class="no"&gt;14&lt;/span&gt; +          &amp;quot;InnoDB&amp;quot;
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt; +        end
&lt;span class="no"&gt;16&lt;/span&gt; +        super(table_name, options.reverse_merge(:options =&amp;gt; &amp;quot;ENGINE=#{engine}&amp;quot;))
&lt;span class="no"&gt;17&lt;/span&gt;        end
&lt;span class="no"&gt;18&lt;/span&gt;  
&lt;span class="no"&gt;19&lt;/span&gt;        def rename_table(table_name, new_name)
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt; diff --git a/vendor/rails/railties/lib/tasks/databases.rake b/vendor/rails/railties/lib/tasks/databases.rake
&lt;span class="no"&gt;21&lt;/span&gt; index 5cb27f1..c520d4a 100644
&lt;span class="no"&gt;22&lt;/span&gt; --- a/vendor/rails/railties/lib/tasks/databases.rake
&lt;span class="no"&gt;23&lt;/span&gt; +++ b/vendor/rails/railties/lib/tasks/databases.rake
&lt;span class="no"&gt;24&lt;/span&gt; @@ -368,9 +368,9 @@ namespace :db do
&lt;span class="no"&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;/span&gt;  
&lt;span class="no"&gt;26&lt;/span&gt;      desc 'Check for pending migrations and load the test schema'
&lt;span class="no"&gt;27&lt;/span&gt;      task :prepare =&amp;gt; 'db:abort_if_pending_migrations' do
&lt;span class="no"&gt;28&lt;/span&gt; -      if defined?(ActiveRecord) &amp;amp;&amp;amp; !ActiveRecord::Base.configurations.blank?
&lt;span class="no"&gt;29&lt;/span&gt; -        Rake::Task[{ :sql  =&amp;gt; &amp;quot;db:test:clone_structure&amp;quot;, :ruby =&amp;gt; &amp;quot;db:test:load&amp;quot; }[ActiveRecord::Base.schema_format]].i
&lt;span class="no"&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;/span&gt; -      end
&lt;span class="no"&gt;31&lt;/span&gt; +      # if defined?(ActiveRecord) &amp;amp;&amp;amp; !ActiveRecord::Base.configurations.blank?
&lt;span class="no"&gt;32&lt;/span&gt; +      #   Rake::Task[{ :sql  =&amp;gt; &amp;quot;db:test:clone_structure&amp;quot;, :ruby =&amp;gt; &amp;quot;db:test:load&amp;quot; }[ActiveRecord::Base.schema_format]]
&lt;span class="no"&gt;33&lt;/span&gt; +      # end
&lt;span class="no"&gt;34&lt;/span&gt;      end
&lt;span class="no"&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;/span&gt;    end
&lt;span class="no"&gt;36&lt;/span&gt;  

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Great, but there&amp;#8217;s little benefit.  First, a regular run (InnoDB):&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; $ time rake
&lt;span class="no"&gt; 2&lt;/span&gt; (in /Users/francois/Documents/work/fasttest)
&lt;span class="no"&gt; 3&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -Ilib:test &amp;quot;/Library/Ruby/Gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader.rb&amp;quot; &amp;quot;test/unit/password_reset_mailer_test.rb&amp;quot; &amp;quot;test/unit/person_test.rb&amp;quot; 
&lt;span class="no"&gt; 4&lt;/span&gt; Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; Started
&lt;span class="no"&gt; 6&lt;/span&gt; ............................
&lt;span class="no"&gt; 7&lt;/span&gt; Finished in 0.520087 seconds.
&lt;span class="no"&gt; 8&lt;/span&gt; 
&lt;span class="no"&gt; 9&lt;/span&gt; 28 tests, 33 assertions, 0 failures, 0 errors
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -Ilib:test &amp;quot;/Library/Ruby/Gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader.rb&amp;quot; &amp;quot;test/functional/accounts_controller_test.rb&amp;quot; &amp;quot;test/functional/password_resets_controller_test.rb&amp;quot; &amp;quot;test/functional/people_controller_test.rb&amp;quot; &amp;quot;test/functional/sessions_controller_test.rb&amp;quot; 
&lt;span class="no"&gt;11&lt;/span&gt; [DEPRECATION] should_be_restful is deprecated.  Please see http://thoughtbot.lighthouseapp.com/projects/5807/tickets/78 for more information.
&lt;span class="no"&gt;12&lt;/span&gt; [DEPRECATION] should_be_restful is deprecated.  Please see http://thoughtbot.lighthouseapp.com/projects/5807/tickets/78 for more information.
&lt;span class="no"&gt;13&lt;/span&gt; Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader
&lt;span class="no"&gt;14&lt;/span&gt; Started
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt; .....................................................
&lt;span class="no"&gt;16&lt;/span&gt; Finished in 1.828175 seconds.
&lt;span class="no"&gt;17&lt;/span&gt; 
&lt;span class="no"&gt;18&lt;/span&gt; 53 tests, 72 assertions, 0 failures, 0 errors
&lt;span class="no"&gt;19&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -Ilib:test &amp;quot;/Library/Ruby/Gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader.rb&amp;quot;  
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt;21&lt;/span&gt; real  0m10.365s
&lt;span class="no"&gt;22&lt;/span&gt; user  0m6.582s
&lt;span class="no"&gt;23&lt;/span&gt; sys  0m1.925s

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Next, a run with the MEMORY engine:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; $ time rake
&lt;span class="no"&gt; 2&lt;/span&gt; (in /Users/francois/Documents/work/fasttest)
&lt;span class="no"&gt; 3&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -Ilib:test &amp;quot;/Library/Ruby/Gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader.rb&amp;quot; &amp;quot;test/unit/password_reset_mailer_test.rb&amp;quot; &amp;quot;test/unit/person_test.rb&amp;quot; 
&lt;span class="no"&gt; 4&lt;/span&gt; Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; Started
&lt;span class="no"&gt; 6&lt;/span&gt; ............................
&lt;span class="no"&gt; 7&lt;/span&gt; Finished in 0.602607 seconds.
&lt;span class="no"&gt; 8&lt;/span&gt; 
&lt;span class="no"&gt; 9&lt;/span&gt; 28 tests, 33 assertions, 0 failures, 0 errors
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -Ilib:test &amp;quot;/Library/Ruby/Gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader.rb&amp;quot; &amp;quot;test/functional/accounts_controller_test.rb&amp;quot; &amp;quot;test/functional/password_resets_controller_test.rb&amp;quot; &amp;quot;test/functional/people_controller_test.rb&amp;quot; &amp;quot;test/functional/sessions_controller_test.rb&amp;quot; 
&lt;span class="no"&gt;11&lt;/span&gt; [DEPRECATION] should_be_restful is deprecated.  Please see http://thoughtbot.lighthouseapp.com/projects/5807/tickets/78 for more information.
&lt;span class="no"&gt;12&lt;/span&gt; [DEPRECATION] should_be_restful is deprecated.  Please see http://thoughtbot.lighthouseapp.com/projects/5807/tickets/78 for more information.
&lt;span class="no"&gt;13&lt;/span&gt; Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader
&lt;span class="no"&gt;14&lt;/span&gt; Started
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt; .....................................................
&lt;span class="no"&gt;16&lt;/span&gt; Finished in 1.132142 seconds.
&lt;span class="no"&gt;17&lt;/span&gt; 
&lt;span class="no"&gt;18&lt;/span&gt; 53 tests, 72 assertions, 0 failures, 0 errors
&lt;span class="no"&gt;19&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -Ilib:test &amp;quot;/Library/Ruby/Gems/1.8/gems/rake-0.8.3/lib/rake/rake_test_loader.rb&amp;quot;  
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt;21&lt;/span&gt; real  0m9.111s
&lt;span class="no"&gt;22&lt;/span&gt; user  0m6.862s
&lt;span class="no"&gt;23&lt;/span&gt; sys  0m1.870s

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Note that in &lt;code class="filename"&gt;test/test_helper.rb&lt;/code&gt;, I had to disable transactional fixtures.  This would account for a lot the lost time difference.&lt;/p&gt;
&lt;p&gt;If you want to play with this further, the sample application&amp;#8217;s code is available at &lt;a href="http://github.com/francois/fasttest"&gt;http://github.com/francois/fasttest&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I would be interested in seeing other people&amp;#8217;s runs, to know if it&amp;#8217;s just my machine that runs at essentially the same speed.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/kKPB8thmOpI" height="1" width="1"/&gt;</content>
    
    <category term="activerecord" label="Activerecord" />
    
    <category term="unit-testing" label="Unit-testing" />
      </entry>
  <entry>
    <title>How to Use AlterEgo With ActiveRecord</title>
    <link href="http://blog.teksol.info/2008/12/09/how-to-use-alterego-with-activerecord.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-12-09:20081209095217</id>
    <updated>2008-12-09T09:52:17-05:00</updated>
    <content type="html">&lt;p&gt;I stumbled on &lt;a href="http://alter-ego.rubyforge.org/"&gt;AlterEgo&lt;/a&gt; last week, after Avdi announced it.  This library implements the &lt;a href="http://en.wikipedia.org/wiki/State_pattern"&gt;state pattern&lt;/a&gt; for any object, not just ActiveRecord models, which &lt;a href="http://agilewebdevelopment.com/plugins/acts_as_state_machine"&gt;acts_as_state_machine&lt;/a&gt; (and it&amp;#8217;s successor, &lt;a href="http://github.com/rubyist/aasm"&gt;aasm&lt;/a&gt;) do.&lt;/p&gt;
&lt;p&gt;But, many people, myself included, want to use AlterEgo in the context of ActiveRecord models.  Fortunately, AlterEgo provides us with all the necessary plumbing to do that very easily.&lt;/p&gt;
&lt;p&gt;I will reuse Avdi&amp;#8217;s traffic light example from the specifications.  Avdi already points us to 90% of the solution in his example:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;TrafficLightWithCustomStorage&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;state&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     gyr = [
&lt;span class="no"&gt; 4&lt;/span&gt;       &lt;span class="iv"&gt;@hardware_controller&lt;/span&gt;.green,
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;       &lt;span class="iv"&gt;@hardware_controller&lt;/span&gt;.yellow,
&lt;span class="no"&gt; 6&lt;/span&gt;       &lt;span class="iv"&gt;@hardware_controller&lt;/span&gt;.red
&lt;span class="no"&gt; 7&lt;/span&gt;     ]
&lt;span class="no"&gt; 8&lt;/span&gt; 
&lt;span class="no"&gt; 9&lt;/span&gt;     &lt;span class="r"&gt;case&lt;/span&gt; gyr
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;     &lt;span class="r"&gt;when&lt;/span&gt; [&lt;span class="pc"&gt;true&lt;/span&gt;, &lt;span class="pc"&gt;false&lt;/span&gt;, &lt;span class="pc"&gt;false&lt;/span&gt;] &lt;span class="r"&gt;then&lt;/span&gt; &lt;span class="sy"&gt;:proceed&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt;     &lt;span class="r"&gt;when&lt;/span&gt; [&lt;span class="pc"&gt;false&lt;/span&gt;, &lt;span class="pc"&gt;true&lt;/span&gt;, &lt;span class="pc"&gt;false&lt;/span&gt;] &lt;span class="r"&gt;then&lt;/span&gt; &lt;span class="sy"&gt;:caution&lt;/span&gt;
&lt;span class="no"&gt;12&lt;/span&gt;     &lt;span class="r"&gt;when&lt;/span&gt; [&lt;span class="pc"&gt;false&lt;/span&gt;, &lt;span class="pc"&gt;false&lt;/span&gt;, &lt;span class="pc"&gt;true&lt;/span&gt;] &lt;span class="r"&gt;then&lt;/span&gt; &lt;span class="sy"&gt;:stop&lt;/span&gt;
&lt;span class="no"&gt;13&lt;/span&gt;     &lt;span class="r"&gt;else&lt;/span&gt; raise &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Invalid state!&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;14&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;16&lt;/span&gt; 
&lt;span class="no"&gt;17&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;state=&lt;/span&gt;(value)
&lt;span class="no"&gt;18&lt;/span&gt;     gyr = &lt;span class="r"&gt;case&lt;/span&gt; value
&lt;span class="no"&gt;19&lt;/span&gt;           &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="sy"&gt;:proceed&lt;/span&gt;  &lt;span class="r"&gt;then&lt;/span&gt; [&lt;span class="pc"&gt;true&lt;/span&gt;, &lt;span class="pc"&gt;false&lt;/span&gt;, &lt;span class="pc"&gt;false&lt;/span&gt;]
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt;           &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="sy"&gt;:caution&lt;/span&gt;  &lt;span class="r"&gt;then&lt;/span&gt; [&lt;span class="pc"&gt;false&lt;/span&gt;, &lt;span class="pc"&gt;true&lt;/span&gt;, &lt;span class="pc"&gt;false&lt;/span&gt;]
&lt;span class="no"&gt;21&lt;/span&gt;           &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="sy"&gt;:stop&lt;/span&gt;     &lt;span class="r"&gt;then&lt;/span&gt; [&lt;span class="pc"&gt;false&lt;/span&gt;, &lt;span class="pc"&gt;false&lt;/span&gt;, &lt;span class="pc"&gt;true&lt;/span&gt;]
&lt;span class="no"&gt;22&lt;/span&gt;           &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;23&lt;/span&gt;     &lt;span class="iv"&gt;@hardware_controller&lt;/span&gt;.green  = gyr[&lt;span class="i"&gt;0&lt;/span&gt;]
&lt;span class="no"&gt;24&lt;/span&gt;     &lt;span class="iv"&gt;@hardware_controller&lt;/span&gt;.yellow = gyr[&lt;span class="i"&gt;1&lt;/span&gt;]
&lt;span class="no"&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;/span&gt;     &lt;span class="iv"&gt;@hardware_controller&lt;/span&gt;.red    = gyr[&lt;span class="i"&gt;2&lt;/span&gt;]
&lt;span class="no"&gt;26&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;27&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;When an object implements #state and #state=, AlterEgo will serialize it&amp;#8217;s state using these two methods.  Let&amp;#8217;s hook this to ActiveRecord (note, I changed the code for a quick example, so it&amp;#8217;s not exactly the same, but very similar):&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;app/models/traffic_light.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;TrafficLight&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;Base&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;state&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     &lt;span class="r"&gt;case&lt;/span&gt; read_attribute(&lt;span class="sy"&gt;:color&lt;/span&gt;)
&lt;span class="no"&gt; 4&lt;/span&gt;     &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;green&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;   &lt;span class="sy"&gt;:proceed&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;     &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;yellow&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;  &lt;span class="sy"&gt;:caution&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;     &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;;     &lt;span class="sy"&gt;:stop&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt;     &lt;span class="r"&gt;else&lt;/span&gt;;           raise &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Invalid color: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;read_attribute(&lt;span class="sy"&gt;:color&lt;/span&gt;).inspect&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 8&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; 9&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt;11&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;state=&lt;/span&gt;(value)
&lt;span class="no"&gt;12&lt;/span&gt;     color_value = &lt;span class="r"&gt;case&lt;/span&gt; value
&lt;span class="no"&gt;13&lt;/span&gt;     &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="sy"&gt;:proceed&lt;/span&gt;;  &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;green&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;14&lt;/span&gt;     &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="sy"&gt;:caution&lt;/span&gt;;  &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;yellow&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt;     &lt;span class="r"&gt;when&lt;/span&gt; &lt;span class="sy"&gt;:stop&lt;/span&gt;;     &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;16&lt;/span&gt;     &lt;span class="r"&gt;else&lt;/span&gt;;           raise &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Don't know how to convert &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;value.inspect&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; to color value&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;17&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;18&lt;/span&gt;     write_attribute(&lt;span class="sy"&gt;:color&lt;/span&gt;, color_value)
&lt;span class="no"&gt;19&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;The most important thing you should check is that your database model has a valid state on model instantiation.  Whether you do it using the :default key in your migration or some other way is irrelevant, but the value has to be provided, or the #state method will barf (or implement default processing there?)  In the example app, I opted to use a default value:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;db/migrate/20081209150159_create_traffic_lights.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;CreateTrafficLights&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveRecord&lt;/span&gt;::&lt;span class="co"&gt;Migration&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.up
&lt;span class="no"&gt; 3&lt;/span&gt;     create_table &lt;span class="sy"&gt;:traffic_lights&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |t|
&lt;span class="no"&gt; 4&lt;/span&gt;       t.string &lt;span class="sy"&gt;:color&lt;/span&gt;, &lt;span class="sy"&gt;:default&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;red&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt; 
&lt;span class="no"&gt; 8&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.down
&lt;span class="no"&gt; 9&lt;/span&gt;     drop_table &lt;span class="sy"&gt;:traffic_lights&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;You may check the full code in action in the GitHub repository:  &lt;a href="http://github.com/francois/alter_ego_plus_active_record"&gt;alter_ego_plus_active_record&lt;/a&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/BxgwMiGGhc8" height="1" width="1"/&gt;</content>
    
    <category term="active-record" label="Active-record" />
    
    <category term="alter-ego" label="Alter-ego" />
      </entry>
  <entry>
    <title>A Simple LinkedList Implementation in Ruby</title>
    <link href="http://blog.teksol.info/2008/11/11/a-simple-linkedlist-implementation-in-ruby.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-11-11:20081111144031</id>
    <updated>2008-11-11T14:40:31-05:00</updated>
    <content type="html">&lt;p&gt;Being bored out of my mind on Monday night, and not having anything interesting to watch on TV, I decided I&amp;#8217;d try my hand at implementing a linked list in Ruby.  For the impatient:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; $ sudo gem install linked_list

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Unfortunately, performance is very poor:&lt;/p&gt;
&lt;pre&gt;Building a list of 1 million random strings
Took 4.389 seconds
Converting to an array
Took 1.686 seconds
                      user     system      total        real
list#push/pop     0.350000   0.000000   0.350000 (  0.364001)
array#push/pop    0.000000   0.000000   0.000000 (  0.009894)
                      user     system      total        real
list#last         0.000000   0.000000   0.000000 (  0.000027)
array#last        0.000000   0.000000   0.000000 (  0.000012)
                      user     system      total        real
list#first        0.010000   0.000000   0.010000 (  0.001188)
array#first       0.000000   0.000000   0.000000 (  0.000449)
                      user     system      total        real
list#reverse      7.540000   0.170000   7.710000 (  7.806306)
array#reverse     0.010000   0.010000   0.020000 (  0.008443)
                      user     system      total        real
list#dup         23.080000   0.380000  23.460000 ( 24.039316)
array#dup         0.000000   0.000000   0.000000 (  0.000017)
&lt;/pre&gt;
&lt;p&gt;NOTE:  &lt;code&gt;#dup&lt;/code&gt; is implemented as &lt;code&gt;self.reverse.reverse&lt;/code&gt;, which is pretty inefficient, I know.  Thanks for asking.&lt;/p&gt;
&lt;p&gt;I probably have implementation issues, but I expected &lt;code&gt;#push&lt;/code&gt; and &lt;code&gt;#pop&lt;/code&gt; to be as fast as the Array implementation.  Anyway, if anyone&amp;#8217;s interested, there&amp;#8217;s a &lt;a href="http://github.com/francois/linked_list/tree/master"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/hvF3B_1CZmo" height="1" width="1"/&gt;</content>
      </entry>
  <entry>
    <title>FAIL: Can't Migrate Because Pending Migrations..</title>
    <link href="http://blog.teksol.info/2008/11/02/fail-cant-migrate-because-pending-migrations-dot.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-11-02:20081102210655</id>
    <updated>2008-11-02T21:06:55-05:00</updated>
    <content type="html">&lt;p&gt;How&amp;#8217;s that for being helpful?&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; $ rake db:migrate --trace
&lt;span class="no"&gt; 2&lt;/span&gt; (in /Users/francois/Documents/work/family_budget)
&lt;span class="no"&gt; 3&lt;/span&gt; ** Invoke db:test:prepare (first_time)
&lt;span class="no"&gt; 4&lt;/span&gt; ** Invoke environment (first_time)
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; ** Execute environment
&lt;span class="no"&gt; 6&lt;/span&gt; ** Invoke db:abort_if_pending_migrations (first_time)
&lt;span class="no"&gt; 7&lt;/span&gt; ** Invoke environment 
&lt;span class="no"&gt; 8&lt;/span&gt; ** Execute db:abort_if_pending_migrations
&lt;span class="no"&gt; 9&lt;/span&gt; You have 13 pending migrations:
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;      1 CreateFamilies
&lt;span class="no"&gt;11&lt;/span&gt;      2 CreatePeople
&lt;span class="no"&gt;12&lt;/span&gt;      3 CreateAccounts
&lt;span class="no"&gt;13&lt;/span&gt;      4 CreateTransfers
&lt;span class="no"&gt;14&lt;/span&gt;      5 CreateTransferMembers
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt;      6 AddFamilyToPeople
&lt;span class="no"&gt;16&lt;/span&gt;      7 DestroyTransferMember
&lt;span class="no"&gt;17&lt;/span&gt;      8 AddDebitAccountIdCreditAccountIdAndAmountToTransfers
&lt;span class="no"&gt;18&lt;/span&gt;      9 CreateBudgets
&lt;span class="no"&gt;19&lt;/span&gt;     10 AddAdminFlagToPerson
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt;     11 DefaultBudgetAmountToZeroFromNull
&lt;span class="no"&gt;21&lt;/span&gt;   20081103020010 CreateTransactions
&lt;span class="no"&gt;22&lt;/span&gt;   20081103020142 CreateBankAccounts
&lt;span class="no"&gt;23&lt;/span&gt; Run &amp;quot;rake db:migrate&amp;quot; to update your database then try again.

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Hmm, I&amp;#8217;m trying to run migrations, stupid&amp;hellip;&lt;/p&gt;
&lt;p&gt;I finally traced the problem (using &lt;a href="http://linux.die.net/man/1/git-bisect"&gt;git bisect&lt;/a&gt; !) to this:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;lib/tasks/cucumber.rake&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="gv"&gt;$:&lt;/span&gt;.unshift(&lt;span class="co"&gt;RAILS_ROOT&lt;/span&gt; + &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;/vendor/plugins/cucumber/lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="no"&gt; 2&lt;/span&gt; require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;cucumber/rake/task&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt; 
&lt;span class="no"&gt; 4&lt;/span&gt; namespace &lt;span class="sy"&gt;:test&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;   desc &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Runs the Cucumber features tests (integration tests)&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;   &lt;span class="co"&gt;Cucumber&lt;/span&gt;::&lt;span class="co"&gt;Rake&lt;/span&gt;::&lt;span class="co"&gt;Task&lt;/span&gt;.new(&lt;span class="sy"&gt;:features&lt;/span&gt;) &lt;span class="r"&gt;do&lt;/span&gt; |t|
&lt;span class="no"&gt; 7&lt;/span&gt;     &lt;span class="co"&gt;ENV&lt;/span&gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;RAILS_ENV&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;] = &lt;span class="co"&gt;RAILS_ENV&lt;/span&gt; = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 8&lt;/span&gt;     &lt;span class="co"&gt;Rake&lt;/span&gt;::&lt;span class="co"&gt;Task&lt;/span&gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;db:test:prepare&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;].invoke
&lt;span class="no"&gt; 9&lt;/span&gt;     &lt;span class="co"&gt;Rake&lt;/span&gt;::&lt;span class="co"&gt;Task&lt;/span&gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;db:fixtures:load&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;].invoke
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;     t.cucumber_opts = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;--format pretty&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;12&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Can you spot the error?  The problem originates with setting RAILS_ENV in this code block.  But isn&amp;#8217;t the block supposed to be executed later?  When the block is #call&amp;#8217;ed?  Very strange.  At the moment, I simply commented out the line, but that&amp;#8217;s going to bite me in a couple moments when I&amp;#8217;m ready to test my features again&amp;hellip;  Oh joy of debugging!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/ypa90YEx7u8" height="1" width="1"/&gt;</content>
    
    <category term="funny" label="Funny" />
      </entry>
  <entry>
    <title>Why no #should_allow_attributes?</title>
    <link href="http://blog.teksol.info/2008/11/01/why-no-should_allow_attributes.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-11-01:20081101223319</id>
    <updated>2008-11-01T22:33:19-04:00</updated>
    <content type="html">&lt;p&gt;Thoughtbot&amp;#8217;s &lt;a href="http://www.thoughtbot.com/projects/shoulda"&gt;Shoulda&lt;/a&gt; is a very nice piece of work.  Their &lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html"&gt;ActiveRecord&lt;/a&gt; macros are also a god-send:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; should_protect_attributes &lt;span class="sy"&gt;:family_id&lt;/span&gt;, &lt;span class="sy"&gt;:debit_account_id&lt;/span&gt;, &lt;span class="sy"&gt;:credit_account_id&lt;/span&gt;, &lt;span class="sy"&gt;:created_at&lt;/span&gt;, &lt;span class="sy"&gt;:updated_at&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This code will assert that ActiveRecord attributes are somehow protected (either though attr_accessible or attr_protected).  But what about the reverse?  There isn&amp;#8217;t a macro to do that.  I happened to need it, so I implemented it on my own &lt;a href="http://github.com/francois/shoulda/tree/should_allow_attributes"&gt;fork&lt;/a&gt; of Shoulda.&lt;/p&gt;
&lt;p&gt;This allows us to specify:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; should_protect_attributes &lt;span class="sy"&gt;:family_id&lt;/span&gt;, &lt;span class="sy"&gt;:debit_account_id&lt;/span&gt;, &lt;span class="sy"&gt;:credit_account_id&lt;/span&gt;, &lt;span class="sy"&gt;:created_at&lt;/span&gt;, &lt;span class="sy"&gt;:updated_at&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt; should_allow_attributes &lt;span class="sy"&gt;:family&lt;/span&gt;, &lt;span class="sy"&gt;:debit_account&lt;/span&gt;, &lt;span class="sy"&gt;:credit_account&lt;/span&gt;, &lt;span class="sy"&gt;:amount&lt;/span&gt;, &lt;span class="sy"&gt;:posted_on&lt;/span&gt;, &lt;span class="sy"&gt;:description&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;NOTE: Example taken from my &lt;a href="http://github.com/francois/family_budget"&gt;family budget&lt;/a&gt; application.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/hxV1NtC4YbQ" height="1" width="1"/&gt;</content>
    
    <category term="unit-tests" label="Unit-tests" />
    
    <category term="shoulda" label="Shoulda" />
      </entry>
  <entry>
    <title>We Are Winners!</title>
    <link href="http://blog.teksol.info/2008/11/01/we-are-winners.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-11-01:20081101215032</id>
    <updated>2008-11-01T21:50:32-04:00</updated>
    <content type="html">&lt;p&gt;&lt;strong&gt;WOW&lt;/strong&gt;  Initially, &lt;a href="http://whatdoesthiserrormean.com/"&gt;What Does this Error Mean?&lt;/a&gt; had a pretty strong presence in the top leaderboard.  As the days went on, we slipped further and further down the scale.  We hovered between 10th and 15th on the general leaderboard.&lt;/p&gt;
&lt;p&gt;I knew we could sort by different criterias, and I occasionaly looked at the leaderboard by other criterias, but I can&amp;#8217;t remember at what ranks we were.&lt;/p&gt;
&lt;p&gt;In the end, we won &lt;strong&gt;Most Useful&lt;/strong&gt;.  That is a very good thing for us.&lt;/p&gt;
&lt;p&gt;Again, congratulations to all teams that participated, and I&amp;#8217;m hoping to see another repeat for 2009.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/1Qi7qB5bdv4" height="1" width="1"/&gt;</content>
    
    <category term="railsrumble" label="Railsrumble" />
      </entry>
  <entry>
    <title>Evolution of a Home Page: What Does This Error Mean?</title>
    <link href="http://blog.teksol.info/2008/10/23/evolution-of-a-home-page-what-does-this-error-mean.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-10-23:20081023195819</id>
    <updated>2008-10-23T19:58:19-04:00</updated>
    <content type="html">&lt;p&gt;To celebrate the start of voting for the &lt;a href="http://railsrumble.com/"&gt;RailsRumble 2008&lt;/a&gt; competition, I thought I&amp;#8217;d make a new video.  Thank god for version control!  This allowed me to go back in time, all the way to the initial checkin, and take a snapshot of each evolution of our design.&lt;/p&gt;
&lt;p&gt;It was a very iterative process.  I did a couple of things in the bus from Sherbrooke to Montreal, then James picked up from there.  The ugly green and red is mine, the nice white, orange and greys are his.&lt;/p&gt;
&lt;p&gt;I hope you enjoy this show!&lt;/p&gt;
&lt;p&gt;&lt;object width="400" height="300"&gt;	&lt;param name="allowfullscreen" value="true" /&gt;	&lt;param name="allowscriptaccess" value="always" /&gt;	&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=2051057&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" /&gt;	&lt;embed src="http://vimeo.com/moogaloop.swf?clip_id=2051057&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;a href="http://vimeo.com/2051057?pg=embed&amp;amp;sec=2051057"&gt;Evolution of a home page: What Does this Error Mean?&lt;/a&gt; from &lt;a href="http://vimeo.com/user784889?pg=embed&amp;amp;sec=2051057"&gt;François Beausoleil&lt;/a&gt; on &lt;a href="http://vimeo.com?pg=embed&amp;amp;sec=2051057"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you prefer the high-quality video: &lt;a href="http://s3.amazonaws.com/teksol/evolution-of-a-home-page--what-does-this-error-mean.mov"&gt;evolution-of-a-home-page&amp;#8212;what-does-this-error-mean.mov&lt;/a&gt; (15 Mb, QuickTime 4)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/Yiu-XwHgOiE" height="1" width="1"/&gt;</content>
    
    <category term="railsrumble" label="Railsrumble" />
      </entry>
  <entry>
    <title>Future creep?  We simply *had* to Stay Focused</title>
    <link href="http://blog.teksol.info/2008/10/20/future-creep-we-had-to-stay-focused.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-10-20:20081020122439</id>
    <updated>2008-10-20T12:24:39-04:00</updated>
    <content type="html">&lt;p&gt;During the &lt;a href="http://railsrumble.com/"&gt;RailsRumble&lt;/a&gt;, we really had to guard against future creep.  Jamis summarized it well in &lt;a href="http://www.37signals.com/svn/posts/1324-beware-of-future-creep"&gt;Beware of future creep&lt;/a&gt;&lt;/p&gt;
&lt;blockquote cite="http://www.37signals.com/svn/posts/1324-beware-of-future-creep"&gt;&lt;p&gt;First, never implement more than you need to. That sounds harsh, in a grasshopper-and-the-ant kind of way, except it really isn’t. It isn’t a mandate to slack off, it’s a command to do what you know. Implement the feature you’re working on, not the feature you hope will land someday. Keep it simple, keep it minimal, and keep it &lt;em&gt;real&lt;/em&gt;.&lt;/p&gt;
&lt;p style="text-align:right"&gt;Jamis in &lt;a href="http://www.37signals.com/svn/posts/1324-beware-of-future-creep"&gt;Beware of future creep&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While pairing with &lt;a href="http://danielharan.com/"&gt;Daniel&lt;/a&gt;, it happened to us a couple of times when he or I would say &amp;#8220;What does our story say already?  Oh, let&amp;#8217;s add a story for later&amp;#8221;.  That was really the essence of the competition.  Delay &lt;strong&gt;anything&lt;/strong&gt; (features, infrastructure, what have you) that could be delayed.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re really excited about &lt;a href="http://whatdoesthiserrormean.com/"&gt;What Does this Error Mean?&lt;/a&gt; and the way it panned out.  Happy &lt;a href="http://railsrumble.com/teams/team-giraffesoft"&gt;voting&lt;/a&gt; !&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/B4Z4D99DAbM" height="1" width="1"/&gt;</content>
    
    <category term="railsrumble" label="Railsrumble" />
      </entry>
  <entry>
    <title>Don't Write Tests?  Are You Crazy?</title>
    <link href="http://blog.teksol.info/2008/10/19/dont-write-tests-are-you-crazy.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-10-19:20081019234637</id>
    <updated>2008-10-19T23:46:37-04:00</updated>
    <content type="html">&lt;p&gt;Reading up on RailsRumble, I found &lt;a href="http://blog.rayvinly.com/"&gt;Raymond Law&lt;/a&gt;&amp;#8217;s &lt;a href="http://blog.rayvinly.com/articles/2008/10/19/railsrumble-2008"&gt;RailsRumble 2008&lt;/a&gt; post-mortem.&lt;/p&gt;
&lt;p&gt;Raymond writes:&lt;/p&gt;
&lt;blockquote cite="http://blog.rayvinly.com/articles/2008/10/19/railsrumble-2008"&gt;&lt;p&gt;Forget about writing tests – Look, I am in support of agile and test-driven development, with one exception. That is, you are not participating in RailsRumble. There’s just no time for it. If you are a good enough programmer, you can build a small application with no tests. If you can’t, I don’t want to work with you. Writing tests for a new application starting from scratch in just 48 hours is simple not feasible. No bargain!&lt;/p&gt;&lt;/blockquote&gt;
&lt;p style="text-align:right"&gt;Raymond Law in &lt;a href="http://blog.rayvinly.com/articles/2008/10/19/railsrumble-2008"&gt;RailsRumble 2008&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sorry Raymond, but that is plain &lt;strong&gt;crazy&lt;/strong&gt;.  We took the time to write tests, and it gave us confidence.  We even ended up with a 1:1.9 ratio of code to test.  I do believe in agile (like you do), and I was really happy for those tests.  Especially as we got more and more tired, the tests were a safety vest that kept us afloat while time was running out.&lt;/p&gt;
&lt;blockquote cite="http://blog.rayvinly.com/articles/2008/10/19/railsrumble-2008"&gt;&lt;p&gt;No ticketing system like Unfuddle and Lighthouse – One team member had tried to use Unfuddle to create tickets to get ourselves more organized. While it was a sincere attempt, it simply didn’t work. There’s no time to accept a ticket, create a new ticket, &amp;#8230; We pretty much abandoned it soon after we started.&lt;/p&gt;&lt;/blockquote&gt;
&lt;p style="text-align:right"&gt;Raymond Law in &lt;a href="http://blog.rayvinly.com/articles/2008/10/19/railsrumble-2008"&gt;RailsRumble 2008&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We used &lt;a href="http://pivotaltracker.com/"&gt;Pivotal Tracker&lt;/a&gt; to organize our stories.  As Raymond said, he didn&amp;#8217;t have a lot of time to plan ahead of the competition.  We got together 10 days prior to the competition and we used Pivotal Tracker to remember a lot of things for us.  Accepting a story was as simple as clicking &lt;em&gt;Start&lt;/em&gt;.  I think having the stories spelled out gave us another safety vest by keeping us focused and on track.&lt;/p&gt;
&lt;p&gt;Before the rumble, I didn&amp;#8217;t know about Pivotal Tracker, but now that I do, I&amp;#8217;ll be sure to use it more and more.  It was a very low ceremony way to remember things.  Even while coding the tests for a story, if we uncovered a missing requirement, we just Apple-Tab&amp;#8217;d to Pivotal Tracker, added the story, Apple-Tab&amp;#8217;d back and went on.&lt;/p&gt;
&lt;p&gt;Hope you had a great weekend!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/790l86CDawA" height="1" width="1"/&gt;</content>
    
    <category term="railsrumble" label="Railsrumble" />
      </entry>
  <entry>
    <title>Fixture Validations in Using Shoulda</title>
    <link href="http://blog.teksol.info/2008/10/19/fixture-validations-in-using-shoulda.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-10-19:20081019220847</id>
    <updated>2008-10-19T22:08:47-04:00</updated>
    <content type="html">&lt;p&gt;I was working on my &lt;a href="http://github.com/francois/family_budget"&gt;family budget&lt;/a&gt; application and wanted to validate existing fixtures.  I wrote the following:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;test/shoulda_macros/validation_macros.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;ValidationMacros&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="pc"&gt;self&lt;/span&gt;.included(base)
&lt;span class="no"&gt; 3&lt;/span&gt;     base.send &lt;span class="sy"&gt;:extend&lt;/span&gt;, &lt;span class="co"&gt;ClassMethods&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt; 6&lt;/span&gt;   &lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;ClassMethods&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt;     &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;should_have_valid_fixtures&lt;/span&gt;(klass=&lt;span class="pc"&gt;self&lt;/span&gt;)
&lt;span class="no"&gt; 8&lt;/span&gt;       should &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;have all valid fixtures&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 9&lt;/span&gt;         klass.name.sub(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Test&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).constantize.all.each &lt;span class="r"&gt;do&lt;/span&gt; |object|
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;           assert object.valid?, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Fixture &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;object.inspect&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; is invalid&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt;         &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;12&lt;/span&gt;       &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;13&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;14&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;16&lt;/span&gt; 
&lt;span class="no"&gt;17&lt;/span&gt; &lt;span class="co"&gt;Test&lt;/span&gt;::&lt;span class="co"&gt;Unit&lt;/span&gt;::&lt;span class="co"&gt;TestCase&lt;/span&gt;.send &lt;span class="sy"&gt;:include&lt;/span&gt;, &lt;span class="co"&gt;ValidationMacros&lt;/span&gt;
&lt;span class="no"&gt;18&lt;/span&gt; 
&lt;span class="no"&gt;19&lt;/span&gt; &lt;span class="c"&gt;# Usage Example&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;AccountTest&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;Test&lt;/span&gt;::&lt;span class="co"&gt;Unit&lt;/span&gt;::&lt;span class="co"&gt;TestCase&lt;/span&gt;
&lt;span class="no"&gt;21&lt;/span&gt;   should_have_valid_fixtures
&lt;span class="no"&gt;22&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;23&lt;/span&gt; 
&lt;span class="no"&gt;24&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;StrangeNameTest&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;Test&lt;/span&gt;::&lt;span class="co"&gt;Unit&lt;/span&gt;::&lt;span class="co"&gt;TestCase&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;/span&gt;   &lt;span class="c"&gt;# Pass the ActiveRecord (or anything that respond_to?(:valid?)&lt;/span&gt;
&lt;span class="no"&gt;26&lt;/span&gt;   &lt;span class="c"&gt;# and respond_to?(:all)) class to validate against.&lt;/span&gt;
&lt;span class="no"&gt;27&lt;/span&gt;   should_have_valid_fixtures &lt;span class="co"&gt;Account&lt;/span&gt;
&lt;span class="no"&gt;28&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This might be interesting if you use fixtures.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/Yutmifszlzw" height="1" width="1"/&gt;</content>
    
    <category term="shoulda" label="Shoulda" />
    
    <category term="unit-testing" label="Unit-testing" />
      </entry>
  <entry>
    <title>RailsRumble 2008: Done &amp; Deployed!</title>
    <link href="http://blog.teksol.info/2008/10/19/railsrumble-2008-done-and-deployed.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-10-19:20081019204027</id>
    <updated>2008-10-19T20:40:27-04:00</updated>
    <content type="html">&lt;p&gt;Well, those were an interesting 48 hours.  We built and deployed &lt;a href="http://whatdoesthiserrormean.com/"&gt;What Does this Error Mean?&lt;/a&gt; within the time constraints that were imposed by the rules.&lt;/p&gt;
&lt;p&gt;What is &lt;a href="http://whatdoesthiserrormean.com/"&gt;What Does this Error Mean?&lt;/a&gt; ?  It&amp;#8217;s a way to search for errors and solutions, but without &lt;a href="http://google.com/"&gt;Google&lt;/a&gt;&amp;#8217;s page ranking algorithm being in the way.  You want to know what it looks like?&lt;/p&gt;
&lt;p style="text-align:center"&gt;&lt;a href="/2008/10/19/what-does-this-error-mean.png"&gt;&lt;img width="400" src="/2008/10/19/what-does-this-error-mean.png" alt="Obligatory What Does this Error Mean? screenshot.  Our app is simple enough that it only needs a paste box on the home page"/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p style="text-align:center"&gt;&lt;a href="/2008/10/19/what-does-this-error-mean.png"&gt;Click for larger version&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The concept behind &lt;a href="http://whatdoesthiserrormean.com/"&gt;What Does this Error Mean?&lt;/a&gt; is simple: you receive some obscure error message you don&amp;#8217;t understand.  You copy it, go to &lt;a href="http://whatdoesthiserrormean.com/"&gt;What Does this Error Mean?&lt;/a&gt;, paste and then click &amp;#8220;Find me some help!&amp;#8221;.  If we find similar error messages in the system from previous posters, we&amp;#8217;ll present you with ranked solutions.  If we don&amp;#8217;t find a solution, we allow you to follow the error so you get notified of new solutions on your error.&lt;/p&gt;
&lt;p&gt;To help us poor developers, &lt;a href="http://giraffesoft.com/"&gt;Team GiraffeSoft&lt;/a&gt; even took the time to create two plugins:  &lt;a href="http://github.com/giraffesoft/what_does_this_error_mean-rails"&gt;What Does this Error Mean? Rails Edition&lt;/a&gt; and &lt;a href="http://github.com/giraffesoft/what_does_this_error_mean-merb"&gt;What Does this Error Mean? Merb Edition&lt;/a&gt; (both plugins have only been tested on the latest released branch).  Install the plugins, and suddenly your development error page becomes a direct link to &lt;a href="http://whatdoesthiserrormean.com/"&gt;What Does this Error Mean?&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To top it all off, &lt;a href="http://jamesgolick.com/"&gt;James&lt;/a&gt;  made a screencast for your viewing pleasure:  &lt;a href="http://s3.amazonaws.com/giraffecasts/wdtem_screencast.mov"&gt;wdtem_screencast.mov&lt;/a&gt; (QuickTime MP4, 75 Mb, 3 minutes).&lt;/p&gt;
&lt;p&gt;If you like our idea, but most of all it&amp;#8217;s implementation, &lt;a href="http://www.railsrumble.com/teams/team-giraffesoft"&gt;vote for us&lt;/a&gt;.  We will be very thankful.&lt;/p&gt;
&lt;h2&gt;Things that worked&lt;/h2&gt;
&lt;p&gt;So, what worked about this competition?  Well&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Being in the same physical location helped, &lt;strong&gt;a lot&lt;/strong&gt;.  This meant we could bounce ideas off each other very quickly;&lt;/li&gt;
	&lt;li&gt;Pair programming;&lt;/li&gt;
	&lt;li&gt;Unit testing (we used &lt;a href="http://thoughtbot.com/projects/shoulda"&gt;Shoulda&lt;/a&gt; and &lt;a href="http://rubyforge.org/projects/test-unit"&gt;Test::Unit&lt;/a&gt;);&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are so self-evident, I don&amp;#8217;t know why people don&amp;#8217;t do that &lt;strong&gt;all the time&lt;/strong&gt;.  The &lt;a href="http://railsrumble.com/"&gt;RailsRumble&lt;/a&gt; team encouraged us to do unit testing, and I pity anyone who didn&amp;#8217;t do that.  We&amp;#8217;re confident that our application is pretty solid, given the amount of tests we have versus the simplicity of the application:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; $ rake stats
&lt;span class="no"&gt; 2&lt;/span&gt; (in /Users/francois/Documents/work/team-giraffesoft)
&lt;span class="no"&gt; 3&lt;/span&gt; +----------------------+-------+-------+---------+---------+-----+-------+
&lt;span class="no"&gt; 4&lt;/span&gt; | Name                 | Lines |   LOC | Classes | Methods | M/C | LOC/M |
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; +----------------------+-------+-------+---------+---------+-----+-------+
&lt;span class="no"&gt; 6&lt;/span&gt; | Controllers          |   278 |   223 |       8 |      25 |   3 |     6 |
&lt;span class="no"&gt; 7&lt;/span&gt; | Helpers              |   153 |    85 |       0 |      12 |   0 |     5 |
&lt;span class="no"&gt; 8&lt;/span&gt; | Models               |   241 |   188 |       7 |      31 |   4 |     4 |
&lt;span class="no"&gt; 9&lt;/span&gt; | Libraries            |   251 |   136 |       1 |      28 |  28 |     2 |
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; | Functional tests     |   730 |   588 |      11 |      13 |   1 |    43 |
&lt;span class="no"&gt;11&lt;/span&gt; | Unit tests           |   767 |   622 |       7 |       2 |   0 |   309 |
&lt;span class="no"&gt;12&lt;/span&gt; +----------------------+-------+-------+---------+---------+-----+-------+
&lt;span class="no"&gt;13&lt;/span&gt; | Total                |  2420 |  1842 |      34 |     111 |   3 |    14 |
&lt;span class="no"&gt;14&lt;/span&gt; +----------------------+-------+-------+---------+---------+-----+-------+
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt;   Code LOC: 632     Test LOC: 1210     Code to Test Ratio: 1:1.9

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;I kept an eye out on our statistics during the competition, and our code to test ratio steadily climbed.  At the end of Saturday, we were at 1.2 / 1.3, and now 1.9?  Wow, hadn&amp;#8217;t really realized that.&lt;/p&gt;
&lt;h2&gt;Things that didn&amp;#8217;t work&lt;/h2&gt;
&lt;ul&gt;
	&lt;li&gt;While pairing with &lt;a href="http://danielharan.com/"&gt;Daniel&lt;/a&gt;, we were stumped a couple of times.  One of the most stressful ones was when we were trying to set properties on Person, and they wouldn&amp;#8217;t be set.  We were really stumped, and just stumbled upon for nearly 20 minutes.  You know what?  The error was that Person had an &lt;code&gt;attr_accessible&lt;/code&gt; declaration.  Once we realized that, our test passed immediately.  Daniel said he&amp;#8217;d write a plugin so that assigning to a protected attribute in test mode would raise an exception.  This will be a welcome relief!&lt;/li&gt;
	&lt;li&gt;Realizing Sunday morning that 1.5 hours of work from Saturday was a bad design decision.  Initially, we would put a 10 year cookie in your browsers.  Then James realized that this had security implications.  We were going to use the cookies to remember what errors and solutions you had posted so that if you ever came back and finally logged on or signed up we could just associate the anonymous postings to your person record.  So, 1.5 hours down the drain&amp;#8230;  We eventually replaced that with some values saved in the session.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thank you to the RailsRumble organizers for putting up this event for the second year in a row.  I count myself very lucky to have participated in this competition with such talented coders as Daniel and James.&lt;/p&gt;
&lt;p&gt;And good luck everyone on your own applications.  May the best one win!&lt;/p&gt;
&lt;p&gt;BTW, if you&amp;#8217;re wondering, we only built 17 story points on Sunday.  Bug fixing, you know&amp;hellip;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/DesoZN66OUY" height="1" width="1"/&gt;</content>
    
    <category term="railsrumble" label="Railsrumble" />
      </entry>
  <entry>
    <title>Team GiraffeSoft Built 28 Story Points in a Day</title>
    <link href="http://blog.teksol.info/2008/10/18/team-giraffesoft-built-28-story-points-in-a-day.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-10-18:20081018195246</id>
    <updated>2008-10-18T19:52:46-04:00</updated>
    <content type="html">&lt;p&gt;We used &lt;a href="http://pivotaltracker.com/"&gt;Pivotal Tracker&lt;/a&gt; to track our stories to build.  Initially, I thought we&amp;#8217;d do maybe 15 points in a day.  Looks like I was really, really, wrong:&lt;/p&gt;
&lt;p style="text-align:center"&gt;&lt;img src="/2008/10/18/28-points-in-a-day.png" alt="28 points in a day, according to Pivotal Tracker"/&gt;&lt;/p&gt;
&lt;p&gt;We delivered 28 story points in a single day.  Team GiraffeSoft really rocks!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/qxUhEEjT_Mk" height="1" width="1"/&gt;</content>
    
    <category term="railsrumble" label="Railsrumble" />
      </entry>
  <entry>
    <title>RailsRumble Started: OpenID FAIL</title>
    <link href="http://blog.teksol.info/2008/10/17/railsrumble-started-openid-fail.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-10-17:20081017232707</id>
    <updated>2008-10-17T23:27:07-04:00</updated>
    <content type="html">&lt;p&gt;Well, the competition is started, but I can&amp;#8217;t access my account.  I use &lt;a href="http://technorati.com/"&gt;Technorati&lt;/a&gt; as my &lt;a href="http://openid.net/"&gt;OpenID&lt;/a&gt; provider, but Technorati won&amp;#8217;t let me grant &lt;a href="http://railsrumble.com/"&gt;RailsRumble&lt;/a&gt; permission to read my profile.&lt;/p&gt;
&lt;p style="background:#999;padding:2px;border:1px solid black;text-align:center;width:100%"&gt;&lt;img src="/2008/10/17/technorati-openid-failed-assoc.png" width="533" height="160" alt="Error: You do not have permission to authorize this url. Please sign in to the appropriate account."/&gt;&lt;/p&gt;
&lt;p&gt;Yee ha!  The wonders of OpenID!  But the saddest fact is that I &lt;strong&gt;did&lt;/strong&gt; authorized RailsRumble at Technorati at least once, since I could sign in and register.&lt;/p&gt;
&lt;p&gt;Who said OpenID solved all problems?  If I had an account at RailsRumble, this wouldn&amp;#8217;t be a problem&amp;#8230;&lt;/p&gt;
&lt;p&gt;Anyway, that won&amp;#8217;t prevent me from kickin&amp;#8217; asses!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/jWwmCi05pOg" height="1" width="1"/&gt;</content>
    
    <category term="railsrumble-2008" label="Railsrumble-2008" />
      </entry>
  <entry>
    <title>How to Use DataMapper With Rails: Part 2</title>
    <link href="http://blog.teksol.info/2008/10/17/how-to-use-datamapper-with-rails-part-2.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-10-17:20081017083525</id>
    <updated>2008-10-17T08:35:25-04:00</updated>
    <content type="html">&lt;p&gt;In &lt;a href="/2008/10/16/how-to-use-datamapper-from-rails-including-migrations-and-tests"&gt;Part I&lt;/a&gt;, I showed how to configure &lt;a href="http://rubyonrails.org/"&gt;Rails&lt;/a&gt; to use &lt;a href="http://datamapper.org/"&gt;DataMapper&lt;/a&gt; instead of &lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html"&gt;ActiveRecord&lt;/a&gt;.  Well, after some thought, I realized we couldn&amp;#8217;t really test anything.  Here&amp;#8217;s the proof:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ArticleTest&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveSupport&lt;/span&gt;::&lt;span class="co"&gt;TestCase&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;test_database_is_empty&lt;/span&gt;
&lt;span class="no"&gt;3&lt;/span&gt;     assert &lt;span class="co"&gt;Article&lt;/span&gt;.all.empty?
&lt;span class="no"&gt;4&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Running the tests results in a failure:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; $ rake test:units
&lt;span class="no"&gt; 2&lt;/span&gt; (in /Users/francois/Documents/work/dm_on_rails)
&lt;span class="no"&gt; 3&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -Ilib:test &amp;quot;/Library/Ruby/Gems/1.8/gems/rake-0.8.2/lib/rake/rake_test_loader.rb&amp;quot; &amp;quot;test/unit/article_test.rb&amp;quot; 
&lt;span class="no"&gt; 4&lt;/span&gt; Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.2/lib/rake/rake_test_loader
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; Started
&lt;span class="no"&gt; 6&lt;/span&gt; .F
&lt;span class="no"&gt; 7&lt;/span&gt; Finished in 0.049976 seconds.
&lt;span class="no"&gt; 8&lt;/span&gt; 
&lt;span class="no"&gt; 9&lt;/span&gt;   1) Failure:
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt; test_database_is_empty(ArticleTest)
&lt;span class="no"&gt;11&lt;/span&gt;     [./test/unit/article_test.rb:10:in `test_db_empty_on_start'
&lt;span class="no"&gt;12&lt;/span&gt;      /Library/Ruby/Gems/1.8/gems/activesupport-2.1.0/lib/active_support/testing/setup_and_teardown.rb:67:in `__send__'
&lt;span class="no"&gt;13&lt;/span&gt;      /Library/Ruby/Gems/1.8/gems/activesupport-2.1.0/lib/active_support/testing/setup_and_teardown.rb:67:in `run']:
&lt;span class="no"&gt;14&lt;/span&gt; &amp;lt;false&amp;gt; is not true.
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt;16&lt;/span&gt; 2 tests, 2 assertions, 1 failures, 0 errors
&lt;span class="no"&gt;17&lt;/span&gt; rake aborted!
&lt;span class="no"&gt;18&lt;/span&gt; Command failed with status (1): [/System/Library/Frameworks/Ruby.framework/...]
&lt;span class="no"&gt;19&lt;/span&gt; 
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt; (See full trace by running task with --trace)

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Time to open the wonderful world of transactions!  At the time of this writing, DataMapper is at 0.9.6.  There is a comment in &lt;tt&gt;lib/dm-core/transaction.rb&lt;/tt&gt; saying &lt;q cite="http://github.com/sam/dm-core/tree/master/lib/dm-core/transaction.rb#L1"&gt;TODO: move to dm-more/dm-transactions&lt;/q&gt;.  If the code below doesn&amp;#8217;t work, add a new dependency on &lt;tt&gt;dm-transaction&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;So, let&amp;#8217;s begin by adding new &lt;code&gt;setup&lt;/code&gt; / &lt;code&gt;teardown&lt;/code&gt; hooks to &lt;code&gt;Test::Unit::TestCase&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;test/test_helper.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Test::Unit::TestCase&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   setup &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     &lt;span class="iv"&gt;@__transaction&lt;/span&gt; = &lt;span class="co"&gt;DataMapper&lt;/span&gt;::&lt;span class="co"&gt;Transaction&lt;/span&gt;.new(&lt;span class="co"&gt;DataMapper&lt;/span&gt;.repository(&lt;span class="sy"&gt;:default&lt;/span&gt;))
&lt;span class="no"&gt; 4&lt;/span&gt;     &lt;span class="iv"&gt;@__transaction&lt;/span&gt;.begin
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt; 6&lt;/span&gt;     &lt;span class="c"&gt;# FIXME: Should I really be calling #push_transaction like that, or is there a better way?&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt;     &lt;span class="co"&gt;DataMapper&lt;/span&gt;.repository(&lt;span class="sy"&gt;:default&lt;/span&gt;).adapter.push_transaction(&lt;span class="iv"&gt;@__transaction&lt;/span&gt;)
&lt;span class="no"&gt; 8&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; 9&lt;/span&gt; 
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   teardown &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt;     &lt;span class="r"&gt;if&lt;/span&gt; &lt;span class="iv"&gt;@__transaction&lt;/span&gt;
&lt;span class="no"&gt;12&lt;/span&gt;       &lt;span class="co"&gt;DataMapper&lt;/span&gt;.repository(&lt;span class="sy"&gt;:default&lt;/span&gt;).adapter.pop_transaction
&lt;span class="no"&gt;13&lt;/span&gt;       &lt;span class="iv"&gt;@__transaction&lt;/span&gt;.rollback
&lt;span class="no"&gt;14&lt;/span&gt;       &lt;span class="iv"&gt;@__transaction&lt;/span&gt; = &lt;span class="pc"&gt;nil&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;16&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;17&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
	&lt;li&gt;GitHub commit:  &lt;a href="http://github.com/francois/dm_on_rails/commit/97a7f253ff09aa18bc95ad549dccac15ae27e636"&gt;Handle transactions during testing to allow each test to be independent of the other ones&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With that code in place, we can run the tests again and see the results of our hard work:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; $ rake test:units
&lt;span class="no"&gt; 2&lt;/span&gt; (in /Users/francois/Documents/work/dm_on_rails)
&lt;span class="no"&gt; 3&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -Ilib:test &amp;quot;/Library/Ruby/Gems/1.8/gems/rake-0.8.2/lib/rake/rake_test_loader.rb&amp;quot; &amp;quot;test/unit/article_test.rb&amp;quot; 
&lt;span class="no"&gt; 4&lt;/span&gt; Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.2/lib/rake/rake_test_loader
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; Started
&lt;span class="no"&gt; 6&lt;/span&gt; ..
&lt;span class="no"&gt; 7&lt;/span&gt; Finished in 0.009485 seconds.
&lt;span class="no"&gt; 8&lt;/span&gt; 
&lt;span class="no"&gt; 9&lt;/span&gt; 2 tests, 2 assertions, 0 failures, 0 errors

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/CW4jbo5SksQ" height="1" width="1"/&gt;</content>
    
    <category term="datamapper" label="Datamapper" />
    
    <category term="rails" label="Rails" />
      </entry>
  <entry>
    <title>How to Use DataMapper From Rails, Including Migrations and Tests</title>
    <link href="http://blog.teksol.info/2008/10/16/how-to-use-datamapper-from-rails-including-migrations-and-tests.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-10-16:20081016213158</id>
    <updated>2008-10-16T21:31:58-04:00</updated>
    <content type="html">&lt;p&gt;&lt;strong&gt;UPDATE 2008/10/17&lt;/strong&gt;: See &lt;a href="/2008/10/17/how-to-use-datamapper-with-rails-part-2"&gt;Part 2&lt;/a&gt; for transation support, including the ability to run multiple tests (which the code below fails to do because of missing transaction support).&lt;/p&gt;
&lt;p&gt;I was bored this evening and wanted to do something at least semi interesting.  I settled on integrating &lt;a href="http://datamapper.org/"&gt;DataMapper&lt;/a&gt; with &lt;a href="http://www.rubyonrails.org/"&gt;Rails&lt;/a&gt;.  Seemed like a nice enough thing to do.  Searching for &lt;a href="http://www.google.com/search?q=datamapper+on+rails"&gt;datamapper on rails&lt;/a&gt; on Google gave me a link to &lt;a href="http://blog.boldr.fr/posts/datamapper-0-9-avec-rails"&gt;DataMapper 0.9 avec Rails&lt;/a&gt; (&lt;a href="http://translate.google.ca/translate?u=http%3A%2F%2Fblog.boldr.fr%2Fposts%2Fdatamapper-0-9-avec-rails&amp;amp;sl=fr&amp;amp;tl=en&amp;amp;hl=fr&amp;amp;ie=UTF-8"&gt;Google translation&lt;/a&gt;).  Nicolas&amp;#8217; article was very interesting, but it&amp;#8217;s focus is just on the basics.  I decided to tackle migrations and testing.&lt;/p&gt;
&lt;h2&gt;Unit testing DataMapper models from within Rails&lt;/h2&gt;
&lt;p&gt;Let&amp;#8217;s start by generating a blank Rails application:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; $ rails dm_on_rails

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
	&lt;li&gt;GitHub commit: &lt;a href="http://github.com/francois/dm_on_rails/commit/28edc32c9dac8e34ecc93659fa3da63892315e90"&gt;Initial version&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, we&amp;#8217;ll remove as much dependency on &lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html"&gt;ActiveRecord&lt;/a&gt; as we can.  From &lt;tt&gt;config/environment.rb&lt;/tt&gt;, uncomment the &lt;code&gt;config.frameworks&lt;/code&gt; line and edit it to the following:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;config/environment.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="c"&gt;# Skip frameworks you're not going to use. To use Rails without a database&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt; &lt;span class="c"&gt;# you must remove the Active Record framework.&lt;/span&gt;
&lt;span class="no"&gt;3&lt;/span&gt; config.frameworks -= [ &lt;span class="sy"&gt;:active_record&lt;/span&gt; ]

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
	&lt;li&gt;GitHub commit: &lt;a href="http://github.com/francois/dm_on_rails/commit/1137da888d64fa0714821599f71332ab8bdfb1fc"&gt;Don&amp;#8217;t load ActiveRecord &amp;#8211; we aren&amp;#8217;t going to use it.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rails 2.1 installs some new defaults in &lt;tt&gt;config/initializers/new_rails_defaults.rb&lt;/tt&gt;.  Remove the ones that reference ActiveRecord.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;GitHub commit: &lt;a href="http://github.com/francois/dm_on_rails/commit/2a07b7baf965a6fc2c45a3a3f8328bf7f70c6000"&gt;Remove new rails defaults that talk about ActiveRecord.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then we need to load the DataMapper gem.  Do it by editing &lt;tt&gt;config/environment.rb&lt;/tt&gt; and loading gems:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;config/environment.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="c"&gt;# I use SQLite3 here, but if you need/want MySQL, replace sqlite3 with mysql&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt; config.gem &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;do_sqlite3&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:version&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;0.9.6&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;3&lt;/span&gt; config.gem &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;dm-core&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:version&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;0.9.6&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
	&lt;li&gt;GitHub commit: &lt;a href="http://github.com/francois/dm_on_rails/commit/8ae469192a6f376a662667085c47da6bf7462756"&gt;Reference the DataMapper gems we need&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Make sure your gems are up to date by running &lt;tt&gt;rake gems:install&lt;/tt&gt;.  I had problems with older versions of dm-core polluting my system.  You might want to remove those if you get dependency issues.&lt;/p&gt;
&lt;p&gt;Then, we need to configure &lt;tt&gt;config/database.yml&lt;/tt&gt;.  Completely replace the data in there with this:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;config/database.yml&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; &lt;span class="ke"&gt;development&lt;/span&gt;: &lt;span class="v"&gt;&amp;amp;defaults&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   &lt;span class="sy"&gt;:adapter&lt;/span&gt;: &lt;span class="er"&gt;sqlite3&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;   &lt;span class="sy"&gt;:database&lt;/span&gt;: &lt;span class="er"&gt;db/development.sqlite3&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt; 
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; &lt;span class="ke"&gt;test&lt;/span&gt;:
&lt;span class="no"&gt; 6&lt;/span&gt;   &lt;span class="cv"&gt;&amp;lt;&amp;lt;&lt;/span&gt;: &lt;span class="gv"&gt;*defaults&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt;   &lt;span class="sy"&gt;:database&lt;/span&gt;: &lt;span class="er"&gt;db/test.sqlite3&lt;/span&gt;
&lt;span class="no"&gt; 8&lt;/span&gt; 
&lt;span class="no"&gt; 9&lt;/span&gt; &lt;span class="ke"&gt;production&lt;/span&gt;:
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   &lt;span class="cv"&gt;&amp;lt;&amp;lt;&lt;/span&gt;: &lt;span class="gv"&gt;*defaults&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt;   &lt;span class="sy"&gt;:database&lt;/span&gt;: &lt;span class="er"&gt;db/production.sqlite3&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Then, we need to load this YAML file to configure DataMapper.  Create &lt;tt&gt;config/initializers/datamapper.rb&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;config/initializers/datamapper.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; require &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;dm-core&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt; hash = &lt;span class="co"&gt;YAML&lt;/span&gt;.load(&lt;span class="co"&gt;File&lt;/span&gt;.new(&lt;span class="co"&gt;Rails&lt;/span&gt;.root + &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/config/database.yml&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;))
&lt;span class="no"&gt;3&lt;/span&gt; &lt;span class="co"&gt;DataMapper&lt;/span&gt;.setup(&lt;span class="sy"&gt;:default&lt;/span&gt;, hash[&lt;span class="co"&gt;Rails&lt;/span&gt;.env])

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
	&lt;li&gt;GitHub commit: &lt;a href="http://github.com/francois/dm_on_rails/commit/2005ba9d541cf10325fc8673781dee6f75b06219"&gt;Configured DataMapper to work with SQLite3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, let&amp;#8217;s generate a model to play with.&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; $ script/generate model article title:string body:text
&lt;span class="no"&gt;2&lt;/span&gt;       exists  app/models/
&lt;span class="no"&gt;3&lt;/span&gt;       exists  test/unit/
&lt;span class="no"&gt;4&lt;/span&gt;       exists  test/fixtures/
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;       create  app/models/article.rb
&lt;span class="no"&gt;6&lt;/span&gt;       create  test/unit/article_test.rb
&lt;span class="no"&gt;7&lt;/span&gt;       create  test/fixtures/articles.yml
&lt;span class="no"&gt;8&lt;/span&gt; uninitialized constant Rails::Generator::GeneratedAttribute::ActiveRecord

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Seems we can&amp;#8217;t use &lt;tt&gt;script/generate model&lt;/tt&gt;.  But the the important files have been created: the fixtures, test and model.&lt;/p&gt;
&lt;p&gt;Running rake test:recent gives us another error:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; $ rake test:recent
&lt;span class="no"&gt; 2&lt;/span&gt; (in /Users/francois/Documents/work/dm_on_rails)
&lt;span class="no"&gt; 3&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -Ilib:test &amp;quot;/Library/Ruby/Gems/1.8/gems/rake-0.8.2/lib/rake/rake_test_loader.rb&amp;quot; &amp;quot;test/unit/article_test.rb&amp;quot; 
&lt;span class="no"&gt; 4&lt;/span&gt; /Library/Ruby/Gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:414:in `to_constant_name': Anonymous modules have no name to be referenced by (ArgumentError)
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;   from /Library/Ruby/Gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:226:in `qualified_name_for'
&lt;span class="no"&gt; 6&lt;/span&gt;   from /Library/Ruby/Gems/1.8/gems/activesupport-2.1.0/lib/active_support/dependencies.rb:491:in `const_missing'
&lt;span class="no"&gt; 7&lt;/span&gt;   from /Library/Ruby/Gems/1.8/gems/activerecord-2.1.0/lib/active_record/fixtures.rb:869:in `require_fixture_classes'
&lt;span class="no"&gt; 8&lt;/span&gt;   from /Library/Ruby/Gems/1.8/gems/activerecord-2.1.0/lib/active_record/fixtures.rb:867:in `each'
&lt;span class="no"&gt; 9&lt;/span&gt;   from /Library/Ruby/Gems/1.8/gems/activerecord-2.1.0/lib/active_record/fixtures.rb:867:in `require_fixture_classes'
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   from /Library/Ruby/Gems/1.8/gems/activerecord-2.1.0/lib/active_record/fixtures.rb:850:in `fixtures'
&lt;span class="no"&gt;11&lt;/span&gt;   from ./test/test_helper.rb:35
&lt;span class="no"&gt;12&lt;/span&gt;   from ./test/unit/article_test.rb:1:in `require'
&lt;span class="no"&gt;13&lt;/span&gt;   from ./test/unit/article_test.rb:1
&lt;span class="no"&gt;14&lt;/span&gt;   from /Library/Ruby/Gems/1.8/gems/rake-0.8.2/lib/rake/rake_test_loader.rb:5:in `load'
&lt;span class="no"&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;/span&gt;   from /Library/Ruby/Gems/1.8/gems/rake-0.8.2/lib/rake/rake_test_loader.rb:5
&lt;span class="no"&gt;16&lt;/span&gt;   from /Library/Ruby/Gems/1.8/gems/rake-0.8.2/lib/rake/rake_test_loader.rb:5:in `each'
&lt;span class="no"&gt;17&lt;/span&gt;   from /Library/Ruby/Gems/1.8/gems/rake-0.8.2/lib/rake/rake_test_loader.rb:5
&lt;span class="no"&gt;18&lt;/span&gt; rake aborted!
&lt;span class="no"&gt;19&lt;/span&gt; Command failed with status (1): [/System/Library/Frameworks/Ruby.framework/...]
&lt;span class="no"&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;/span&gt; 
&lt;span class="no"&gt;21&lt;/span&gt; (See full trace by running task with --trace)

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This is caused by the default &lt;code&gt;fixtures :all&lt;/code&gt; line in &lt;tt&gt;test/test_helper.rb&lt;/tt&gt;.  In fact, all the fixtures code is highly dependent on ActiveRecord.  So, we won&amp;#8217;t use Rails fixtures with DataMapper.  Comment out the &lt;code&gt;fixtures :all&lt;/code&gt; line, as well as the lines that specify transactional fixtures options.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;GitHub commit: &lt;a href="http://github.com/francois/dm_on_rails/commit/f3d233d4c69a2f35648096d35e48f54b5271896f"&gt;Copy the test_help.rb code in test/test_helper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next up, the database isn&amp;#8217;t created.  Ooops!  Let&amp;#8217;s use a nice DataMapper feature, auto migrations.  Append to the end of &lt;tt&gt;test/test_helper.rb&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;test/test_helper.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="co"&gt;Dir&lt;/span&gt;[&lt;span class="co"&gt;File&lt;/span&gt;.join(&lt;span class="co"&gt;Rails&lt;/span&gt;.root, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;models&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)].each {|f| require f}
&lt;span class="no"&gt;2&lt;/span&gt; &lt;span class="co"&gt;DataMapper&lt;/span&gt;.auto_migrate!

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
	&lt;li&gt;GitHub commit: &lt;a href="http://github.com/francois/dm_on_rails/commit/63a012c50689c685824ed9a040f0f75e6453acfc"&gt;Running auto migrations on test start&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We begin by loading all models, because at the end of &lt;code&gt;test/test_helper.rb&lt;/code&gt;, no model files have been loaded yet.  So we have to define the models in memory before DataMapper can auto migrate them.&lt;/p&gt;
&lt;p&gt;Edit &lt;tt&gt;test/unit/article_test.rb&lt;/tt&gt; and put the following:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;test/unit/article_test.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ArticleTest&lt;/span&gt; &amp;lt; &lt;span class="co"&gt;ActiveSupport&lt;/span&gt;::&lt;span class="co"&gt;TestCase&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt;   &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;test_create&lt;/span&gt;
&lt;span class="no"&gt;3&lt;/span&gt;     article = &lt;span class="co"&gt;Article&lt;/span&gt;.create(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;First Post&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:body&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;This is my first-ever post&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:published_at&lt;/span&gt; =&amp;gt; &lt;span class="co"&gt;Time&lt;/span&gt;.now.utc)
&lt;span class="no"&gt;4&lt;/span&gt;     assert !article.new_record?
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;6&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;And put real code in &lt;tt&gt;app/models/article.rb&lt;/tt&gt;:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;app/models/article.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Article&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt;   include &lt;span class="co"&gt;DataMapper&lt;/span&gt;::&lt;span class="co"&gt;Resource&lt;/span&gt;
&lt;span class="no"&gt;3&lt;/span&gt; 
&lt;span class="no"&gt;4&lt;/span&gt;   property &lt;span class="sy"&gt;:id&lt;/span&gt;,           &lt;span class="co"&gt;Integer&lt;/span&gt;, &lt;span class="sy"&gt;:serial&lt;/span&gt; =&amp;gt; &lt;span class="pc"&gt;true&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;   property &lt;span class="sy"&gt;:title&lt;/span&gt;,        &lt;span class="co"&gt;String&lt;/span&gt;
&lt;span class="no"&gt;6&lt;/span&gt;   property &lt;span class="sy"&gt;:body&lt;/span&gt;,         &lt;span class="co"&gt;Text&lt;/span&gt;
&lt;span class="no"&gt;7&lt;/span&gt;   property &lt;span class="sy"&gt;:published_at&lt;/span&gt;, &lt;span class="co"&gt;DateTime&lt;/span&gt;
&lt;span class="no"&gt;8&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
	&lt;li&gt;GitHub commit: &lt;a href="http://github.com/francois/dm_on_rails/commit/1ff281e82c8bd234441bb36e3c5d2a00031ded3c"&gt;Added green test for creating an Article&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And with that, we get a fully functional DataMapper integration!&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; $ rake test:units
&lt;span class="no"&gt; 2&lt;/span&gt; (in /Users/francois/Documents/work/dm_on_rails)
&lt;span class="no"&gt; 3&lt;/span&gt; /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -Ilib:test &amp;quot;/Library/Ruby/Gems/1.8/gems/rake-0.8.2/lib/rake/rake_test_loader.rb&amp;quot; &amp;quot;test/unit/article_test.rb&amp;quot; 
&lt;span class="no"&gt; 4&lt;/span&gt; Loaded suite /Library/Ruby/Gems/1.8/gems/rake-0.8.2/lib/rake/rake_test_loader
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; Started
&lt;span class="no"&gt; 6&lt;/span&gt; .
&lt;span class="no"&gt; 7&lt;/span&gt; Finished in 0.005368 seconds.
&lt;span class="no"&gt; 8&lt;/span&gt; 
&lt;span class="no"&gt; 9&lt;/span&gt; 1 tests, 0 assertions, 0 failures, 0 errors

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;h2&gt;Running DataMapper migrations from Rails&lt;/h2&gt;
&lt;p&gt;What about migrations?  Well, now we need to enter the world of dm-migrations.  Back in &lt;tt&gt;config/environment.rb&lt;/tt&gt;, depend on a new gem:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;config/environment.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; config.gem &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;dm-migrations&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:version&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;0.9.6&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
	&lt;li&gt;GitHub commit: &lt;a href="http://github.com/francois/dm_on_rails/commit/a8b76d82ade7b7978e739a44953d629aa1057eb5"&gt;Depend on dm-migrations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then, create the migration file itself (remember!  no &lt;tt&gt;script/generate&lt;/tt&gt; migration for you):&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;db/migrate/articles.rb&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt; 1&lt;/span&gt; migration &lt;span class="i"&gt;1&lt;/span&gt;, &lt;span class="sy"&gt;:create_articles&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 2&lt;/span&gt;   up &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 3&lt;/span&gt;     create_table &lt;span class="sy"&gt;:articles&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt; 4&lt;/span&gt;       column &lt;span class="sy"&gt;:id&lt;/span&gt;, &lt;span class="co"&gt;Integer&lt;/span&gt;, &lt;span class="sy"&gt;:serial&lt;/span&gt; =&amp;gt; &lt;span class="pc"&gt;true&lt;/span&gt;, &lt;span class="sy"&gt;:nullable?&lt;/span&gt; =&amp;gt; &lt;span class="pc"&gt;false&lt;/span&gt;
&lt;span class="no"&gt; &lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;       column &lt;span class="sy"&gt;:title&lt;/span&gt;, &lt;span class="co"&gt;String&lt;/span&gt;
&lt;span class="no"&gt; 6&lt;/span&gt;       column &lt;span class="sy"&gt;:body&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;TEXT&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt; 7&lt;/span&gt;     &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; 8&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt; 9&lt;/span&gt; 
&lt;span class="no"&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;/span&gt;   down &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt;11&lt;/span&gt;     drop_table &lt;span class="sy"&gt;:articles&lt;/span&gt;
&lt;span class="no"&gt;12&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;13&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Finally, we want a Rake task which will run the migrations.  Since the &lt;tt&gt;db:migrate&lt;/tt&gt; namespace is already used, we&amp;#8217;ll create a &lt;tt&gt;dm:migrate&lt;/tt&gt; namespace instead.  Create &lt;code&gt;lib/tasks/migrations.rake&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;h5&gt;lib/tasks/migrations.rake&lt;/h5&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; namespace &lt;span class="sy"&gt;:dm&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt;   task &lt;span class="sy"&gt;:migrate&lt;/span&gt; =&amp;gt; &lt;span class="sy"&gt;:environment&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
&lt;span class="no"&gt;3&lt;/span&gt;     gem &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;dm-migrations&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;=0.9.6&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;4&lt;/span&gt;     require &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;migration_runner&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;     &lt;span class="co"&gt;Dir&lt;/span&gt;[&lt;span class="co"&gt;File&lt;/span&gt;.join(&lt;span class="co"&gt;Rails&lt;/span&gt;.root, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;db&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;migrate&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)].each {|f| require f}
&lt;span class="no"&gt;6&lt;/span&gt;     migrate_up!
&lt;span class="no"&gt;7&lt;/span&gt;   &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;8&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;ul&gt;
	&lt;li&gt;GitHub commit: &lt;a href="http://github.com/francois/dm_on_rails/commit/5e685c506e87378450ed34e6e54d6a8b31224f82"&gt;Added migrations support and an initial migration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With all that support in place, it&amp;#8217;s time to run the migrations:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; $ rake dm:migrate
&lt;span class="no"&gt;2&lt;/span&gt; (in /Users/francois/Documents/work/dm_on_rails)
&lt;span class="no"&gt;3&lt;/span&gt;  == Performing Up Migration #1: create_articles
&lt;span class="no"&gt;4&lt;/span&gt;    CREATE TABLE &amp;quot;articles&amp;quot; (&amp;quot;id&amp;quot; INTEGER PRIMARY KEY AUTOINCREMENT, &amp;quot;title&amp;quot; VARCHAR(50), &amp;quot;body&amp;quot; TEXT)
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt;    -&amp;gt; 0.0005s
&lt;span class="no"&gt;6&lt;/span&gt;  -&amp;gt; 0.0010s

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If you wish to see the code in action, you may checkout the GitHub repository &lt;a href="http://github.com/francois/dm_on_rails"&gt;dm_on_rails&lt;/a&gt;.  Each commit corresponds to a step in this article.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/NnntH7aOnUE" height="1" width="1"/&gt;</content>
    
    <category term="datamapper" label="Datamapper" />
    
    <category term="rails" label="Rails" />
      </entry>
  <entry>
    <title>RailsRumble Training Video</title>
    <link href="http://blog.teksol.info/2008/10/15/railsrumble-training-video.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-10-15:20081015165834</id>
    <updated>2008-10-15T16:58:34-04:00</updated>
    <content type="html">&lt;p&gt;You know what, training for the &lt;a href="http://railsrumble.com/"&gt;RailsRumble&lt;/a&gt; was very hard.  I had to work at it.  Hope you enjoy my workout as much as I did!&lt;/p&gt;
&lt;p&gt;&lt;object width="400" height="300"&gt;	&lt;param name="allowfullscreen" value="true" /&gt;	&lt;param name="allowscriptaccess" value="always" /&gt;	&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=1977477&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" /&gt;	&lt;embed src="http://vimeo.com/moogaloop.swf?clip_id=1977477&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;a href="http://vimeo.com/1977477?pg=embed&amp;amp;sec=1977477"&gt;RailsRumble 2008 Training&lt;/a&gt; from &lt;a href="http://vimeo.com/user784889?pg=embed&amp;amp;sec=1977477"&gt;François Beausoleil&lt;/a&gt; on &lt;a href="http://vimeo.com?pg=embed&amp;amp;sec=1977477"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/NDQIck9Q09E" height="1" width="1"/&gt;</content>
    
    <category term="railsrumble" label="Railsrumble" />
      </entry>
  <entry>
    <title>RailsRumble Participation:  Team GiraffeSoft Go!</title>
    <link href="http://blog.teksol.info/2008/10/15/railsrumble-participation-team-giraffesoft-go.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-10-15:20081015164807</id>
    <updated>2008-10-15T16:48:07-04:00</updated>
    <content type="html">&lt;p&gt;Are you participating to the &lt;a href="http://railsrumble.com/"&gt;RailsRumble&lt;/a&gt; ?  I&amp;#8217;m part of &lt;strong&gt;Team GiraffeSoft&lt;/strong&gt;, with the other team members being &lt;a href="http://jamesgolick.com/"&gt;James Golick&lt;/a&gt;, &lt;a href="http://danielharan.com/"&gt;Daniel Haran&lt;/a&gt; and &lt;a href="http://programblings.com/"&gt;Mathieu Martin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;None of us are designers, so our application might suffer a bit for that, but we&amp;#8217;ve got so many great ideas.  What&amp;#8217;s our idea you&amp;#8217;re saying?  Oh, that&amp;#8217;s &lt;a href="http://whatdoesthiserrormean.com/"&gt;What does this error mean&lt;/a&gt; (obviously, the website isn&amp;#8217;t up yet).  We intend people (not just developers!) to come in, paste an error message they don&amp;#8217;t understand and get an instant answer.&lt;/p&gt;
&lt;p&gt;I certainly hope to see you there!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/0iVLPj3tIHE" height="1" width="1"/&gt;</content>
    
    <category term="railsrumble" label="Railsrumble" />
      </entry>
  <entry>
    <title>Cliaws 1.2.2: put correctly now...</title>
    <link href="http://blog.teksol.info/2008/08/25/cliaws-1-2-2-put-correctly-now.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-08-26:121352</id>
    <updated>2008-08-26T00:28:00-04:00</updated>
    <content type="html">&lt;p&gt;Today sees a new release of &lt;a href="http://github.com/francois/cliaws/wikis"&gt;Cliaws&lt;/a&gt;.  This is a simple library to interact with &lt;a href="http://aws.amazon.com/s3/"&gt;S3&lt;/a&gt; (and other services) through the command-line.  This library is very similar to Amazon&amp;#8217;s own ec2-* scripts, except this library is written in &lt;a href="http://ruby-lang.org/"&gt;Ruby&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Interacting with S3 should be no harder than:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; $ clis3 put my-local-file my-bucket/my-s3-file

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Put many files at once:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; $ clis3 put my-local-file0 my-local-file1 my-bucket/my-s3-directory/

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Put an environment variable:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; $ clis3 put --data $MY_DATA my-bucket/my-env-value

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Put stdin too!&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; $ tar czfv /var/cache/mylvmbackup/backup | clis3 put - my-bucket/my-backup/backup-20080825-000000.tar.gz

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;All of this functionnality is available from with Ruby too:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; require &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;rubygems&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt; require &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;cliaws&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="no"&gt;3&lt;/span&gt; 
&lt;span class="no"&gt;4&lt;/span&gt; &lt;span class="co"&gt;Cliaws&lt;/span&gt;.s3.put(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;this is the content&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;my-bucket/my-s3-file&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="no"&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;/span&gt; &lt;span class="co"&gt;File&lt;/span&gt;.open(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;my-local-file&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;rb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class="r"&gt;do&lt;/span&gt; |io|
&lt;span class="no"&gt;6&lt;/span&gt;   &lt;span class="co"&gt;Cliaws&lt;/span&gt;.s3.put(io, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;my-bucket/my-s3-file&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)
&lt;span class="no"&gt;7&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Give the &lt;a href="http://rubyforge.org/"&gt;RubyForge&lt;/a&gt; gem servers a couple of hours to refresh themselves, and then enjoy!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/LpW935ISjdk" height="1" width="1"/&gt;</content>
    
    <category term="cliaws" label="Cliaws" />
    
    <category term="aws" label="Aws" />
    
    <category term="s3" label="S3" />
      </entry>
  <entry>
    <title>Catastrophic Database Crash: Oh no!</title>
    <link href="http://blog.teksol.info/2008/08/22/catastrophic-database-crash-oh-no.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-08-23:121255</id>
    <updated>2008-08-23T00:05:00-04:00</updated>
    <content type="html">&lt;p&gt;Ouch!  That hurts!  Thurdsay (yesterday) I finished setting up new DB instances for &lt;a href="http://xlsuite.com/"&gt;XLsuite&lt;/a&gt;.  All was well, and the servers performed admirably well for 24 hours.  Then, suddenly, the LVM partition that held /var/lib/mysql went away&amp;#8230;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Around 18:08 UTC (11:08:09 PDT), our main MySQL database server went down. Luckily, yesterday (Thurdsay), I had just replaced our whole DB infrastructure to have a replicated master/slave setup. It took us 15 minutes to notice that the sites were down, and another 20 minutes to execute a database failover. By 18:50 UTC (11:50 PDT), things were back to normal.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style="text-align:right"&gt;&lt;a href="http://xlsuite.com/blogs/francois/2008/8/22/catastrophic-database-crash-on-the-main-xlsuite-master-mysql-instance/276"&gt;François Beausoleil&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, I did not have the scripts in place yet to do the database failover, so it was a manual process.  It wasn&amp;#8217;t &lt;strong&gt;too&lt;/strong&gt; hard, but I did have to remember one thing:&lt;/p&gt;
&lt;div class="code"&gt;
&lt;div class="CodeRay"&gt;&lt;pre&gt;
&lt;span class="no"&gt;1&lt;/span&gt; Mysql::Error: The MySQL server is running with the --read-only option so it cannot execute this statement: INSERT INTO sessions (`updated_at`, `sessid`, `data`) VALUES('2008-08-22 18:50:58', '589efd77796b913a1cdd7875693ea0c2', 'BAh7BzoWaW5jb21pbmdfcmVxdWVzdHNbBiI1L2FkbWluL2ZvcnVtX2NhdGVn\nb3JpZXMvODMvZm9ydW1zLzEzMS90b3BpY3MvMzgyIgpmbGFzaElDOidBY3Rp\nb25Db250cm9sbGVyOjpGbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA\n')

&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;In &lt;a href="http://oreilly.com/catalog/9780596101718/"&gt;High Performance MySQL&lt;/a&gt;, the authors recommend, in Chapter 8:&lt;/p&gt;
&lt;blockquote cite="http://oreilly.com/catalog/9780596101718/"&gt;On the slave, we recommend enabling the following configuration options:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;skip_slave_start
read_only&lt;/code&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Double oops!  Anyway, the advice in the book was invaluable to me.  If you manage MySQL and don&amp;#8217;t already have the book, I highly suggest you buy it.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/2PYXNJsSEXU" height="1" width="1"/&gt;</content>
    
    <category term="xlsuite" label="Xlsuite" />
    
    <category term="mysql" label="Mysql" />
    
    <category term="recovery" label="Recovery" />
      </entry>
  <entry>
    <title>RubyFringe: Recollections</title>
    <link href="http://blog.teksol.info/2008/07/21/rubyfringe-recollections.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-07-21:119708</id>
    <updated>2008-07-21T17:38:00-04:00</updated>
    <content type="html">&lt;div style="float:left;border:1px solid black;padding:2px;margin:0 4px 4px"&gt;&lt;a href="http://www.flickr.com/photos/chaimzvi/531941055/"&gt;&lt;img src="http://farm2.static.flickr.com/1150/531941055_f1cc0f626b_m_d.jpg" width="240" height="240" alt="Tearful Goodbye, by chaim zvi."&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;I had so much fun at &lt;a href="http://rubyfringe.com/"&gt;RubyFringe&lt;/a&gt; that I don&amp;#8217;t want to go!  I&amp;#8217;m in the &lt;a href="http://metropolitan.com/&amp;#39;s"&gt;Metropolitan&lt;/a&gt; lobby, and writing this.  I almost have a tear in my eyes.  What fond recollections I will cherish for a long time to come.&lt;/p&gt;
&lt;p&gt;Thanks to the &lt;a href="http://www.unspace.ca/"&gt;Unspace&lt;/a&gt; crew (Pete, Megan, &lt;a href="http://hamptoncatlin.com/"&gt;Hampton&lt;/a&gt; and the others I haven&amp;#8217;t thanked personally but who did an &lt;strong&gt;amazing&lt;/strong&gt; job) for making this event.&lt;/p&gt;
&lt;p&gt;This was my first conference ever, and it was great.  As Pete said, &lt;q&gt;I&amp;#8217;m happy we took your conference virginity.&lt;/q&gt;&lt;/p&gt;
&lt;p style="font-size:80%"&gt;&lt;em&gt;Photo by chaim zvi, &lt;a href="http://www.flickr.com/photos/chaimzvi/531941055/"&gt;Tearful Goodbye&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/krLXiGlfCLg" height="1" width="1"/&gt;</content>
    
    <category term="rubyfringe" label="Rubyfringe" />
      </entry>
  <entry>
    <title>RubyFringe: Reginald Braithwaite's Talk</title>
    <link href="http://blog.teksol.info/2008/07/20/rubyfringe-reginald-braithwaite-s-talk.html" type="text/html" />
    <id>tag:blog.teksol.info,2008-07-21:118862</id>
    <updated>2008-07-21T00:09:00-04:00</updated>
    <content type="html">&lt;p&gt;For the first time ever, &lt;a href="http://weblog.raganwald.com/"&gt;ragan&lt;/a&gt; crystallized &lt;strong&gt;why&lt;/strong&gt; he didn&amp;#8217;t like the original #andand implementation, or my own &amp;quot;implementation&amp;quot;http://blog.teksol.info/2007/11/23/a-little-smalltalk-in-ruby-if_nil-and-if_not_nil, #if_not and #if_not_nil and other implementations.&lt;/p&gt;
&lt;p&gt;His point is that if you are writing a library, and you want to use the &lt;a href="http://andand.rubyforge.org/"&gt;andand&lt;/a&gt; gem, you, the author of the library, will pollute the Object namespace of the application that&amp;#8217;s using our library.&lt;/p&gt;
&lt;p&gt;In effect, the library&amp;#8217;s author dependencies will become dependencies of the application that&amp;#8217;s using it, even though they don&amp;#8217;t want or need the extensions.&lt;/p&gt;
&lt;p&gt;The same problem happens with &lt;a href="http://mongrel.rubyforge.org/"&gt;Mongrel&lt;/a&gt; and &lt;a href="http://code.macournoyer.com/thin/"&gt;Thin&lt;/a&gt; : all the libraries these servers use are loaded in the application that&amp;#8217;s running on top of them.&lt;/p&gt;
&lt;p&gt;Thank you Reginald for clearing this up for me.  I now fully understand the need for the &lt;a href="http://rewrite.rubyforge.org/" title="Ruby"&gt;Ruby.rewrite&lt;/a&gt; project.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/teksol/~4/GgoflnqlbnM" height="1" width="1"/&gt;</content>
    
    <category term="gem" label="Gem" />
    
    <category term="rubyfringe" label="Rubyfringe" />
    
    <category term="ragan" label="Ragan" />
    
    <category term="andand" label="Andand" />
      </entry>
</feed>
