<?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" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">
 
  <title>Will Leinweber</title>
  <subtitle>Bitfission</subtitle>
  
  <link href="http://bitfission.com/" />
  <updated>2009-06-09T03:31:37-05:00</updated>
  <author>
    <name>Will Leinweber</name>
    <email>will@bitfission.com</email>
  </author>
  <id>http://bitfission.com/</id>
  
  <link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc-sa/3.0/" /><link rel="self" href="http://feeds.feedburner.com/bitfission" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry>
    <title>Quick Guide to Celerity</title>
    <link href="http://feedproxy.google.com/~r/bitfission/~3/Odg2UieV0Lw/celerity.html" />
    <id>tag:bitfission.com,2009-06-09:1244539077</id>
    <updated>2009-06-09T04:17:57-05:00</updated>
    <content type="html">&lt;p&gt;I&amp;#8217;ll assume you already know and love &lt;a href="http://wiki.github.com/aslakhellesoy/cucumber"&gt;Cucumber&lt;/a&gt; and are using it. I&amp;#8217;ll go even farther and assume you&amp;#8217;re writing your steps in &lt;a href="http://gitrdoc.com/brynary/webrat/tree/master/"&gt;Webrat&lt;/a&gt; since that&amp;#8217;s what cucumber ships with. Now, I really like webrat. It&amp;#8217;s a wonderful DSL and fun to work with, but it does have one problem: no javascript, no ajax.&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/2009/06/celerity.png" alt="" /&gt;&lt;/p&gt;
&lt;h3&gt;Enter Celerity&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://celerity.rubyforge.org/"&gt;Celerity&lt;/a&gt; is a headless browser for jruby that can do javascript. Now you can run your cucumber features that need to do ajax calls, and stay on the command line or CI box. It gets better though. The API is compatible with Watir, so you have the option of driving a real browser at any time. It&amp;#8217;s not as expressive as webrat, but since you reusing cucumber steps is easy, it&amp;#8217;s not a huge deal.&lt;/p&gt;
&lt;h3&gt;Don&amp;#8217;t want jruby?&lt;/h3&gt;
&lt;p&gt;If you don&amp;#8217;t want to run your whole app in jruby, checkout &lt;a href="http://github.com/langalex/culerity/tree/master"&gt;langalex-culerity&lt;/a&gt;. It&amp;#8217;s a gem that will let you drive celerity from mri. It also comes with a &lt;code&gt;common_celerity.rb&lt;/code&gt; file to replace most of your &lt;code&gt;webrat_steps&lt;/code&gt;. We ran into a few steps that were missing or worked a little differently, but porting over didn&amp;#8217;t take long at all.&lt;/p&gt;
&lt;h3&gt;That&amp;#8217;s it!&lt;/h3&gt;
&lt;p&gt;Honestly, there&amp;#8217;s not much to getting it working, so I&amp;#8217;ve skipped doing a detailed step-by-step style guide. The documentation on getting jruby, celerity, and culerity installed is all you need. There weren&amp;#8217;t any surprises. If your app has uses a fair amount of javascript, it&amp;#8217;s worth your time to check this out.&lt;/p&gt;


&lt;img src="http://feeds.feedburner.com/~r/bitfission/~4/Odg2UieV0Lw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://bitfission.com/blog/2009/06/celerity.html</feedburner:origLink></entry>
  
  <entry>
    <title>Acts as Conference Talk</title>
    <link href="http://feedproxy.google.com/~r/bitfission/~3/v9ymjyD5qt8/aac-talk.html" />
    <id>tag:bitfission.com,2009-02-09:1234224657</id>
    <updated>2009-02-09T18:10:57-06:00</updated>
    <content type="html">&lt;p&gt;I just got back from &lt;a href="http://actsasconference.com"&gt;acts_as_conference&lt;/a&gt; and it was great! I promised a few people that I&amp;#8217;d put up my slides so here they are:&lt;/p&gt;
&lt;div style="width:425px;text-align:left" id="__ss_1009857"&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slideshare.net/swf/ssplayer2.swf?doc=relaxing-with-couchdb-acts-as-conference-final-1234224419527061-2&amp;rel=0&amp;stripped_title=relaxing-with-couchdb" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=relaxing-with-couchdb-acts-as-conference-final-1234224419527061-2&amp;rel=0&amp;stripped_title=relaxing-with-couchdb" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;
&lt;p&gt;Thanks again to everyone who made this a fantastic conference.&lt;/p&gt;
&lt;h3&gt;Video&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Update (2/13):&lt;/strong&gt; Confreaks just posted &lt;a href="http://aac2009.confreaks.com/"&gt;all the videos&lt;/a&gt; for acts_as_conference. There were a lot of great talks so be sure to check them out. The &lt;a href="http://aac2009.confreaks.com/07-feb-2009-16-00-relaxing-with-couchdb-will-leinweber.html"&gt;full page for my talk&lt;/a&gt; has links for ridiculously high quality versions.&lt;/p&gt;
&lt;p&gt;&lt;embed src='http://aac2009.confreaks.com/player.swf' height='380' width='640' allowscriptaccess='always' allowfullscreen='true' flashvars='file=http%3A%2F%2Faac2009.confreaks.com%2Fvideos%2F07-feb-2009-16-00-relaxing-with-couchdb-will-leinweber-small.mp4&amp;image=images%2F07-feb-2009-16-00-relaxing-with-couchdb-will-leinweber-preview.jpg&amp;plugins=viral-1'/&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfission/~4/v9ymjyD5qt8" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://bitfission.com/blog/2009/02/aac-talk.html</feedburner:origLink></entry>
  
  <entry>
    <title>Profiling RSpec</title>
    <link href="http://feedproxy.google.com/~r/bitfission/~3/8-3IclOCQ0o/profiling-rspec.html" />
    <id>tag:bitfission.com,2009-02-01:1233530277</id>
    <updated>2009-02-01T17:17:57-06:00</updated>
    <content type="html">&lt;p&gt;If you have anything approaching a large test suite, the time spent running them becomes an important factor. The longer they take, the less often I tend to run them, which is bad. And I&amp;#8217;m probably not alone in that. Ideally you&amp;#8217;d be refactoring all your tests, removing duplication and such. If you&amp;#8217;re just interested in speeding things up, though it&amp;#8217;d be nice to know where the slow specs are.&lt;/p&gt;
&lt;p&gt;RSpec ships with a profile formatter that, but it leaves a lot to be desired. It only reports the top 10 slowest examples, and with several thousand specs, the top ten just isn&amp;#8217;t enough. It also doesn&amp;#8217;t provide any sort of statistics which are nice to track over time, say on the CI box. So let&amp;#8217;s improve this.&lt;/p&gt;
&lt;p&gt;&lt;img src="/images/2009/02/stopwatch.jpg" alt="" /&gt;&lt;/p&gt;
&lt;h3&gt;RSpec Formatters&lt;/h3&gt;
&lt;p&gt;Just run &lt;code&gt;spec&lt;/code&gt; by itself, and you&amp;#8217;ll see there are about a half dozen formatters. Let&amp;#8217;s take a closer look at the &lt;a href="http://github.com/dchelimsky/rspec/blob/738d9245c3ff68add2218294e3eb46951a18f245/lib/spec/runner/formatter/profile_formatter.rb"&gt;existing profile formatter&lt;/a&gt;. It records the time taken for each example and then prints the top ten in &lt;code&gt;#start_dump&lt;/code&gt;. The recording part is fine, we just need to do a little more work in that dump method there.&lt;/p&gt;
&lt;p&gt;&lt;div class="CodeRay"&gt;&lt;br /&gt;
&lt;pre&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;start_dump&lt;/span&gt;&lt;br /&gt;
   &lt;span class="r"&gt;super&lt;/span&gt;&lt;br /&gt;
   &lt;br /&gt;
   &lt;span class="iv"&gt;&lt;code&gt;example_times&amp;lt;/span&amp;gt; = &amp;lt;span class="iv"&amp;gt;&lt;/code&gt;example_times&lt;/span&gt;.sort_by &lt;span class="r"&gt;do&lt;/span&gt; |description, example, time|&lt;br /&gt;
     time&lt;br /&gt;
   &lt;span class="r"&gt;end&lt;/span&gt;.reverse&lt;br /&gt;
   &lt;br /&gt;
   times = &lt;span class="iv"&gt;&lt;code&gt;example_times&amp;lt;/span&amp;gt;.map {|d,e,t| t}
   mean = times.mean
   stddev = times.standard_deviation
   k = &amp;lt;span class="i"&amp;gt;2&amp;lt;/span&amp;gt;
   &amp;lt;span class="iv"&amp;gt;&lt;/code&gt;example_times&lt;/span&gt;.reject! { |d,e,t| t &amp;lt; mean + k * stddev }&lt;br /&gt;
   &lt;br /&gt;
   &lt;span class="iv"&gt;&lt;code&gt;output&amp;lt;/span&amp;gt;.puts &amp;lt;span class="s"&amp;gt;&amp;lt;span class="dl"&amp;gt;&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span class="ch"&amp;gt;\n&amp;lt;/span&amp;gt;&amp;lt;span class="ch"&amp;gt;\n&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;Top &amp;lt;/span&amp;gt;&amp;lt;span class="il"&amp;gt;&amp;lt;span class="idl"&amp;gt;#{&amp;lt;/span&amp;gt;&amp;lt;span class="iv"&amp;gt;&lt;/code&gt;example_times&lt;/span&gt;.size&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt; slowest examples:&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
   &lt;br /&gt;
   &lt;span class="iv"&gt;&lt;code&gt;example_times&amp;lt;/span&amp;gt;.each &amp;lt;span class="r"&amp;gt;do&amp;lt;/span&amp;gt; |description, example, time|
     &amp;lt;span class="iv"&amp;gt;&lt;/code&gt;output&lt;/span&gt;.print red(sprintf(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;%.7f&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, time))&lt;br /&gt;
     &lt;span class="iv"&gt;&lt;code&gt;output&amp;lt;/span&amp;gt;.puts &amp;lt;span class="s"&amp;gt;&amp;lt;span class="dl"&amp;gt;&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span class="ch"&amp;gt;\t&amp;lt;/span&amp;gt;&amp;lt;span class="il"&amp;gt;&amp;lt;span class="idl"&amp;gt;#{&amp;lt;/span&amp;gt;description&amp;lt;span class="idl"&amp;gt;}&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt; &amp;lt;/span&amp;gt;&amp;lt;span class="il"&amp;gt;&amp;lt;span class="idl"&amp;gt;#{&amp;lt;/span&amp;gt;example&amp;lt;span class="idl"&amp;gt;}&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span class="dl"&amp;gt;&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;
   &amp;lt;span class="r"&amp;gt;end&amp;lt;/span&amp;gt;
   
   &amp;lt;span class="iv"&amp;gt;&lt;/code&gt;output&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="ch"&gt;\n&lt;/span&gt;&lt;span class="k"&gt;Stats&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
   &lt;br /&gt;
   &lt;span class="iv"&gt;&lt;code&gt;output&amp;lt;/span&amp;gt;.puts &amp;lt;span class="s"&amp;gt;&amp;lt;span class="dl"&amp;gt;&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;Mean:&amp;lt;/span&amp;gt;&amp;lt;span class="ch"&amp;gt;\t&amp;lt;/span&amp;gt;&amp;lt;span class="il"&amp;gt;&amp;lt;span class="idl"&amp;gt;#{&amp;lt;/span&amp;gt;&amp;lt;span class="s"&amp;gt;&amp;lt;span class="dl"&amp;gt;&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;%.5f&amp;lt;/span&amp;gt;&amp;lt;span class="dl"&amp;gt;&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt; % mean&amp;lt;span class="idl"&amp;gt;}&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span class="dl"&amp;gt;&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;
   &amp;lt;span class="iv"&amp;gt;&lt;/code&gt;output&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;StdDev:&lt;/span&gt;&lt;span class="ch"&gt;\t&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;%.5f&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt; % stddev&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;br /&gt;
   &lt;span class="iv"&gt;&lt;code&gt;output&amp;lt;/span&amp;gt;.puts &amp;lt;span class="s"&amp;gt;&amp;lt;span class="dl"&amp;gt;&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;span class="k"&amp;gt;Total:&amp;lt;/span&amp;gt;&amp;lt;span class="ch"&amp;gt;\t&amp;lt;/span&amp;gt;&amp;lt;span class="il"&amp;gt;&amp;lt;span class="idl"&amp;gt;#{&amp;lt;/span&amp;gt;times.size&amp;lt;span class="idl"&amp;gt;}&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span class="dl"&amp;gt;&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;
   &amp;lt;span class="iv"&amp;gt;&lt;/code&gt;output&lt;/span&gt;.puts &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Slow:&lt;/span&gt;&lt;span class="ch"&gt;\t&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="iv"&gt;&lt;code&gt;example_times&amp;lt;/span&amp;gt;.size&amp;lt;span class="idl"&amp;gt;}&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span class="dl"&amp;gt;&amp;amp;quot;&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;
   
   &amp;lt;span class="iv"&amp;gt;&lt;/code&gt;output&lt;/span&gt;.flush&lt;br /&gt;
 &lt;span class="r"&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
&lt;br /&gt;
So what&amp;#8217;s going on here? It&amp;#8217;s not too much different than the built in one, except we compute the standard deviation and mean of the set of times and use them grab all of the slow specs. This of course assumes that you already have &lt;code&gt;#standard_deviation&lt;/code&gt; and &lt;code&gt;#mean&lt;/code&gt; on &lt;code&gt;Array&lt;/code&gt;. If you don&amp;#8217;t or don&amp;#8217;t feel comfortable adding those to the class, they can just as easily be methods in this module.&lt;/p&gt;
&lt;p&gt;Once we have those, we keep the ones that are 2 deviations from the mean. The choice of two is arbitrary, but I found this gave just enough to get a good look at the slow specs. Finally we print some of the stats we collected. This is great to run on the your CI box. It still checks the whole suite like &lt;code&gt;rake spec&lt;/code&gt;, but now there&amp;#8217;s the chance to record the stats and see how the tests are evolving over time.&lt;/p&gt;
&lt;h3&gt;Using the new Formatter&lt;/h3&gt;
&lt;p&gt;To get this going, we have to make a class that inherits from &lt;code&gt;Spec::Runner::Formatter::ProgressBarFormatter&lt;/code&gt;, and that file will also need to &lt;code&gt;require "spec/runner/formatter/progress_bar_formatter"&lt;/code&gt;. The rest is exactly the same as the built in &lt;code&gt;ProfileFormatter&lt;/code&gt;. For example, name this new formatter &lt;code&gt;RobustProfileFormatter&lt;/code&gt;, and put it in &lt;code&gt;spec/config&lt;/code&gt;. To run it once off the command looks like this: &lt;code&gt;spec -c -r spec/config/robust_profile_formatter.rb -f RobustProfileFormatter&lt;/code&gt;. The &lt;code&gt;-c&lt;/code&gt; option turns on color output, &lt;code&gt;-r&lt;/code&gt; requires the new code, and &lt;code&gt;-f&lt;/code&gt; chooses it as the formatter.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s a lot to type out, and a rake task would be much nicer. In &lt;code&gt;lib/tasks/rspec.rake&lt;/code&gt; there are a bunch of tasks. Inside the &lt;code&gt;spec&lt;/code&gt; namespace is a good place to put our new task:&lt;/p&gt;
&lt;p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;desc &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Profile specs&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class="co"&gt;Spec&lt;/span&gt;::&lt;span class="co"&gt;Rake&lt;/span&gt;::&lt;span class="co"&gt;SpecTask&lt;/span&gt;.new(&lt;span class="sy"&gt;:profile&lt;/span&gt;) &lt;span class="r"&gt;do&lt;/span&gt; |t|
  t.spec_opts = [&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="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;-r spec/config/robust_profile_formatter.rb&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;-f RobustProfileFormatter&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]
  t.spec_files = &lt;span class="co"&gt;FileList&lt;/span&gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;spec/**/*/*_spec.rb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]
&lt;span class="r"&gt;end&lt;/span&gt;
&lt;br /&gt;
&lt;div class="CodeRay"&gt;&lt;br /&gt;
&lt;pre&gt;desc &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Profile specs&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="co"&gt;Spec&lt;/span&gt;::&lt;span class="co"&gt;Rake&lt;/span&gt;::&lt;span class="co"&gt;SpecTask&lt;/span&gt;.new(&lt;span class="sy"&gt;:profile&lt;/span&gt;) &lt;span class="r"&gt;do&lt;/span&gt; |t|&lt;br /&gt;
  t.spec_opts = [&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;br /&gt;
                 &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;-r spec/config/robust_profile_formatter.rb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;br /&gt;
                 &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;-f RobustProfileFormatter&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]&lt;br /&gt;
  t.spec_files = &lt;span class="co"&gt;FileList&lt;/span&gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;spec/&lt;strong&gt;/&lt;/strong&gt;/*_spec.rb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]&lt;br /&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;/pre&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;/notextile&gt;&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s all there is to it, go and speed up your specs!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="http://flickr.com/photos/teamperks/2110119064/"&gt;Stopwatch image&lt;/a&gt; from flickr&lt;/em&gt;&lt;/p&gt;



&lt;img src="http://feeds.feedburner.com/~r/bitfission/~4/8-3IclOCQ0o" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://bitfission.com/blog/2009/02/profiling-rspec.html</feedburner:origLink></entry>
  
  <entry>
    <title>Switching to Webby</title>
    <link href="http://feedproxy.google.com/~r/bitfission/~3/5RyYBYcWxOo/switching-to-webby.html" />
    <id>tag:bitfission.com,2008-11-12:1226478764</id>
    <updated>2008-11-12T02:32:44-06:00</updated>
    <content type="html">&lt;p&gt;I made the transition to &lt;a href="http://webby.rubyforge.org/"&gt;webby&lt;/a&gt; for the blog. Last time I tried to upgrade typo, the migrations broke, everything blew up, tears and sorrow. I realized I didn&amp;#8217;t really need typo, or anything like that.&lt;/p&gt;
&lt;p&gt;Webby is, at its core, a set of fancy rake tasks that will compile your site to html from ruby. It can also deploy over ssh or rsync to your site. If you&amp;#8217;re the only one writing for your blog, and you know how to code, webby is the way to go. There isn&amp;#8217;t really any need for a web UI to write posts, or any of the features (and overhead) you get from a blogging engine. And a huge plus: you can throw the whole thing in git.&lt;/p&gt;
&lt;p&gt;Other people have written quality articles and tutorials on webby. Rather than repeating everything, I&amp;#8217;ll just link them here:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://clarkware.com/cgi/blosxom/2008/08/06"&gt;Mike Clark &amp;#8211; Building Static Websites with Webby&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://judofyr.net/posts/building-a-website-with-webby.html"&gt;Mangus Holm &amp;#8211; Building a Website with Webby&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="https://github.com/search?q=webby"&gt;github search: &amp;#8216;webby&amp;#8217;&lt;/a&gt; &amp;#8211; some people have shared their source for their blogs. Reading code is always a great place to start.&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfission/~4/5RyYBYcWxOo" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://bitfission.com/blog/2008/11/switching-to-webby.html</feedburner:origLink></entry>
  
  <entry>
    <title>Closures in Ruby</title>
    <link href="http://feedproxy.google.com/~r/bitfission/~3/tz16X7b7FL8/closures-in-ruby.html" />
    <id>tag:bitfission.com,2008-09-15:1221460211</id>
    <updated>2008-09-15T01:30:11-05:00</updated>
    <content type="html">I remember reading that Proc.new and lambda weren't exactly the same, but I never ran into any problems so I never bothered to look up exactly &lt;em&gt;what&lt;/em&gt; the differences were. I just always used lambda, which as it turns out, is probably for the best.

Paul Cantrell wrote a &lt;a href="http://innig.net/software/ruby/closures-in-ruby.rb"&gt;article/script&lt;/a&gt; hybrid that does a great job showing and telling all of the differences with the 7 (who knew?) different ways you can have a closure. It's worth a read, check it out.

Here's the summary table that's about halfway through.
&lt;pre&gt;

                                                    "return" returns
                                                    from closure or
                                   True closure?    declaring context?     Arity check?
                                   ---------------  -------------------    -------------------
1. block (called with yield)       N                declaring              no
2. block (&amp;b =&gt; f(&amp;b) =&gt; yield)    N                declaring              no
3. block (&amp;b =&gt; b.call)            Y except return  declaring              warn on too few
4. Proc.new                        Y except return  declaring              warn on too few
5. proc                                &lt;&lt;&lt; alias for lambda in 1.8, Proc.new in 1.9 &gt;&gt;&gt;
6. lambda                          Y                closure                yes, except arity 1
7. method                          Y                closure                yes
&lt;/pre&gt;
&lt;img src="http://feeds.feedburner.com/~r/bitfission/~4/tz16X7b7FL8" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://bitfission.com/blog/2008/09/closures-in-ruby.html</feedburner:origLink></entry>
  
  <entry>
    <title>Why You Should Use CouchDB</title>
    <link href="http://feedproxy.google.com/~r/bitfission/~3/sWNP_sr5X7k/why-you-should-use-couchdb.html" />
    <id>tag:bitfission.com,2008-11-16:1226858400</id>
    <updated>2008-11-16T12:00:00-06:00</updated>
    <content type="html">&lt;h3&gt;New Approach to an Old Problem&lt;/h3&gt;
&lt;p&gt;Your applications need to store and retrieve data. That&amp;#8217;s nothing new.  &lt;a href="http://incubator.apache.org/couchdb/"&gt;CouchDB&lt;/a&gt;, and other document databases like Amazon SimpleDB, are new to the game however. Okay, I&amp;#8217;ll admit the general concept is some &lt;a href="http://en.wikipedia.org/wiki/IBM_Lotus_Notes"&gt;20 years old&lt;/a&gt;, but it&amp;#8217;s safe to say that they&amp;#8217;ve recently started to gain popularity over the last year or so.&lt;/p&gt;
&lt;div class="image left"&gt;&lt;img src="/images/2008/11/couchdb.png" /&gt;&lt;/div&gt;
&lt;p&gt;Learning a document database is worthwhile, even if you don&amp;#8217;t end up using it for anything serious in the near future. You&amp;#8217;ll gain new insights on how to solve your current problems. Don&amp;#8217;t take my word for it, there&amp;#8217;s that line everyone quotes from The Pragmatic Programmer: &lt;em&gt;Learn at least one new database paradigm a year&lt;/em&gt;, or something like that.&lt;/p&gt;
&lt;p&gt;What exactly makes CouchDB so great? Read on.&lt;/p&gt;
&lt;h3&gt;Stable and Scalable&lt;/h3&gt;
&lt;p&gt;When you update a document in CouchDB, it doesn&amp;#8217;t go in and change the existing document. Instead, it just adds a new version. The upshot is that your data is never in a bad state, so even in the case of a power failure, you&amp;#8217;re not going to lose data or spend time verifying against corruption when you start up again. All these extra versions are deleted when you compact the database, so there isn&amp;#8217;t much of a storage penalty because of it.&lt;/p&gt;
&lt;div class="image right"&gt;
&lt;a href="http://leinweber.us/post/58513962/we-need-more-erlangs"&gt;
&lt;img src="/images/2008/11/erlangs.png" /&gt;&lt;br /&gt;
&lt;span class="alt"&gt;Other databases have low erlangs&lt;/span&gt;
&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;It&amp;#8217;s written in Erlang, and benefits from the stability and concurrency of the language its design idioms. Also, unlike current relational databases that try and make a single query as fast as possible, CouchDB tries to maintain consistent performance as the number of queries grows.&lt;/p&gt;
&lt;p&gt;Another big plus is that it doesn&amp;#8217;t have a custom binary protocol. It uses regular HTTP. This means you can use existing http infrastructure tools such as load balancers and clustering proxies. Better still, it&amp;#8217;s RESTful, so you interact with it using the CRUD operations we&amp;#8217;ve come to know and love.&lt;/p&gt;
&lt;p&gt;The way you query data from CouchDB is through views which are written using the map/reduce approach. These views themselves are indexed, so they&amp;#8217;re very fast as long as you keep the indices fresh. While it&amp;#8217;s not an option now, it&amp;#8217;s possible that in the future the mapping step could be distributed amongst several nodes which could make it ridiculously fast.&lt;/p&gt;
&lt;h3&gt;Deep Structures, No Schemas&lt;/h3&gt;
&lt;p&gt;Data has it&amp;#8217;s own natural shape, and I know I&amp;#8217;m not the only one who is sick and tired of fighting that fact. It is often an uphill battle cramming models into relational records. Your data is more complex than a few simple strings, numbers, and boolean values. You have lists, you have hashes, and even small variations between instances of the same object. This is unacceptable in the relational world.&lt;/p&gt;
&lt;p&gt;ORMs like ActiveRecord and DataMapper have done a lot to to ease the pain and abstract away the nastiness of SQL. It&amp;#8217;s not enough though. It&amp;#8217;s like treating the symptoms and not the underlying condition. You still have to worry about joins, normalization, and other artifacts from relational databases. These issues leak their way up into your models where they don&amp;#8217;t belong, and obscure more important logic.&lt;/p&gt;
&lt;p&gt;All of this isn&amp;#8217;t an issue with CouchDB, and that&amp;#8217;s the biggest selling point for me. The fields in your documents can be hashes, they can be arrays, they can be arrays of hashes. Anything that can be serialized to JSON. It&amp;#8217;s about documents &amp;mdash; not records.&lt;/p&gt;
&lt;p&gt;As a quick example, rather than having to create an assets table for uploads, you can store all the metadata in a single field. That field can live right on the object that is responsible for it, where it belongs. Or you could store all the comments for a blog post inline with the post itself. There&amp;#8217;s a good article comparing &lt;a href="http://www.cmlenz.net/archives/2007/10/couchdb-joins"&gt;inline vs. separate storage&lt;/a&gt; that is worth a read.&lt;/p&gt;
&lt;h3&gt;Downsides&lt;/h3&gt;
&lt;p&gt;Nothing is without drawbacks, and CouchDB is no exception. For one, it&amp;#8217;s still alpha. That&amp;#8217;s not to say it&amp;#8217;s buggy and unusable &amp;mdash; far from it &amp;mdash; but there are likely to be changes before they hit 1.0. I can&amp;#8217;t say to what extent this will be an issue, but you should be aware of that.&lt;/p&gt;
&lt;p&gt;There is no security model. This turns out to not be &lt;em&gt;that&lt;/em&gt; big of a deal, but it&amp;#8217;s far from ideal. You can lock down the port it runs on to only talk to localhost, which I think happens by default.&lt;/p&gt;
&lt;p&gt;The first time you run a view it will be slow. It has to go through every document and build the index. After that though, it only has to go through the new or changed documents and is significantly faster. You can make sure your views are fresh by running them after every couple hundred updates or every 10 minutes or so. But if you&amp;#8217;re always running unique views, CouchDB probably isn&amp;#8217;t a good choice.&lt;/p&gt;
&lt;h3&gt;Getting Started&lt;/h3&gt;
&lt;p&gt;Go ahead and compile CouchDB from the svn head rather than going for the last release. You can find instructions over on &lt;a href="http://wiki.apache.org/couchdb/Installation"&gt;their wiki&lt;/a&gt;. You&amp;#8217;ll also want a persistence layer. So far, I&amp;#8217;ve been most impressed with &lt;a href="http://github.com/langalex/couch_potato/tree/master"&gt;Couch Potato&lt;/a&gt;. I&amp;#8217;ve been using it with Merb, which has been great. You just need to add it to your &lt;code&gt;config/dependencies.rb&lt;/code&gt; like this&lt;/p&gt;
&lt;p&gt;&lt;div class="CodeRay"&gt;&lt;br /&gt;
&lt;pre&gt;dependency &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;langalex-couch_potato&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.1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:require_as&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;couch_potato&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
then add this to your &lt;code&gt;config/init.rb&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;div class="CodeRay"&gt;&lt;br /&gt;
&lt;pre&gt;&lt;span class="co"&gt;Merb&lt;/span&gt;::&lt;span class="co"&gt;BootLoader&lt;/span&gt;.before_app_loads &lt;span class="r"&gt;do&lt;/span&gt;&lt;br /&gt;
  &lt;span class="co"&gt;CouchPotato&lt;/span&gt;::&lt;span class="co"&gt;Config&lt;/span&gt;.database_name = &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;appname_&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;&lt;span class="co"&gt;Merb&lt;/span&gt;.environment&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;br /&gt;
  require &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;#8216;&lt;/span&gt;&lt;span class="k"&gt;json/pure&lt;/span&gt;&lt;span class="dl"&gt;&amp;#8217;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;/pre&gt;&lt;br /&gt;
&lt;/div&gt;&lt;br /&gt;
You might not need that &lt;code&gt;json/pure&lt;/code&gt; fix. I was having some problem where &lt;code&gt;#to_json&lt;/code&gt; was declared multiple times. It&amp;#8217;d be nice if there was a merb_couchpotato gem so you could just say &lt;code&gt;use_orm :couchpotato&lt;/code&gt;, and maybe use database.yml instead, but it&amp;#8217;s not really necessary yet.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s really all it takes. Go checkout the readme for Couch Potato and its &lt;a href="http://upstream-berlin.com/2008/10/27/couch-potato-unleashed-a-couchdb-persistence-layer-in-ruby/"&gt;introduction post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Time to relax.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfission/~4/sWNP_sr5X7k" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://bitfission.com/blog/2008/11/why-you-should-use-couchdb.html</feedburner:origLink></entry>
  
  <entry>
    <title>Faking "or shift left"</title>
    <link href="http://feedproxy.google.com/~r/bitfission/~3/nfITBzTEr44/faking-or-shift-left.html" />
    <id>tag:bitfission.com,2008-09-04:1220509811</id>
    <updated>2008-09-04T01:30:11-05:00</updated>
    <content type="html">&lt;p&gt;
I've often been annoyed at the lack of &lt;code&gt;||&lt;&lt;&lt;/code&gt; after being spoiled with &lt;code&gt;||=&lt;/code&gt; for so long. The workaround I've typically used is to go ahead and use &lt;code&gt;||= [ ]&lt;/code&gt; to make sure I have an empty array. That's ugly though. You're dropping down a level and writing the "how" instead of the "why". 
&lt;/p&gt;
&lt;p&gt;
Today some code &lt;a href=http://blog.jayfields.com/2008/09/ruby-recording-method-calls-and.html&gt;Jay Fields posted&lt;/a&gt; had the answer I've been looking for. It's not quite as elegant has having the operator itself, but it does the job of tucking away the ugly detail of ensuring you have an empty array to shift on.
&lt;/p&gt;
&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="no"&gt;1&lt;/span&gt; &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;method_stack&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt;   &lt;span class="iv"&gt;@method_stack&lt;/span&gt; ||= []
&lt;span class="no"&gt;3&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;4&lt;/span&gt;  
&lt;span class="no"&gt;5&lt;/span&gt; &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;method_missing&lt;/span&gt;(sym, *args)
&lt;span class="no"&gt;6&lt;/span&gt;   method_stack &amp;lt;&amp;lt; [sym, args]
&lt;span class="no"&gt;7&lt;/span&gt;   &lt;span class="pc"&gt;self&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;
We're still using &lt;code&gt;||= [ ]&lt;/code&gt; but it is hidden away in its own spot, which I find to be much cleaner.&lt;img src="http://feeds.feedburner.com/~r/bitfission/~4/nfITBzTEr44" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://bitfission.com/blog/2008/09/faking-or-shift-left.html</feedburner:origLink></entry>
  
  <entry>
    <title>RubyGems and Leopard</title>
    <link href="http://feedproxy.google.com/~r/bitfission/~3/0m-WQAWMkE4/rubygems-and-leopard.html" />
    <id>tag:bitfission.com,2008-01-12:1200119411</id>
    <updated>2008-01-12T00:30:11-06:00</updated>
    <content type="html">I just got my replacement iMac (the speakers were shot on the first one) and was going about getting my development environment back together. While trying to instal &lt;a href="http://datamapper.org/"&gt;datamapper&lt;/a&gt;, it choked on the json gem.
&lt;pre class="source-code"&gt;&lt;code&gt;ruby extconf.rb install json&lt;br /&gt;can't find header files for ruby.&lt;/code&gt;&lt;/pre&gt;
As it turns out, the solution is very simple. I didn't have Xcode tools from the install disc on there yet. Since it's something you just put on once then forget about, it took me a while to realize what was going on. Hopefully this post helps others figure it out quicker than I did if they stumble across it.

Also remember to update RubyGems. Leopard comes with 0.9.4 and we're up to 1.0.1 right now.
&lt;pre class="source-code"&gt;&lt;code&gt; sudo gem update --system&lt;/code&gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfission/~4/0m-WQAWMkE4" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://bitfission.com/blog/2008/01/rubygems-and-leopard.html</feedburner:origLink></entry>
  
  <entry>
    <title>More on setting up Leopard</title>
    <link href="http://feedproxy.google.com/~r/bitfission/~3/xStZ4nOisCA/more-on-setting-up-leopard.html" />
    <id>tag:bitfission.com,2008-01-15:1200378611</id>
    <updated>2008-01-15T00:30:11-06:00</updated>
    <content type="html">&lt;p&gt;After posting about &lt;a href="/blog/2008/01/rubygems-and-leopard.html"&gt;setting up a new mac&lt;/a&gt;, I started to put all the other things I found myself missing on a new install. Aside from the standard adium, quicksilver, colloquy, and others there are a few things that are good enough to share.&lt;/p&gt;

&lt;h2&gt;Blurminal&lt;/h2&gt;

&lt;p&gt;I'm a long time user of &lt;a href="http://iterm.sourceforge.net/"&gt;iTerm&lt;/a&gt; but I've decided to give leopard's new tabbed terminal a chance. The one big frustrating thing is it lacks iTerm's ability to switch between tabs with command+arrow keys. However, a big plus is Ciarin Walsh's &lt;a href="http://ciaranwal.sh/2007/11/16/blurminal"&gt;Blurminal&lt;/a&gt;. Instead of just having a percentage of transparency, it slightly blurs whatever is behind the terminal.&lt;/p&gt;

&lt;h2&gt;macFusion&lt;/h2&gt;

&lt;p&gt;This is a &lt;a href="http://www.sccs.swarthmore.edu/users/08/mgorbach/MacFusionWeb/"&gt;nice gui&lt;/a&gt; for the OS X implementation of fuse. This allows you to mount an ssh directory locally right from the menu bar which is really awesome. One annoyance: in tiger, when you mounted something, it would appear on the desktop and the sidebar of finder, which was nice. With leopard though, that's not happening. You can still go up to the menu bar and click on one of your mounts so it's not a huge problem.&lt;/p&gt;

&lt;h2&gt;skitch&lt;/h2&gt;

&lt;p&gt;Sktich is a little app that lets you take screenshots, edit them up, and upload them in one go. It's turning out to be really useful. It's still in beta right now, and I'm not sure when it will be finished. One thing it needs is keyed sftp uploading. It has support for sftp, but with usernames and passwords only. They haven't said how much it's going to be once it's out of beta, but they're doing a good job of getting people hooked before that happens. First one is always free.&lt;/p&gt;

&lt;h2&gt;blue phone elite&lt;/h2&gt;

&lt;p&gt;The last one I'm going to talk about is &lt;a href="http://mirasoftware.com/BPE2/"&gt;blue phone elite&lt;/a&gt;. If you have a supported phone, this will let you use your mac as a handsfree (though I've not had great success with this), send and receive text messages through it, flash up caller id on the screen, pause iTunes when you're on a call and resume when the call is over, and a few other neat things. I have it set to run an applescript that syncs my phone when I come in range, which helps a lot because I'd otherwise never remember to sync. I was having some problems with the 2.0 release so I went back to using 1.x. It looks like they've had a few more releases, so I'll give 2.x a try again.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/bitfission/~4/xStZ4nOisCA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://bitfission.com/blog/2008/01/more-on-setting-up-leopard.html</feedburner:origLink></entry>
  
  <entry>
    <title>Merb and Datamapper</title>
    <link href="http://feedproxy.google.com/~r/bitfission/~3/fRmxlo_o_i0/merb-and-datamapper.html" />
    <id>tag:bitfission.com,2008-01-20:1200810611</id>
    <updated>2008-01-20T00:30:11-06:00</updated>
    <content type="html">&lt;p&gt;With the recent release of &lt;a href="http://merbivore.com"&gt;Merb 0.5&lt;/a&gt;, I've decided to use it along with &lt;a href="http://datamapper.org"&gt;datamapper&lt;/a&gt; for one of my new projects. It isn't different enough to be completely foreign, but enough to be a refreshing change. I haven't done a whole lot with either yet, but I have had a patch accepted, ran into a huge, annoying problem with autotest, and found out how to watch the SQL datamaper is generating.&lt;/p&gt;

&lt;h2&gt;stats patch&lt;/h2&gt;

&lt;p&gt;While I was in #merb earlier today, &lt;a href="http://hassox.blogspot.com/"&gt;hassox&lt;/a&gt; posted some &lt;a href="http://pastie.caboo.se/136989"&gt;current benchmarks&lt;/a&gt;. Being somewhat a stickler for statistics, I had to point out that means alone were meaningless. Not to get into all of the boring details, two distributions can have the same mean, but be completely different. Here is an image I made in Mathematica and sktich to show why:
&lt;a href="http://skitch.com/leinweber/fydc/normal-distribution"&gt;&lt;img src="http://img.skitch.com/20080120-tscppcbjptm64suuupkr63bsqe.preview.jpg" alt="normal distribution" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;They all have the same mean, but a random pick from the distribution with the smaller variance of 0.5 is more likely to be actually be near the mean than with either of the ones with higher variances. If you apply this to load times, two severs could serve pages just as quickly on average. However, the one with the higher variance is going to seem a lot slower, since there are more slow points in the set.&lt;/p&gt;

&lt;p&gt;I submitted a &lt;a href="http://merb.devjavu.com/ticket/460"&gt;patch&lt;/a&gt; to add the standard deviations to each of the tests and &lt;a href="http://pastie.caboo.se/139496"&gt;clean up the output a bit&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;AutoTest problem&lt;/h2&gt;

&lt;p&gt;I was trying to get autotest up and running but kept running into this problem:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/Library/Ruby/Site/1.8/rubygems/custom_require.rb:27:in `gem_original_require': 
no such file to load -- rspec_autotest (LoadError)
from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:27:in `require'
from /Library/Ruby/Gems/1.8/gems/zentest-3.5.0/bin/autotest:35
from /usr/bin/autotest:19:in `load'
from /usr/bin/autotest:19
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After futilely searching for the problem for a long time, and asking in #merb where someone else was having the same problem, I was about to give up and just run my tests by hand (oh no!). I decided to check the versions of all my gems, and it turned out that zentest was only 3.5.0 when the latest was 3.7.2. I thought that was odd, because I just installed the gem that night. Odder still, updating the gem did nothing to increase the version. It turns out there is zentest and there is ZenTest&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ gem list -r | grep -i zentest
zentest (3.5.0)
ZenTest (3.7.2, 3.7.1, 3.7.0, 3.6.1, 3.6.0, 3.5.2, 3.5.1, 3.4.3, 3.4.2, 3.4.1, 3.4.0, 3.3.0, 3.2.0, 3.1.0, 3.0.0)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;edit&lt;/strong&gt;: As of Jan 20, 2008 this seems to be fixed, and there is only ZenTest&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Uninstalling zentest and installing ZenTest fixed the problem.&lt;/p&gt;

&lt;h2&gt;Watching Datamapper's SQL&lt;/h2&gt;

&lt;p&gt;This is very easy to do. Just edit your config/database.yml file to include
&lt;div class="CodeRay"&gt;
&lt;pre&gt;&lt;span class="no"&gt;1&lt;/span&gt;   &lt;span class="sy"&gt;:log_stream&lt;/span&gt;: &lt;span class="er"&gt;STDOUT&lt;/span&gt;
&lt;span class="no"&gt;2&lt;/span&gt;   &lt;span class="sy"&gt;:log_level&lt;/span&gt;: &lt;span class="er"&gt;0&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;and you can see the SQL in your merb process.&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/bitfission/~4/fRmxlo_o_i0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://bitfission.com/blog/2008/01/merb-and-datamapper.html</feedburner:origLink></entry>
  
</feed>
