<?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" xml:lang="en-US">
  <title>Rails on the Run - Home</title>
  <id>tag:www.railsontherun.com,2008:mephisto/</id>
  <generator version="0.7.3" uri="http://mephistoblog.com">Mephisto Noh-Varr</generator>
  
  <link href="http://www.railsontherun.com/" rel="alternate" type="text/html" />
  <updated>2008-05-04T08:37:51Z</updated>
  <link rel="self" href="http://feeds.feedburner.com/railsontherun" type="application/atom+xml" /><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Frailsontherun" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/railsontherun" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Frailsontherun" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Frailsontherun" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-05-04:1128</id>
    <published>2008-05-04T08:29:00Z</published>
    <updated>2008-05-04T08:37:51Z</updated>
    <category term="benchmark" />
    <category term="merb" />
    <category term="metaprogramming" />
    <category term="speed" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/PYjwt7BKd8c/avoid-using-metaprogramming" rel="alternate" type="text/html" />
    <title>Avoid using metaprogramming (seriously!)</title>
<content type="html">
            &lt;p&gt;Ruby is sexy, Ruby is cool and its metaprogramming potential offers some really cook features. However you might not realize that your cleverness is slowing down your code.&lt;/p&gt;

&lt;p&gt;Today I was working on cleaning up merb_helper a Merb plugin that brings a lot of the stuff Rails developers are used to. In Merb we aim for speed and try to avoid magic.&lt;/p&gt;

&lt;p&gt;merb_plugin didn't receive a lot of love from the main contributors but few features were added by different contributors and the code became hard to maintain. &lt;/p&gt;

&lt;p&gt;Looking at the code I quickly found this bad boy:&lt;/p&gt;

&lt;p&gt;(Old Merb Time DSL using metaprogramming)&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;   &lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;MetaTimeDSL&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    {&lt;span class="sy"&gt;:second&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;1&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;     &lt;span class="sy"&gt;:minute&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;60&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;     &lt;span class="sy"&gt;:hour&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;3600&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;     &lt;span class="sy"&gt;:day&lt;/span&gt; =&amp;gt; [&lt;span class="i"&gt;24&lt;/span&gt;,&lt;span class="sy"&gt;:hours&lt;/span&gt;], &lt;tt&gt;
&lt;/tt&gt;     &lt;span class="sy"&gt;:week&lt;/span&gt; =&amp;gt; [&lt;span class="i"&gt;7&lt;/span&gt;,&lt;span class="sy"&gt;:days&lt;/span&gt;], &lt;tt&gt;
&lt;/tt&gt;     &lt;span class="sy"&gt;:month&lt;/span&gt; =&amp;gt; [&lt;span class="i"&gt;30&lt;/span&gt;,&lt;span class="sy"&gt;:days&lt;/span&gt;], &lt;tt&gt;
&lt;/tt&gt;     &lt;span class="sy"&gt;:year&lt;/span&gt; =&amp;gt; [&lt;span class="fl"&gt;364.25&lt;/span&gt;, &lt;span class="sy"&gt;:days&lt;/span&gt;]}.each &lt;span class="r"&gt;do&lt;/span&gt; |meth, amount|&lt;tt&gt;
&lt;/tt&gt;      define_method &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;m_&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;meth&lt;span class="dl"&gt;}&lt;/span&gt;&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;tt&gt;
&lt;/tt&gt;        amount = amount.is_a?(&lt;span class="co"&gt;Array&lt;/span&gt;) ? amount[&lt;span class="i"&gt;0&lt;/span&gt;].send(amount[&lt;span class="i"&gt;1&lt;/span&gt;]) : amount&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="pc"&gt;self&lt;/span&gt; * amount&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      alias_method &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;m_&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;meth&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;s&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;.intern, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;m_&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="dl"&gt;#{&lt;/span&gt;meth&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;Numeric&lt;/span&gt;.send &lt;span class="sy"&gt;:include&lt;/span&gt;, &lt;span class="co"&gt;MetaTimeDSL&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;The above code looks awful to me and I decided to rewrite it a way I thought would be more efficient:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;TimeDSL&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;second&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="pc"&gt;self&lt;/span&gt; * &lt;span class="i"&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    alias_method &lt;span class="sy"&gt;:seconds&lt;/span&gt;, &lt;span class="sy"&gt;:second&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;minute&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="pc"&gt;self&lt;/span&gt; * &lt;span class="i"&gt;60&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    alias_method &lt;span class="sy"&gt;:minutes&lt;/span&gt;, &lt;span class="sy"&gt;:minute&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;hour&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="pc"&gt;self&lt;/span&gt; * &lt;span class="i"&gt;3600&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    alias_method &lt;span class="sy"&gt;:hours&lt;/span&gt;, &lt;span class="sy"&gt;:hour&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;day&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="pc"&gt;self&lt;/span&gt; * &lt;span class="i"&gt;86400&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    alias_method &lt;span class="sy"&gt;:days&lt;/span&gt;, &lt;span class="sy"&gt;:day&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;week&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="pc"&gt;self&lt;/span&gt; * &lt;span class="i"&gt;604800&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    alias_method &lt;span class="sy"&gt;:weeks&lt;/span&gt;, &lt;span class="sy"&gt;:week&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;month&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="pc"&gt;self&lt;/span&gt; * &lt;span class="i"&gt;2592000&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    alias_method &lt;span class="sy"&gt;:months&lt;/span&gt;, &lt;span class="sy"&gt;:month&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;year&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="pc"&gt;self&lt;/span&gt; * &lt;span class="i"&gt;31471200&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    alias_method &lt;span class="sy"&gt;:years&lt;/span&gt;, &lt;span class="sy"&gt;:year&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;Numeric&lt;/span&gt;.send &lt;span class="sy"&gt;:include&lt;/span&gt;, &lt;span class="co"&gt;TimeDSL&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;To make sure I was right, I run the following benchmarks:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;54&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;55&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;56&lt;tt&gt;
&lt;/tt&gt;57&lt;tt&gt;
&lt;/tt&gt;58&lt;tt&gt;
&lt;/tt&gt;59&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;61&lt;tt&gt;
&lt;/tt&gt;62&lt;tt&gt;
&lt;/tt&gt;63&lt;tt&gt;
&lt;/tt&gt;64&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;65&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;66&lt;tt&gt;
&lt;/tt&gt;67&lt;tt&gt;
&lt;/tt&gt;68&lt;tt&gt;
&lt;/tt&gt;69&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;71&lt;tt&gt;
&lt;/tt&gt;72&lt;tt&gt;
&lt;/tt&gt;73&lt;tt&gt;
&lt;/tt&gt;74&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;75&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;76&lt;tt&gt;
&lt;/tt&gt;77&lt;tt&gt;
&lt;/tt&gt;78&lt;tt&gt;
&lt;/tt&gt;79&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;80&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;81&lt;tt&gt;
&lt;/tt&gt;82&lt;tt&gt;
&lt;/tt&gt;83&lt;tt&gt;
&lt;/tt&gt;84&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;85&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;86&lt;tt&gt;
&lt;/tt&gt;87&lt;tt&gt;
&lt;/tt&gt;88&lt;tt&gt;
&lt;/tt&gt;89&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;90&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;91&lt;tt&gt;
&lt;/tt&gt;92&lt;tt&gt;
&lt;/tt&gt;93&lt;tt&gt;
&lt;/tt&gt;94&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;95&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;96&lt;tt&gt;
&lt;/tt&gt;97&lt;tt&gt;
&lt;/tt&gt;98&lt;tt&gt;
&lt;/tt&gt;99&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;100&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;101&lt;tt&gt;
&lt;/tt&gt;102&lt;tt&gt;
&lt;/tt&gt;103&lt;tt&gt;
&lt;/tt&gt;104&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;105&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;106&lt;tt&gt;
&lt;/tt&gt;107&lt;tt&gt;
&lt;/tt&gt;108&lt;tt&gt;
&lt;/tt&gt;109&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;110&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;111&lt;tt&gt;
&lt;/tt&gt;112&lt;tt&gt;
&lt;/tt&gt;113&lt;tt&gt;
&lt;/tt&gt;114&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;115&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;116&lt;tt&gt;
&lt;/tt&gt;117&lt;tt&gt;
&lt;/tt&gt;118&lt;tt&gt;
&lt;/tt&gt;119&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;120&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;121&lt;tt&gt;
&lt;/tt&gt;122&lt;tt&gt;
&lt;/tt&gt;123&lt;tt&gt;
&lt;/tt&gt;124&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;125&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;126&lt;tt&gt;
&lt;/tt&gt;127&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;benchmark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;TIMES&lt;/span&gt; = (&lt;span class="pc"&gt;ARGV&lt;/span&gt;[&lt;span class="i"&gt;0&lt;/span&gt;] || &lt;span class="i"&gt;100_000&lt;/span&gt;).to_i&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;Benchmark&lt;/span&gt;.bmbm &lt;span class="r"&gt;do&lt;/span&gt; |x|&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;metaprogramming 360.seconds&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;    &lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;360&lt;/span&gt;.m_seconds&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;no metaprogramming 360.hours&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;360&lt;/span&gt;.seconds&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;metaprogramming 360.minutes&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;    &lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;360&lt;/span&gt;.m_minutes&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;no metaprogramming 360.minutes&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;360&lt;/span&gt;.minutes&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;metaprogramming 360.hours&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;    &lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;360&lt;/span&gt;.m_hours&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;no metaprogramming 360.hours&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;360&lt;/span&gt;.hours&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;metaprogramming 360.days&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;    &lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;360&lt;/span&gt;.m_days&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;no metaprogramming 360.days&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;360&lt;/span&gt;.days&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;metaprogramming 360.weeks&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;    &lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;360&lt;/span&gt;.m_weeks&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;no metaprogramming 360.weeks&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;360&lt;/span&gt;.weeks&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;metaprogramming 18.months&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;    &lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;18&lt;/span&gt;.m_months&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;no metaprogramming 18.months&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;18&lt;/span&gt;.months&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;metaprogramming 7.years&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;    &lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;7&lt;/span&gt;.m_years&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  x.report(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;no metaprogramming 7.years&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;TIMES&lt;/span&gt;.times &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="i"&gt;7&lt;/span&gt;.years&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt; &lt;span class="co"&gt;Rehearsal&lt;/span&gt; ------------------------------------------------------------------&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.seconds      &lt;span class="fl"&gt;0.130000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.130000&lt;/span&gt; (  &lt;span class="fl"&gt;0.133164&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.hours     &lt;span class="fl"&gt;0.050000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.050000&lt;/span&gt; (  &lt;span class="fl"&gt;0.042655&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.minutes      &lt;span class="fl"&gt;0.130000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.130000&lt;/span&gt; (  &lt;span class="fl"&gt;0.133327&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.minutes   &lt;span class="fl"&gt;0.040000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.040000&lt;/span&gt; (  &lt;span class="fl"&gt;0.042401&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.hours        &lt;span class="fl"&gt;0.140000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.140000&lt;/span&gt; (  &lt;span class="fl"&gt;0.134312&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.hours     &lt;span class="fl"&gt;0.040000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.040000&lt;/span&gt; (  &lt;span class="fl"&gt;0.043125&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.days         &lt;span class="fl"&gt;0.130000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.130000&lt;/span&gt; (  &lt;span class="fl"&gt;0.134949&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.days      &lt;span class="fl"&gt;0.050000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.050000&lt;/span&gt; (  &lt;span class="fl"&gt;0.043745&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.weeks        &lt;span class="fl"&gt;0.130000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.130000&lt;/span&gt; (  &lt;span class="fl"&gt;0.135581&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.weeks     &lt;span class="fl"&gt;0.050000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.050000&lt;/span&gt; (  &lt;span class="fl"&gt;0.043544&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;18&lt;/span&gt;.months        &lt;span class="fl"&gt;0.130000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.130000&lt;/span&gt; (  &lt;span class="fl"&gt;0.135234&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;18&lt;/span&gt;.months     &lt;span class="fl"&gt;0.050000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.050000&lt;/span&gt; (  &lt;span class="fl"&gt;0.044354&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;7&lt;/span&gt;.years          &lt;span class="fl"&gt;0.140000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.140000&lt;/span&gt; (  &lt;span class="fl"&gt;0.144062&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;7&lt;/span&gt;.years       &lt;span class="fl"&gt;0.050000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.050000&lt;/span&gt; (  &lt;span class="fl"&gt;0.044392&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;--------------------------------------------------------- total: &lt;span class="fl"&gt;1.260000&lt;/span&gt;sec&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;                                     user     system      total        real&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.seconds      &lt;span class="fl"&gt;0.130000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.130000&lt;/span&gt; (  &lt;span class="fl"&gt;0.132567&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.hours     &lt;span class="fl"&gt;0.040000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.040000&lt;/span&gt; (  &lt;span class="fl"&gt;0.042777&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.minutes      &lt;span class="fl"&gt;0.140000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.140000&lt;/span&gt; (  &lt;span class="fl"&gt;0.132554&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.minutes   &lt;span class="fl"&gt;0.040000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.040000&lt;/span&gt; (  &lt;span class="fl"&gt;0.043193&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.hours        &lt;span class="fl"&gt;0.130000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.130000&lt;/span&gt; (  &lt;span class="fl"&gt;0.133027&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.hours     &lt;span class="fl"&gt;0.050000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.050000&lt;/span&gt; (  &lt;span class="fl"&gt;0.042613&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.days         &lt;span class="fl"&gt;0.130000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.130000&lt;/span&gt; (  &lt;span class="fl"&gt;0.138637&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.days      &lt;span class="fl"&gt;0.050000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.050000&lt;/span&gt; (  &lt;span class="fl"&gt;0.043213&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.weeks        &lt;span class="fl"&gt;0.130000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.130000&lt;/span&gt; (  &lt;span class="fl"&gt;0.134049&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;360&lt;/span&gt;.weeks     &lt;span class="fl"&gt;0.040000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.040000&lt;/span&gt; (  &lt;span class="fl"&gt;0.043713&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;18&lt;/span&gt;.months        &lt;span class="fl"&gt;0.140000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.140000&lt;/span&gt; (  &lt;span class="fl"&gt;0.134941&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;18&lt;/span&gt;.months     &lt;span class="fl"&gt;0.040000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.040000&lt;/span&gt; (  &lt;span class="fl"&gt;0.043980&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;metaprogramming &lt;span class="i"&gt;7&lt;/span&gt;.years          &lt;span class="fl"&gt;0.150000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.150000&lt;/span&gt; (  &lt;span class="fl"&gt;0.143389&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;no metaprogramming &lt;span class="i"&gt;7&lt;/span&gt;.years       &lt;span class="fl"&gt;0.040000&lt;/span&gt;   &lt;span class="fl"&gt;0.000000&lt;/span&gt;   &lt;span class="fl"&gt;0.040000&lt;/span&gt; (  &lt;span class="fl"&gt;0.044585&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt; &lt;span class="fl"&gt;0.136591&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;The metaprogramming version of the same implementation is almost 3 times slower! &lt;/p&gt;

&lt;p&gt;Moral of the story: only use metaprogramming if you really have to or if you don't care about speed of execution.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/PYjwt7BKd8c" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/5/4/avoid-using-metaprogramming</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-04-27:1081</id>
    <published>2008-04-27T17:24:00Z</published>
    <updated>2008-04-28T03:20:38Z</updated>
    <category term="barcamp" />
    <category term="sandiego" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/3OImUcxfRQU/barcamp-san-diego-rev-3" rel="alternate" type="text/html" />
    <title>BarCamp San Diego rev.3</title>
<content type="html">
            &lt;p&gt;&lt;img src="http://www.barcampsd.org/badges_for_bcsd3/orange.png" alt="BarCamp" /&gt;&lt;/p&gt;

&lt;p&gt;Just a reminder, this coming week end, San Diego presents &lt;a href="http://www.barcampsd.org/"&gt;BarCamp&lt;/a&gt; for the third time.&lt;/p&gt;

&lt;p&gt;This time, the chosen Venue is &lt;a href="http://www.technicaltrainingresources.com/"&gt;Microsoft&lt;/a&gt; in &lt;a href="http://maps.google.com/maps?hl=en&amp;amp;amp;ie=UTF8&amp;amp;amp;f=d&amp;amp;amp;daddr=9255+Towne+Centre+Dr+San+Diego,+CA+92121"&gt;La Jolla&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was thinking about preparing 2 intro talks, one on &lt;a href="http://merbivore.com"&gt;Merb&lt;/a&gt; and one on &lt;a href="http://en.wikipedia.org/wiki/Unobtrusive_JavaScript"&gt;Unobtrusive Javascript&lt;/a&gt; (jQuery, Prototype + LowPro etc...), then we'll see the crowd and what people are interested in. Feel free to give me your feedback, suggestions...&lt;/p&gt;

&lt;p&gt;I also heard that on top of the awesome people from san Diego, some other important people are coming just for the event:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://glu.ttono.us/"&gt;Kevin Clark&lt;/a&gt; from the &lt;a href="http://www.powerset.com/"&gt;Powerset&lt;/a&gt; hall of fame.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://derekneighbors.com/"&gt;Derek Neighbors&lt;/a&gt; representing Phoenix's top Rails shop: &lt;a href="http://integrumtech.com"&gt;Integrum&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Warning&lt;/h2&gt;

&lt;p&gt;Based on previous BarCamps, you might end up seeing &lt;a href="http://www.flickr.com/photos/kirinqueen/1993483057/sizes/m/in/pool-393912@N21/"&gt;a guy wearing a kilt who talks about how he is his own imaginary friend&lt;/a&gt;, having to look at  &lt;a href="http://www.flickr.com/photos/techslut/2043825771/sizes/l/in/pool-393912@N21/"&gt;ActionScript code&lt;/a&gt;, meet &lt;a href="http://www.flickr.com/photos/acphonehome/532658193/in/pool-barcampsd/"&gt;a lot&lt;/a&gt; of &lt;a href="http://www.flickr.com/photos/kirinqueen/531272887/in/pool-barcampsd"&gt;interesting people&lt;/a&gt; and even maybe learn about &lt;a href="http://www.flickr.com/photos/techslut/545216043/in/pool-barcampsd"&gt;lock picking&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://farm2.static.flickr.com/1053/527321111_763e4ad085.jpg"&gt;&lt;img src="http://farm2.static.flickr.com/1053/527321111_763e4ad085_m.jpg" alt="last year barcamp sd crowd" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://farm3.static.flickr.com/2004/2044606386_2ee84dcce3.jpg"&gt;&lt;img src="http://farm3.static.flickr.com/2004/2044606386_2ee84dcce3_m.jpg" alt="outside" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://farm2.static.flickr.com/1082/529394507_f34d9015c0.jpg"&gt;&lt;img src="http://farm2.static.flickr.com/1082/529394507_f34d9015c0_m.jpg" alt="powerpoint karaoke" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://farm2.static.flickr.com/1114/527020113_cbe6393372.jpg"&gt;&lt;img src="http://farm2.static.flickr.com/1114/527020113_cbe6393372_m.jpg" alt="tshirt printing" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://farm3.static.flickr.com/2351/1994270564_3a0a2f5319.jpg"&gt;&lt;img src="http://farm3.static.flickr.com/2351/1994270564_3a0a2f5319_m.jpg" alt="presentation" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I even heard rumors saying that &lt;a href="http://blog.aisleten.com/"&gt;Ryan Felton&lt;/a&gt; is organizing another &lt;a href="http://www.flickr.com/photos/kirinqueen/1994487718/in/pool-barcampsd"&gt;wii tournament&lt;/a&gt;.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/3OImUcxfRQU" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/4/27/barcamp-san-diego-rev-3</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-04-16:959</id>
    <published>2008-04-16T08:21:00Z</published>
    <updated>2008-04-16T15:54:36Z</updated>
    <category term="freeze" />
    <category term="git" />
    <category term="rais" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/I_JdCWg58Is/freezing-rails-with-git" rel="alternate" type="text/html" />
    <title>Freezing Rails with Git</title>
<content type="html">
            &lt;p&gt;As you've &lt;a href="http://blog.rubyonrails.com/2008/4/11/rails-premieres-on-github"&gt;probably heard&lt;/a&gt;, Rails now moved to &lt;a href="http://github.com/rails/rails"&gt;its own GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If, like me you were a heavy &lt;a href="http://piston.rubyforge.org/"&gt;piston&lt;/a&gt; user, you are wondering how you will be able to do the same thing if you switch to git. &lt;/p&gt;

&lt;p&gt;First off, you need to know that Piston will soon support git. As a matter a fact it already does. At least you can download a beta version from &lt;a href="http://blog.teksol.info/tags/piston"&gt;François's blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can also go with &lt;a href="http://evil.che.lu/projects/braid"&gt;giston/braids&lt;/a&gt; which was meant to make the svn/switch easy on you. I heard rumors that &lt;a href="http://evil.che.lu"&gt;evilchelu&lt;/a&gt; might not keep on developing this project. You might want to check with him.&lt;/p&gt;

&lt;p&gt;Personally I didn't really like using any of these solutions. Rails also came with its' own approach. (&lt;a href="http://github.com/rails/rails/commit/4b17082107aced980fc4b511028ee763247bc5ab"&gt;rake rails:freeze:edge&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;When I recently worked on &lt;a href="http://railsontherun.com/2008/4/15/merb-tip-how-to-freeze-a-project"&gt;Merb's freezer&lt;/a&gt;, I discovered the power of &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-submodule.html"&gt;git submodules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Submodules allow you to import "modules" from other git repos inside your own repo. Basically they do what piston does for SVN, apart that submodules are built-in git. Of course it has an expected limitation, you can only add git submodules. &lt;/p&gt;

&lt;p&gt;The good news is that Rails moved to git and now you can "freeze" Rails as a submodule and update really easily!&lt;/p&gt;

&lt;p&gt;First thing first, you need to move your project to git. If you are not confident it's a good move yet, you can use "git-svn". However, I would personally recommend you don't. I did that for few months and when I finally moved to git only, it was a pain to restructure the entire path of the app.&lt;/p&gt;

&lt;p&gt;Anyways, let's say you created a new &lt;a href="http://github.com"&gt;github&lt;/a&gt; project and if still wish to use git svn do:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="er"&gt;$&lt;/span&gt; git-svn import svn&lt;span class="sy"&gt;:/&lt;/span&gt;/path-to-your-svn-repo project-name&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;$&lt;/span&gt; cd project-name&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;$&lt;/span&gt; git remote add origin git&lt;span class="iv"&gt;@github&lt;/span&gt;.com&lt;span class="sy"&gt;:matta&lt;/span&gt;/project-name.git&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;$&lt;/span&gt; git push origin master&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;Your project is now under git, but if you pistonized Rails, you can't update it anymore :(&lt;/p&gt;

&lt;p&gt;Do not fear my dear friend and do as follows:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="er"&gt;$&lt;/span&gt; rm -rf vendor/rails&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;$&lt;/span&gt; git commit&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;$&lt;/span&gt; git submodule add git&lt;span class="sy"&gt;:/&lt;/span&gt;/github.com/rails/rails.git vendor/rails&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;$&lt;/span&gt; git submodule init&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;$&lt;/span&gt; git commit&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;$&lt;/span&gt; &lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;That's it you are done :)&lt;/p&gt;

&lt;p&gt;Next time you want to update just do:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="er"&gt;$&lt;/span&gt; cd vendor/rails&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;$&lt;/span&gt; git remote update&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;$&lt;/span&gt; git merge origin/master&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;or you can also do&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;span class="er"&gt;$&lt;/span&gt; cd vendor/rails&lt;tt&gt;
&lt;/tt&gt;&lt;span class="er"&gt;$&lt;/span&gt; git pull&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;(yes, each plugin acts a a normal git repo)&lt;/p&gt;

&lt;p&gt;A quick note for gitHub users. If you browse your repo you won't see the vendor/rails folder and might freak out. Don't! Git is smart and wants to stay slim, instead of copying the files over, it just creates a reference to the original repo. If you try to pull your project in another folder you will see that the Rails folder gets created as expected.&lt;/p&gt;

&lt;p&gt;Personally, when plugins are not available in a git repo I usually do a simple svn export to my project vendor's folder. If I need to modify one of these plugins, I just import it to &lt;a href="http://github.com"&gt;github&lt;/a&gt; and work on it from there.&lt;/p&gt;

&lt;p&gt;You might still want to stick to Piston or Braids and that's fine, but now you won't have an excuse not to switch to Git :)&lt;/p&gt;

&lt;p&gt;UPDATE: I just found out that Graeme wrote a &lt;a href="http://woss.name/2008/04/09/using-git-submodules-to-track-vendorrails/"&gt;nice detailed post&lt;/a&gt; about tracking plugins using git, &lt;a href="http://woss.name/2008/04/09/using-git-submodules-to-track-vendorrails/"&gt;check it out&lt;/a&gt;&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/I_JdCWg58Is" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/4/16/freezing-rails-with-git</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-04-15:944</id>
    <published>2008-04-15T07:42:00Z</published>
    <updated>2008-04-15T07:43:03Z</updated>
    <category term="freezer" />
    <category term="merb" />
    <category term="merb-freezer" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/XZfQDSuk1kQ/merb-tip-how-to-freeze-a-project" rel="alternate" type="text/html" />
    <title>Merb tip - how to freeze a project?</title>
<content type="html">
            &lt;p&gt;After few of my patches got accepted by the &lt;a href="merbivore"&gt;Merb&lt;/a&gt; lead team, I was given commit access to &lt;a href="http://github.com/wycats/merb-more"&gt;merb-more&lt;/a&gt;. &lt;a href="merbivore"&gt;Merb&lt;/a&gt; doesn't really have a core team per say. It's actually managed the same way &lt;a href="http://rubini.us"&gt;Rubinius&lt;/a&gt; is managed meaning that few people such as &lt;a href="http://github.com/ezmobius"&gt;Ezra&lt;/a&gt;, &lt;a href="http://github.com/wycats"&gt;Wycats&lt;/a&gt; and &lt;a href="http://github.com/ivey"&gt;Ivey&lt;/a&gt; lead the development while many other contributors have commit rights to the different repos.&lt;/p&gt;

&lt;p&gt;Patches are handled via &lt;a href="http://github.com"&gt;GitHub pull Request&lt;/a&gt; and &lt;a href="http://merb.lighthouseapp.com/"&gt;LightHouse tickets&lt;/a&gt;. Read the following &lt;a href="http://merbivore.com/contribute.html"&gt;contribution documentation&lt;/a&gt; for more info.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.music-lyrics-chord.com/cover/Vanilla_Ice_Cool_as_Ice.jpg" alt="vanilla ice" /&gt;&lt;/p&gt;

&lt;p&gt;Anyway, I've been working on a &lt;a href="http://github.com/wycats/merb-more"&gt;merb-more&lt;/a&gt; gem called &lt;a href="http://github.com/wycats/merb-more/tree/master/merb-freezer"&gt;merb-freezer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We don't have a logo for the plugin yet so I picked a "cool" star from the late 80's to represent.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Vanilla Ice!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&amp;lt;object height="355" width="425"&gt;&amp;lt;param&gt;&amp;lt;/param&gt;&amp;lt;param&gt;&amp;lt;/param&gt;&amp;lt;embed src="http://www.youtube.com/v/Vp-is6S_b_g&amp;amp;amp;hl=en" height="355" width="425"&gt;&amp;lt;/embed&gt;&amp;lt;/object&gt;&lt;/p&gt;

&lt;p&gt;Right, so you might wonder what's the connection between a &lt;a href="http://en.wikipedia.org/wiki/Kitsch"&gt;kitsch&lt;/a&gt; white rapper and a new &lt;a href="merbivore"&gt;Merb&lt;/a&gt; Gem? Not much, apart that they are both cool (or kinda cool).&lt;/p&gt;

&lt;p&gt;Let's forget about "ice ice Baby" and focus on &lt;a href="http://github.com/wycats/merb-more/tree/master/merb-freezer"&gt;merb-freezer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://github.com/wycats/merb-more/tree/master/merb-freezer"&gt;merb-freezer&lt;/a&gt; has a simple goal: let you "freeze" your application and run it without dependencies. &lt;/p&gt;

&lt;h2&gt;Why would you want to freeze your app?&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;(This is only valid for Merb 0.9.3 and 0.9.2 edge as of April 14)&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You might have multiple applications on the same server/slice/cluster. Different applications might require different versions of Merb or some other Merb gems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You might work with a team of developers and want everyone to be using the same version of the gems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You are using Merb Edge and want to make sure that your coworkers are developing/testing against the same revision.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;How to freeze your app?&lt;/h2&gt;

&lt;p&gt;First thing, in your init.rb file you need to require merb-freezer&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;merb-freezer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;Now that you required the plugin when you get new rake tasks:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  rake freeze&lt;span class="sy"&gt;:core&lt;/span&gt;            &lt;span class="c"&gt;# Freeze core from git://github.com/wycats/merb...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  rake freeze&lt;span class="sy"&gt;:more&lt;/span&gt;            &lt;span class="c"&gt;# Freeze more from git://github.com/wycats/merb...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  rake freeze&lt;span class="sy"&gt;:plugins&lt;/span&gt;         &lt;span class="c"&gt;# Freeze plugins from git://github.com/wycats/m...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;The rake freeze tasks use by default git submodules to freeze the various components. That means that you need to have your project under git to use that feature. However, if you didn't switch to git yet, do no worry, we have a plan B.&lt;/p&gt;

&lt;p&gt;When you run the freeze tasks a framework directory is created at the root of the folder and the gems are checked out there.&lt;/p&gt;

&lt;p&gt;Not a git user? We thought of you and added an option for you to use rubygems. &lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  rake freeze&lt;span class="sy"&gt;:core&lt;/span&gt; &lt;span class="co"&gt;MODE&lt;/span&gt;=rubygems&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;When doing that, you are freezing the latest version available on the rubygems server or installed locally.
Note that when using the default mode, you are pulling the latest version of Merb from the official git repo. If you want to do that using rubygems you will need to checkout the git repos locally and install the gems yourself before freezing them.&lt;/p&gt;

&lt;p&gt;Also it's worth noting that you can also do all of that manually, as long as you follow the same conventions you should be fine.&lt;/p&gt;

&lt;h2&gt;How to use the freezing gems?&lt;/h2&gt;

&lt;p&gt;If you are a Rails user, you might expect that Merb uses the frozen gems by default, at least that what I expected. Turns out, it's not the case since Merb avoids too much magic and unless you ask for it, Merb will use the available system gems.&lt;/p&gt;

&lt;p&gt;So how to start a frozen merb app? Easy enough:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;frozen-merb&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;That's it, you can uninstall merb-core from your system and as long as you froze merb-core, you can start your app.&lt;/p&gt;

&lt;h2&gt;How to update a frozen app?&lt;/h2&gt;

&lt;p&gt;simply re-freeze but with the UPDATE=true param&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  rake freeze&lt;span class="sy"&gt;:core&lt;/span&gt; &lt;span class="co"&gt;UPDATE&lt;/span&gt;=&lt;span class="pc"&gt;true&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;This option works for in both modes (rubygems and git submodules).&lt;/p&gt;

&lt;h2&gt;What's next?&lt;/h2&gt;

&lt;p&gt;I'd like to add a locking mechanism that would allow you to force your app to only run on specific versions of few gems. The main advantage of this approach is that you wouldn't need to freeze files in your repo as long as you have the required versions on your machine. &lt;/p&gt;

&lt;p&gt;I would also like to extend the freezer to let you use the submodules to freeze other gems.&lt;/p&gt;

&lt;p&gt;Other suggestions? Found a bug? Want to submit a patch?  Leave me a comment or use &lt;a href="http://merb.lighthouseapp.com/"&gt;the Merb LightHouse ticketing system&lt;/a&gt;&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/XZfQDSuk1kQ" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/4/15/merb-tip-how-to-freeze-a-project</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-04-10:872</id>
    <published>2008-04-10T08:10:00Z</published>
    <updated>2008-04-10T08:13:38Z</updated>
    <category term="benchmark" />
    <category term="merb" />
    <category term="rails" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/WzeNB-4ryTU/rails-or-merb-what-s-best-for-you" rel="alternate" type="text/html" />
    <title>Rails or Merb, what's best for you?</title>
<content type="html">
            &lt;p&gt;&lt;img src="http://brainspl.at/louiecon.gif" alt="" /&gt;&lt;/p&gt;

&lt;p&gt;If you follow my blog, you already know what &lt;a href="http://merbivore.com"&gt;Merb&lt;/a&gt; is.&lt;/p&gt;

&lt;p&gt;I love Rails and I truly believe it has changed web development. At least it has changed the way I do web development. &lt;/p&gt;

&lt;p&gt;But Merb looks slick, apparently is way faster than Rails, and has less "fluff" and less magic. &lt;/p&gt;

&lt;p&gt;Now that we are getting really close to a Merb 1.0 (scheduled for Rails Conf '08) it's time to evaluate if Merb is the good choice for some of my clients' projects.&lt;/p&gt;

&lt;p&gt;However, according to Merb's author, Ezra, at MountainWest RubyConf 2008, &lt;a href="http://mwrc2008.confreaks.com/02zygmuntowicz.html"&gt;Rails will get you there faster&lt;/a&gt;. In a client's case, they don't need to build a huge app but need a lot of speed and the ability to easily handle a heavy load right away without using caching. Also most of the traffic will go through an API so we won't have to manage too many views.&lt;/p&gt;

&lt;h2&gt;Let's see how fast Merb really is.&lt;/h2&gt;

&lt;p&gt;To test Merb's speed, I built the very same prototype using Merb 0.9.2 and Rails Edge (pre 2.1). Both apps use ActiveRecord and are connected to a UTF8 MySQL database, both apps have exactly the same views. (Note that Merb would run way faster using DataMapper, but I don't feel that DM 0.9x is production ready yet, also, using a rack handler would certainly be way faster but my goal was really to compare ActionPack vs Merb.)&lt;/p&gt;

&lt;p&gt;Both apps use the same ActiveRecord class, their controllers are a bit different but basically do the same thing.&lt;/p&gt;

&lt;p&gt;Here is what was tested:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The Merb/Rails app should receive a GET request with a JSON object in the query. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Merb/Rails app should route the request to a controller and pass the JSON object to an AR class.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The AR class should parse the JSON object (which contains an array of objects), extract each object, and try to find them in the database using one of the attributes. If the object isn't found, it should be created, otherwise it should return the AR object. The amount of hits should be incremented by 1 and the object should be saved back to the database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A simple HTML view should be rendered&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Quick Merb benchmark&lt;/h2&gt;

&lt;p&gt;&lt;img src="http://merbivore.com/img/header_logo.png" alt="merb" /&gt;&lt;/p&gt;

&lt;p&gt;I setup Merb to run locally on my MacBook 2.16Ghz Core Duo 2, 2Gb Ram. To test the raw performance, Merb is started in production mode.&lt;/p&gt;

&lt;p&gt;I then used httperf to make 10000 connections to the server at a rate of 500 (--rate=500 --send-buffer=4096 --recv-buffer=16384 --num-conns=10000 --num-calls=1)&lt;/p&gt;

&lt;p&gt;Here are the results:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Maximum connect burst length: 29
Total: connections 4377 requests 4221 replies 2932 test-duration 41.629 s
Connection rate: 105.1 conn/s (9.5 ms/conn, &amp;lt;=1022 concurrent connections)
Connection time [ms]: min 41.0 avg 1920.4 max 35390.8 median 898.5 stddev 4887.3
Connection time [ms]: connect 2118.1
Connection length [replies/conn]: 1.000

Request rate: 101.4 req/s (9.9 ms/req)
Request size [B]: 321.0

*Reply rate [replies/s]: min 0.0 avg 73.3 max 143.0 stddev 65.8 (8 samples)*
Reply time [ms]: response 809.0 transfer 18.1
Reply size [B]: header 121.0 content 557.0 footer 0.0 (total 678.0)
*Reply status: 1xx=0 2xx=2932 3xx=0 4xx=0 5xx=0*

CPU time [s]: user 0.35 system 36.54 (user 0.8% system 87.8% total 88.6%)
Net I/O: 78.4 KB/s (0.6*10^6 bps)

Errors: total 7068 client-timo 0 socket-timo 0 connrefused 0 connreset 1445
Errors: fd-unavail 5623 addrunavail 0 ftab-full 0 other 0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What we care about is the reply rate/s. We have an average of &lt;em&gt;73.3 requests per second&lt;/em&gt; with a standard deviation of 65.8 using 8 samples.&lt;/p&gt;

&lt;p&gt;We also make sure that all the replies were successful. (status == 2xx)&lt;/p&gt;

&lt;p&gt;I also checked the database, made sure my AR object was created and that the hits were increased. AR object hits: 2932, which matches the amount of replies reported by httperf.&lt;/p&gt;

&lt;p&gt;We don't care so much about the rest of the httperf. Let's move on to the Rails benchmark.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2&gt;Quick Rails benchmark&lt;/h2&gt;

&lt;p&gt;&lt;img src="http://www.rubyonrails.org/images/rails.png" alt="rails" /&gt;&lt;/p&gt;

&lt;p&gt;Rails is set the same way, running locally in production mode, same httperf settings.&lt;/p&gt;

&lt;p&gt;Here are the results:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Maximum connect burst length: 44

Total: connections 2923 requests 2825 replies 1672 test-duration 37.418 s

Connection rate: 78.1 conn/s (12.8 ms/conn, &amp;lt;=1022 concurrent connections)
Connection time [ms]: min 382.7 avg 5635.4 max 36384.5 median 1887.5 stddev 10103.1
Connection time [ms]: connect 3631.2
Connection length [replies/conn]: 1.000

Request rate: 75.5 req/s (13.2 ms/req)
Request size [B]: 319.0

*Reply rate [replies/s]: min 0.0 avg 43.4 max 75.2 stddev 30.8 (7 samples)*
Reply time [ms]: response 1568.1 transfer 36.7
Reply size [B]: header 471.0 content 581.0 footer 0.0 (total 1052.0)
*Reply status: 1xx=0 2xx=1672 3xx=0 4xx=0 5xx=0*

CPU time [s]: user 0.25 system 31.31 (user 0.7% system 83.7% total 84.4%)
Net I/O: 69.4 KB/s (0.6*10^6 bps)

DB hits: 1672
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;First thing, the database object was created properly and the hits incremented to 1672 which matches the amount of replies reported by httperf.&lt;/p&gt;

&lt;p&gt;Then, we notice that on this test, we only got 7 samples, that's more than enough though. The standard deviation is 30.8 which is better than Merb's 65.8. That means that in our benchmarks, the reply speed difference in Merb's requests was bigger than Rails'. Not a big deal, this is not a scientific test but it's good to acknowledge it.&lt;/p&gt;

&lt;p&gt;What we really care about is the average reply rate: 43.4&lt;/p&gt;

&lt;p&gt;Let's also note that all the replies had a 2xx status, so everything went well.&lt;/p&gt;

&lt;h2&gt;Results&lt;/h2&gt;

&lt;p&gt;Based on this really basic benchmark, my Merb app had an average reply rate of &lt;em&gt;73.3 requests per second&lt;/em&gt; against Rails' &lt;em&gt;43.4 requests per second&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That means that in this very specific case, &lt;/p&gt;

&lt;h2&gt;&lt;em&gt;Merb is 69% faster than Rails&lt;/em&gt;!  Sexy! &lt;/h2&gt;

&lt;p&gt;In other words, my Merb prototype could handle 69% more requests than the Rails prototype in the same amount of time.&lt;/p&gt;

&lt;p&gt;I heard people reporting than Merb was 3 to 5 times faster than Rails. Honestly, it really depends on what you do. By using ActiveRecord on both prototypes, I limited the speed difference since AR is not multithread and therefore Merb can't run as fast as it would using Sequel or DataMapper. By actually hitting the database on every single request, I also made sure to really compare ActionPack vs Merb.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The conclusion is simple, I recommended that my client go with Merb. Merb 1.0 is almost ready, the public API has been frozen. My client needs speed and simplicity. Using Merb I get exactly what I need and nothing more. Actually, we'll probably increase the performance by writing a rack handler and bypassing the entire framework for API calls (that should be wicked fast!).  Also, as soon as DataMapper becomes production ready, we'll switch to DM and should get way better performance!&lt;/p&gt;

&lt;p&gt;Am I suggesting to give up Rails and switch to Merb?
Absolutely not!  First off, Merb is a "lower level" framework. It requires a deeper understanding of Web Development in general and being more than just 'acquainted' with the Ruby language. So, unless you are an advanced developer or have time to learn, I would suggest to keep on using Rails (start using Merb on personal projects, it's a perfect way of learning).
If you have a lot of views and/or use loads of AJAX, RJS, built-in helpers, you probably want to stick to Rails and start looking at how you can do all of that from scratch. By default Rails uses nasty helpers that create inline javascript, and is something you really want to avoid. RJS is fun, but it goes against Merb's philosophy, so you need to make sure you can live without it (note that you can reproduce the same behavior in Merb rendering JS, it just requries more work). If you rely a lot of Rails plugins, you might want to delay your switch, Merb is pretty new and doesn't have a mass-load of plugins yet.&lt;/p&gt;

&lt;p&gt;Finally, Merb doesn't have a lot of documentation and changed a lot when 0.9 got released. To understand how Merb works, you will need to go through the source code, specs, Google, and ask on the Merb IRC channel.&lt;/p&gt;

&lt;p&gt;It turns out that in our case we have experienced developers, a great need for speed, not too many views and are following Merb's development really closely . I honestly think it's the best choice for my client and I'm excited they accepted to use Merb.&lt;/p&gt;

&lt;p&gt;Merb is addressing different issues than Rails and doing it well. I think there is a bright future for Merb. And don't even think that Rails is going away, that won't happen anytime soon! &lt;/p&gt;

&lt;p&gt;Recently, &lt;a href="http://www.us.playstation.com/Corporate/About"&gt;Sony Playstation&lt;/a&gt; even posted a &lt;a href="https://www2.recruitingcenter.net/Clients/playstation/PublicJobs/controller.cfm?jbaction=JobProfile&amp;amp;amp;Job_Id=11424&amp;amp;amp;esid=az"&gt;job post&lt;/a&gt; looking for a Rails/Merb developer. This is very promising for the Merb community!&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/WzeNB-4ryTU" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/4/10/rails-or-merb-what-s-best-for-you</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-04-08:865</id>
    <published>2008-04-08T02:11:00Z</published>
    <updated>2008-04-08T02:12:52Z</updated>
    <category term="logger" />
    <category term="merb" />
    <category term="routes" />
    <category term="tips" />
    <category term="tricks" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/ejjMY_-NW0c/merb-tips-2" rel="alternate" type="text/html" />
    <title>Merb tips II</title>
<content type="html">
            &lt;p&gt;I the &lt;a href="http://railsontherun.com/2008/4/5/merb-tips-1"&gt;previous post&lt;/a&gt; I covered few useful tips for Merb 0.9. The good news is that Merb should get its wiki setup over the week end!&lt;/p&gt;

&lt;p&gt;Here is another batch of hopefully useful tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In init.rb, you can define a dependency and specify a version number: &lt;em&gt;dependency "merb_fu", "&gt;= 1.0"&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you want to run your application from a subdirectory, once again, in your init.rb file, add: &lt;em&gt;c[:path_prefix] = "/your_prefix"&lt;/em&gt; &lt;em&gt;(note, that you can also do that in a specific environment file.)&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You feel like limiting a route to a specific request such as a DELETE? In your router.rb file add the following:&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  r.match(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/:bucket_id&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:method&lt;/span&gt; =&amp;gt; &lt;span class="sy"&gt;:delete&lt;/span&gt;).to(&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;buckets&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;destroy&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;ul&gt;
&lt;li&gt;Since we are talking about routes, what about an iPhone only route?&lt;/li&gt;
&lt;/ul&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  r.match(&lt;span class="rx"&gt;&lt;span class="dl"&gt;%r[&lt;/span&gt;&lt;span class="k"&gt;^/(.+)&lt;/span&gt;&lt;span class="dl"&gt;]&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:user_agent&lt;/span&gt; =&amp;gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;iPhone&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;).to(&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;mobile&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:title&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;Welcome Apple FanBoy&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;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;ul&gt;
&lt;li&gt;what about an admin section for my blogposts?&lt;/li&gt;
&lt;/ul&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  r.match(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;/admin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="r"&gt;do&lt;/span&gt; |admin|&lt;tt&gt;
&lt;/tt&gt;    admin.resources &lt;span class="sy"&gt;:blogposts&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;ul&gt;
&lt;li&gt;To finish with the routes, look at the &lt;a href="http://github.com/wycats/merb-core/tree/master/spec/public/router/special_spec.rb#L39-46"&gt;following merb-core spec&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  it &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;should allow you to restrict routes based on protocol&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;tt&gt;
&lt;/tt&gt;    &lt;span class="co"&gt;Merb&lt;/span&gt;::&lt;span class="co"&gt;Router&lt;/span&gt;.prepare &lt;span class="r"&gt;do&lt;/span&gt; |r|&lt;tt&gt;
&lt;/tt&gt;      r.match(&lt;span class="sy"&gt;:protocol&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;http://&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).to(&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;foo&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;bar&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;      r.default_routes&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    route_to(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/foo/bar&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).should have_route(&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;foo&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;bar&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    route_to(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/boo/hoo&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:protocol&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;https://&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).should have_route(&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;boo&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;hoo&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;You can set custom routes to only work when connected via SSL, that's just really nice!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Other quick tip. &lt;a href="http://railsontherun.com/2008/4/5/merb-tips-1"&gt;Last time&lt;/a&gt; we saw how to install locally all the required gems. Well, you can also freeze merb by doing:&lt;/li&gt;
&lt;/ul&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  merb-gen frozen-merb&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;ul&gt;
&lt;li&gt;Another common IRC question, how do I use Merb's logger. It's really easy:&lt;/li&gt;
&lt;/ul&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;Merb&lt;/span&gt;.logger.info(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;our stuff&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;Where info is the debugging level you want to send your message to.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Finally, today in IRC a Rails user asked how reset a session in Merb. Rails has a &lt;em&gt;reset_session&lt;/em&gt; method that resets the session by clearing out all the objects stored within and initializing a new session object. Merb simply uses a hash to store sessions, so &lt;em&gt;session.clear&lt;/em&gt; will do it ;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to add a comment with your Merb tips or leave a question regarding something you can't seem to be able to do with Merb.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/ejjMY_-NW0c" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/4/8/merb-tips-2</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-04-05:851</id>
    <published>2008-04-05T05:59:00Z</published>
    <updated>2008-04-21T06:05:37Z</updated>
    <category term="logger" />
    <category term="merb" />
    <category term="tricks" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/dne5oZiuxnk/merb-tips-1" rel="alternate" type="text/html" />
    <title>Merb tips I</title>
<content type="html">
            &lt;p&gt;I'm working on a post reporting a recent benchmark I did comparing Rails vs Merb performances for a client's app.&lt;/p&gt;

&lt;p&gt;In the meantime, here are few tricks you might need when using Merb 0.9x&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;In the init.rb file, uncomment and rename &lt;em&gt;c[:session_id_key]&lt;/em&gt;  (in the Merb::Config.use block)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the same block, add &lt;em&gt;c[:log_level] = :debug&lt;/em&gt;  to set a log level&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;By default, Merb logs to STDOUT, to log to a file, in the config block add &lt;em&gt;c[:log_file] = Merb.log_path + '/development.log'&lt;/em&gt;  (note that you need to create the file yourself, Merb won't do that)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;to save your gems locally, do: &lt;em&gt;sudo gem install gem_name -i gems&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;need basic HTTP auth? &lt;a href="http://github.com/wycats/merb-core/tree/e690bb81bb550e58dad519712de050141b8552d8/lib/merb-core/controller/mixins/authentication.rb#L15-46"&gt;it's now available in core&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;don't forget to require any plugins, extra gems you need (such as &lt;em&gt;merb_helpers&lt;/em&gt; or &lt;em&gt;merb-assets&lt;/em&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;don't forget to select your ORM before using the generator( so your generated goodies will be adapted to your ORM)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;routes are easy to use. In the console (merb -i) type &lt;em&gt;merb.show_routes&lt;/em&gt; to see all your named routes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if you want to use link&lt;em&gt;to, install &lt;a href="http://github.com/wycats/merb-plugins/tree/master/merb_assets"&gt;merb&lt;/em&gt;assets&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;nested routes example:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  r.resources &lt;span class="sy"&gt;:channels&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |channels|&lt;tt&gt;
&lt;/tt&gt;    channels.resources &lt;span class="sy"&gt;:shows&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |shows|&lt;tt&gt;
&lt;/tt&gt;     shows.resources &lt;span class="sy"&gt;:episodes&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;   &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;usage: &lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  url(&lt;span class="sy"&gt;:channel_shows&lt;/span&gt;, &lt;span class="sy"&gt;:channel_id&lt;/span&gt; =&amp;gt; channel)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  link_to h(channel.description), url(&lt;span class="sy"&gt;:channel&lt;/span&gt;, &lt;span class="sy"&gt;:id&lt;/span&gt; =&amp;gt; channel)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;That's it for today :)&lt;/p&gt;

&lt;p&gt;In the meantime, check this &lt;a href="http://mwrc2008.confreaks.com/02zygmuntowicz.html"&gt;Merb presentation by Ezra&lt;/a&gt; and &lt;a href="http://mwrc2008.confreaks.com/04katz.html"&gt;this DataMapper presentation by Wycats&lt;/a&gt;&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/dne5oZiuxnk" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/4/5/merb-tips-1</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-03-21:800</id>
    <published>2008-03-21T06:59:00Z</published>
    <updated>2008-03-21T06:59:57Z</updated>
    <category term="community" />
    <category term="duplo" />
    <category term="plugins" />
    <category term="rails" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/TVos-jilTdA/how-duplo-and-i-offended-people" rel="alternate" type="text/html" />
    <title>How Duplo (and I) offended people</title>
<content type="html">
            &lt;p&gt;My &lt;a href="http://railsontherun.com/2008/3/17/rails-the-duplo-generation"&gt;recent and certainly provocative post&lt;/a&gt; generated a lot of noise. Just by reading some of the &lt;a href="http://railsontherun.com/2008/3/17/rails-the-duplo-generation#comments"&gt;comments&lt;/a&gt; on my blog or on &lt;a href="http://reddit.com/r/ruby/info/6cbwo/comments/"&gt;reddit&lt;/a&gt; I could only notice that some people took offense and some people tried to push the metaphor way too far. At the same time, it generated a lot of interesting discussions even &lt;a href="http://msforums.ph/forums/p/47347/226547.aspx"&gt;outside&lt;/a&gt; of our &lt;em&gt;small&lt;/em&gt; Ruby community.&lt;/p&gt;

&lt;h2&gt;A few clarifications:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Rails is an awesome framework, and to be honest I really like the fact that it's accessible to newbies while offering great tools&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rails Plugins that I like calling Duplo blocks are great and I use a bunch in most of my projects&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I, myself wrote a bunch of &lt;a href="http://github.com/matta/"&gt;plugins and gems&lt;/a&gt; never as great as the one mentioned in &lt;a href="http://railsontherun.com/2008/3/17/rails-the-duplo-generation"&gt;my post&lt;/a&gt; though&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No, I don't think you are dumb if you don't have a clue how Rails or Rails plugins work&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also agree that the &lt;img src="http://cache.lego.com/upload/contentTemplating/LifestyleProductsBags/otherfiles/1033/uploadF2767709-6EFA-4D99-93FA-13F75766309B.jpg" alt="Duplo" /&gt; metaphor is very limited and doesn't stretch... but who cares.. it's funny.&lt;/p&gt;

&lt;h2&gt;&lt;em&gt;What did I mean to say&lt;/em&gt;&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Rails plugins are useful, use them and &lt;em&gt;ABUSE&lt;/em&gt; them. Even though most of them are very well written I strongly believe you would become a better developer if you understand how they work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A &lt;em&gt;Duplo&lt;/em&gt; doesn't do exactly what you want it to do, don't &lt;em&gt;bitch&lt;/em&gt; about it. Try submitting a patch or if you can write your own plugin.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you are using a plugin on a regular basis, give it some love. Submit some documentation, write a blog post, send a thank you email.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A great framework and a bunch of nice plugins are awesome tools for developers but they won't replace your brain.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, there you go, this time around I tried to be more straight forward and I even apologize if I offended you.&lt;/p&gt;

&lt;p&gt;Finally, I don't believe the Rails community is a bunch of &lt;em&gt;obnoxious-arrogant-wannabe-rockstars&lt;/em&gt;, and certainly not a ghetto. We all started as newbies and I hope a lot of newbies will join the fun and learn through Rails and later provide the community with a lot of awesome Duplos!&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/TVos-jilTdA" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/3/21/how-duplo-and-i-offended-people</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-03-17:755</id>
    <published>2008-03-17T06:39:00Z</published>
    <updated>2008-03-17T07:19:57Z</updated>
    <category term="community" />
    <category term="duplo" />
    <category term="lego" />
    <category term="plugins" />
    <category term="rails" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/2C6r5Le0h9M/rails-the-duplo-generation" rel="alternate" type="text/html" />
    <title>Ruby on Rails: the Duplo generation</title>
<content type="html">
            &lt;p&gt;&lt;img src="http://cache.lego.com/upload/contentTemplating/LifestyleProductsBags/otherfiles/1033/uploadF2767709-6EFA-4D99-93FA-13F75766309B.jpg" alt="duplo" /&gt;
I'm sure, at least once in your life you played with Duplos. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Duplo bricks are eight times the size in volume, twice the length, height and width of traditional Lego bricks, and are &lt;strong&gt;easier to handle for younger children&lt;/strong&gt;. Despite their size, they are &lt;strong&gt;still compatible&lt;/strong&gt; with traditional Lego brick.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Duplos are great to introduce kids to the concept of Lego bricks and to get them to think about building their own creations. However you would freak out if your kid would grow up and not want to start playing with Legos and building more advanced/custom stuff.&lt;/p&gt;

&lt;p&gt;Unfortunately, that's exactly what's going on in the Rails community right now. We created a generation of Duplo developers. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rick Olson&lt;/strong&gt;, AKA &lt;a href="http://techno-weenie.net/"&gt;Technoweenie&lt;/a&gt; fathered a great majority of this Duplo generation. Rick is a Rails core member and a prolific Rails plugin developer. He has written very popular plugins and Rails apps such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://github.com/technoweenie/restful-authentication/tree"&gt;restful-authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/technoweenie/attachment_fu/tree"&gt;attachment_fu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/technoweenie/acts_as_versioned/tree"&gt;acts_as_versioned&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/technoweenie/permalink_fu/tree"&gt;permalink_fu&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://mephistoblog.com/"&gt;mephisto blog engine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://beast.caboo.se/"&gt;Beast forum&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If Rick is the father, the mother of this generation would obviously be &lt;a href="http://www.loudthinking.com/"&gt;David Heinemeier Hansson&lt;/a&gt;, creator of the Ruby on Rails framework. David has always wanted to make our lives easier, providing us with tools to avoid repeating ourselves and a mass-load of tools to create web apps in no time.&lt;/p&gt;

&lt;p&gt;Rick, David and others worked hard to provide the community with tools that cut our development times by 20% to 30% and that's just awesome. They basically took their &lt;a href="http://www.meccano.com/"&gt;meccano&lt;/a&gt; applications and extracted Duplo blocks you can play with.&lt;/p&gt;

&lt;p&gt;from &lt;img src="http://upload.wikimedia.org/wikipedia/en/thumb/b/b5/Meccano_model_Steam_shovel_excavator.jpg/250px-Meccano_model_Steam_shovel_excavator.jpg" alt="meccano" /&gt; to &lt;img src="http://upload.wikimedia.org/wikipedia/en/thumb/e/eb/Duplo_bricks.jpg/250px-Duplo_bricks.jpg" alt="Duplo" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem is that a generation of Rubyists has grown up being used to getting everything pre written for them. They haven't yet passed the "Duplo stage" and basically write applications putting a few blocks together, only writing 10 to 20% and barely understand 5%.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On top of that, what really annoys me is that, these very same developers complain about the existing plugins, always ask for more and don't give anything back to the community.&lt;/p&gt;

&lt;p&gt;The problem is that it's always the same people giving and helping. Relatively quickly, the community grows and people supporting it get tired. I won't go as far as &lt;a href="http://www.zedshaw.com/rants/rails_is_a_ghetto.html"&gt;Zed and his funny rant&lt;/a&gt; but we need to wake up. We need to evolve, learn how Rails magic works, give up the &lt;a href="http://www.therailsway.com/2007/8/1/dangers-of-cargo-culting"&gt;cargo culting&lt;/a&gt; and start giving back.&lt;/p&gt;

&lt;p&gt;The first thing would be to stop complaining about plugins you use on a daily basis and write your own or fork existing ones. &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt; is a good place to start forking existing projects, if you are a Rails/Ruby beginner, you can help with documentation or submit small patches. &lt;a href="http://hasmanythrough.com"&gt;Josh Susser&lt;/a&gt; wrote a &lt;a href="http://hasmanythrough.com/layingtracks/LayingTracks.pdf"&gt;nice tutorial&lt;/a&gt; on how to commit changes (patches/documentation).&lt;/p&gt;

&lt;p&gt;Why not blog about issues you have just faced and how you resolved them. Start writing small plugins/gems. Try helping people on the various mailing lists. &lt;/p&gt;

&lt;p&gt;And finally, drop the Duplos and start playing with Legos - don't use plugins just because they are available to you, make sure you fully understand what the plugins you use do! Learn more about Rails guts and start using it in a way that makes sense to you.&lt;/p&gt;

&lt;p&gt;Why not even switch to meccano and take a look at &lt;a href="http://merbivore.com"&gt;Merb&lt;/a&gt;&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/2C6r5Le0h9M" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/3/17/rails-the-duplo-generation</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-03-05:682</id>
    <published>2008-03-05T07:48:00Z</published>
    <updated>2008-03-05T07:52:49Z</updated>
    <category term="git" />
    <category term="plugins" />
    <category term="projects" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/72P81n-Pzzk/starting-the-migration-to-github" rel="alternate" type="text/html" />
    <title>starting the migration to GitHub</title>
<content type="html">
            &lt;p&gt;I started moving some of my projects to &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://github.com/matta"&gt;Here&lt;/a&gt; is my &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt; account.&lt;/p&gt;

&lt;p&gt;Projects moved to &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://github.com/matta/globalite/tree"&gt;GlobaLite&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://github.com/matta/ar-backup/tree"&gt;ActiveRecord Backup&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="http://github.com/matta/mimetype-fu/tree"&gt;mimetype-fu&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm planning on moving &lt;a href="http://rubyforge.org/projects/googlecharts/"&gt;GoogleCharts&lt;/a&gt;, &lt;a href="http://rubyforge.org/projects/random-word-gen/"&gt;RandomWordGenerator&lt;/a&gt; and some not released stuff to GitHub so people can have fun forking my projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://git.or.cz/"&gt;Git&lt;/a&gt; and &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt; are the new cool things. GitHub is planning on setting up a gem server while they are already offering tarball download and a post-receive hook. (they also plan on becoming myspace for geeks, but that's another story)&lt;/p&gt;

&lt;p&gt;Do you have to switch to git and github? Honestly, ...no you don't.. 
Git can act as SVN, but let's be honest, if you switch to a new SCM it needs to do more. I've been using Git for a couple of months and even though I still don't have a full understanding of this SCM, I really enjoy using it.&lt;/p&gt;

&lt;p&gt;So, get over it, learn on your own or purchase &lt;a href="https://peepcode.com/products/git"&gt;this excellent peepcode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Email me to get a GitHub invite (Tom and Chris gave me some invites for readers) or/and try &lt;a href="http://gitorious.org/"&gt;Gitorious&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The fact that some major players (&lt;a href="http://topfunky.com/"&gt;Topfunky&lt;/a&gt;, &lt;a href="http://weblog.techno-weenie.net/2008/3/4/my-gushing-github-love-letter"&gt;technoweenie&lt;/a&gt;, &lt;a href="http://errtheblog.com/"&gt;Chris &amp;amp; PJ&lt;/a&gt;, &lt;a href="http://railstips.org/2008/2/16/git-and-github/"&gt;jnunemaker&lt;/a&gt; and major projects such as &lt;a href="http://weblog.rubyonrails.com/2008/2/28/capistrano-2-2-0"&gt;capistrano&lt;/a&gt;, &lt;a href="http://rubyhitsquad.com/Vlad_the_Deployer.html"&gt;vlad the deployer&lt;/a&gt; and &lt;a href="http://merbivore.com"&gt;Merb&lt;/a&gt; use and support Git is a sign that it's the next big thing. &lt;/p&gt;

&lt;p&gt;Also, I believe that a lot of developers will also be motivated to move their plugins/gems to GitHub because they simply can't always maintain their own libs and/or just hope people will fork their project and contribute back.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/72P81n-Pzzk" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/3/5/starting-the-migration-to-github</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-03-03:668</id>
    <published>2008-03-03T08:22:00Z</published>
    <updated>2008-03-03T08:23:04Z</updated>
    <category term="contribute" />
    <category term="git" />
    <category term="github" />
    <category term="merb" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/NwP0KxfXdEw/how-to-use-github-and-submit-a-patch" rel="alternate" type="text/html" />
    <title>How to use github and submit a patch</title>
<content type="html">
            &lt;p&gt;If you don't know about &lt;a href="http://git.or.cz/"&gt;git&lt;/a&gt; and &lt;a href="http://github.com"&gt;github&lt;/a&gt; yet, it's time you clean up your RSS feeds and find some good source of information.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://github.com"&gt;Github&lt;/a&gt; is used by the &lt;a href="http://merbivore.com"&gt;Merb core team&lt;/a&gt; and I'll show you how to use github to fork Merb, make your modifications and "submit your patch".&lt;/p&gt;

&lt;p&gt;This is the exact reason why github is simply awesome, it makes forking projects just super simple and submitting changes even easier.&lt;/p&gt;

&lt;p&gt;First thing, you need to have a github account, if you don't have one yet, email me, I have a couple of invitations left, otherwise, just wait until github gets public.&lt;/p&gt;

&lt;p&gt;Now, let's go to &lt;a href="http://github.com/wycats/merb-core/tree/master"&gt;Merb's repository&lt;/a&gt; and fork Merb-core by clicking on the fork button.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080303-q2aceaadcqk59kqck4b199bdmh.jpg" alt="fork merb" /&gt;&lt;/p&gt;

&lt;p&gt;Actually, for this example, I'll fork &lt;a href="http://github.com/wycats/merb-plugins/tree/master"&gt;merb-plugins&lt;/a&gt; because I want to improve the ActiveRecord rake tasks.&lt;/p&gt;

&lt;p&gt;Because I forked merb-plugins, I now have my own forked repo: !&lt;img src="http://img.skitch.com/20080303-g8jas46gq1enn9fhu1t7rsyunj.jpg" alt="my forked repo" /&gt;&lt;/p&gt;

&lt;p&gt;I'll start by checking out/cloning my forked repo locally.&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;git clone git&lt;span class="iv"&gt;@github&lt;/span&gt;.com&lt;span class="sy"&gt;:matta&lt;/span&gt;/merb-plugins.git&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;!&lt;img src="http://img.skitch.com/20080303-rf87t44c3c6m6hqy5b38ksycua.jpg" alt="git clone" /&gt;&lt;/p&gt;

&lt;p&gt;Great I can now make my own changes.... but wait, what if the merb core team makes a change to the code? Well, I need to track their changes. Here is how:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;git remote add coreteam git&lt;span class="sy"&gt;:/&lt;/span&gt;/github.com/wycats/merb-plugins.git&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;FYI, it adds the following to edit .git/config:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  [remote &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;coreteam&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;  url = git&lt;span class="sy"&gt;:/&lt;/span&gt;/github.com/wycats/merb-plugins.git&lt;tt&gt;
&lt;/tt&gt;  fetch = +refs/heads/*&lt;span class="sy"&gt;:refs&lt;/span&gt;/remotes/coreteam/*&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;then &lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;git fetch coreteam&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;and finally&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;git checkout -b coreteam coreteam/master&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;You can now track the latest change and merge them with your branch. Note that you can also track other forks and merge some other changes. (just that feature is worth using git)&lt;/p&gt;

&lt;p&gt;Alright, now you can do your stuff, and push your local change to your remote repo at github.&lt;/p&gt;

&lt;p&gt;Once you are done, you can simply click on the "pull request button"&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080303-xxh5d3a2uu65ksf8u4i9tga59e.jpg" alt="pull request button" /&gt;&lt;/p&gt;

&lt;p&gt;fill up the form and select the recipient. (wycats in this example if you want him to merge your changes into the official version of Merb).&lt;/p&gt;

&lt;p&gt;&lt;img src="http://img.skitch.com/20080303-dei7bxpt577gqe3d1x4ncpmq6w.jpg" alt="pull request" /&gt;&lt;/p&gt;

&lt;p&gt;p.s: The github guys are working on a gem to make our loves easier, give &lt;a href="http://github.com/defunkt/github-gem/tree/master"&gt;http://github.com/defunkt/github-gem/tree/master&lt;/a&gt; a try. I'll post about the gem when it will be a bit more stable.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/NwP0KxfXdEw" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/3/3/how-to-use-github-and-submit-a-patch</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-02-29:648</id>
    <published>2008-02-29T22:40:00Z</published>
    <updated>2008-02-29T22:48:09Z</updated>
    <category term="git" />
    <category term="git-svn" />
    <category term="repository" />
    <category term="scm" />
    <category term="subversion" />
    <category term="svn" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/dobLIqP6pk8/resolving-git-svn-conflicts" rel="alternate" type="text/html" />
    <title>resolving git-svn conflicts</title>
<content type="html">
            &lt;p&gt;I've been using &lt;a href="http://git.or.cz/"&gt;git&lt;/a&gt; and &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-svn.html"&gt;git-svn&lt;/a&gt; for a little while and never had a problem... until today.&lt;/p&gt;

&lt;p&gt;On one of my &lt;a href="http://gumgum.com"&gt;project&lt;/a&gt;, we have a SVN repo but since I prefer using Git, I'm using git-svn.&lt;/p&gt;

&lt;p&gt;Git-svn has been great, it let me create my own local branches for each new set of features (that's when I don't forget to create a branch) and to commit all the changes back to svn.&lt;/p&gt;

&lt;p&gt;The problem today happened after I did a simple git-svn rebase. I had some sort of error and my local repo looked like it got reverted to the head of the svn repo.... &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;error: patch failed: trunk/app/models/view.rb:1
error: trunk/app/models/view.rb: patch does not apply
[blah blah]
sing index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I hadn't committed to SVN for 24 hours and had a lot of work that was just checked in locally... You can imagine the panic.  &lt;a href="http://notch8.com"&gt;Rob&lt;/a&gt; started digging in the .git repo to finally find the hash representing the latest delta before the rebase. With the help of the #caboose guys, I did a simple&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git reset --hard hash-name
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which restore my repo to the pre SVN commit state. Awesome... however I still had issues to commit my stuff. After a little while I as able to commit again, worked a bit more and tried to commit again.... same error :(&lt;/p&gt;

&lt;p&gt;But this time I noticed I could simply do&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git rebase --abort
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to restore the original branch.an &lt;/p&gt;

&lt;p&gt;But I still couldn't commit properly... until I discovered that I just needed to fix the conflicts manually using&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git-mergetool
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;git-mergetool uses whichever merge tool available: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff filemerge&lt;/p&gt;

&lt;p&gt;I fixed my conflicts in no time, then did a &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git rebase --continue
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and finally&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git-svn dcommit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Looking back, I wish I knew how to properly deal with conflicts when using git-svn, I wasted a bit of my precious time ;)  hopefully this post will help you.&lt;/p&gt;

&lt;p&gt;p.s:  &lt;a href="http://brian.maybeyoureinsane.net/blog/2008/01/31/git-sake-tasks/"&gt;here&lt;/a&gt; is an interesting use of Sake to handle git-svn&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/dobLIqP6pk8" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/2/29/resolving-git-svn-conflicts</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-02-28:633</id>
    <published>2008-02-28T08:42:00Z</published>
    <updated>2008-02-28T22:41:56Z</updated>
    <category term="ec2" />
    <category term="engineyard" />
    <category term="gumgum" />
    <category term="hosting" />
    <category term="joyent" />
    <category term="launch" />
    <category term="rails" />
    <category term="scale" />
    <category term="startup" />
    <category term="techcrunch" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/W2PHTOWtNJ0/gumgum-launch-or-how-to-avoid-a-disastrous-launch" rel="alternate" type="text/html" />
    <title>GumGum launch, or how to avoid a disastrous launch.</title>
<content type="html">
            &lt;p&gt;For the last few months I worked on a Rails app called &lt;a href="http://gumgum.com"&gt;GumGum&lt;/a&gt;. &lt;a href="http://gumgum.com"&gt;GumGum&lt;/a&gt; is a licensing and distribution platform for online content. &lt;a href="http://gumgum.com"&gt;GumGum&lt;/a&gt; believes paying a flat rate to license content for online use is illogical. Offline, the flat rate model works because distribution is finite. Online, thanks to Google and other search engines, a story lives forever. &lt;a href="http://gumgum.com"&gt;GumGum&lt;/a&gt; has developed two usage models to fairly monetize a license: pay-per-use and ad supported. Pay-per-use allows publishers to license content on a CPM basis. Ad supported subsidizes the licensing revenue through advertisements, providing the publisher a free license.&lt;/p&gt;

&lt;p&gt;Simple concept and great team. When Ari Mir and Ophir Tanz approached me to work on their app I was impressed by their understanding of Web Business. It was not their first start up and as a consultant, you usually prefer to work with some experienced clients. Ari, GumGum's CPO was great at defining realistic expectations, and limit the scope of the application which was great since I'm an Agile/XP fanboy. I believe that really helped us meeting our dead line without feature creeping the app.&lt;/p&gt;

&lt;p&gt;We were finally ready to enter a public beta phase, we were running our production server on a godaddy VPS (no comment) and were on the process of migrating to &lt;a href="http://www.slicehost.com/"&gt;slicehost&lt;/a&gt; where we were running our staging environment. The plan was to go public on Tuesday 12 and have a feel for the load. We also setup an &lt;a href="http://www.amazon.com/gp/browse.html?node=201590011"&gt;EC2&lt;/a&gt; image to handle some of the background tasks and were thinking of moving to &lt;a href="http://engineyard.com"&gt;Engine Yard&lt;/a&gt; within few months.&lt;/p&gt;

&lt;p&gt;Everything was ready for a launch, when the day before D Day, Ari calls me telling me: "Good news Matt, &lt;a href="http://www.techcrunch.com/"&gt;TechCrunch&lt;/a&gt; is going to publish a blog post about us!". While he sounded really excited, I couldn't believe me ears. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The app wasn't optimized, darn it all, I hadn't even properly indexed the database, no caching, nothing. (it was in the backlog, things I was planning on doing after the public beta launch)&lt;/li&gt;
&lt;li&gt;We would never be able to handle the load. Running an app like ours definitely needs more than a 256Mb shared CPU shared host.&lt;/li&gt;
&lt;li&gt;Ari asked me if they could embed one of our license object in &lt;a href="http://www.techcrunch.com/"&gt;TechCrunch&lt;/a&gt; home page.&lt;/li&gt;
&lt;li&gt;I had 12 hours to get stuff ready.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;Trying to be ready:&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://www.techcrunch.com/"&gt;TechCrunch&lt;/a&gt; has 688k &lt;a href="http://feeds.feedburner.com/Techcrunch"&gt;RSS subscribers&lt;/a&gt;! Even though I asked Ari not to embed one of our protected object inside TC's home page, I knew he couldn't say no to &lt;a href="http://www.techcrunch.com/about-michael-arrington/"&gt;Mike Arrington&lt;/a&gt;. (little did I know, they would end up embedding 2 licenses)&lt;/p&gt;

&lt;p&gt;I hurried up and started properly indexing the database, ask advice to some of my &lt;a href="http://blog.caboo.se/"&gt;cabooser&lt;/a&gt; friends, did some quick re-factoring but obviously didn't have enough time to rewrite the way we handle tags and tooltips (the overlay popup window that displays when you rollover a picture in our browse page). &lt;a href="http://notch8.com"&gt;Rob&lt;/a&gt; helped me getting ready and we transformed our staging environment into a secondary production server hoping we would split the load.&lt;/p&gt;

&lt;p&gt;Since we didn't have a load balancer, we tried to cheat by setting up two A records for gumgum.com. The idea was that browsers would pick an ip randomly and since we were only using 1 database, everything should be fine. That was the theory, during our tests we realized that our Flash object was not using the same IP than the webpage and that was creating random issues with our licensing system.&lt;/p&gt;

&lt;p&gt;We were running out of time, I turned on page caching on few actions (home page) so even though my mongrels would die, I knew we would at least be able to display something. Because of our complex authentication system, I couldn't cache much and I didn't have time to re-factor a lot of my code or to setup &lt;a href="http://www.danga.com/memcached/"&gt;memcached&lt;/a&gt;. (on top of that I knew the product was stable and I didn't want to mess up with it).&lt;/p&gt;

&lt;h1&gt;The Storm:&lt;/h1&gt;

&lt;p&gt;&lt;a href="http://www.techcrunch.com/2008/02/13/gumgum-launches-new-image-licensing-platform/"&gt;The article got published&lt;/a&gt; and in seconds we saw the load on the main box going from 0.2 to 2.0! We were still dealing with the DNS issues and some pictures were not getting loaded. When Rails got above 60 req/s we started dropping some requests and returning 500s. That was bad, really bad. Our browse page (not optimized) was down and we handled around 80k requests in a matter of few hours. What you don't know is that each of our flash object generates a couple of requests, and that &lt;a href="http://techcrunch.com"&gt;TechCrunch&lt;/a&gt; decided to embed 2 objects on their home page.&lt;/p&gt;

&lt;p&gt;Remember, it was our launch, which was not meant to be a big launch, we were not prepared for that!&lt;/p&gt;

&lt;h1&gt;Dealing with the load:&lt;/h1&gt;

&lt;p&gt;The good thing is that my code didn't leak memory, Rails was stable and it was a good sign. We all know that "Rails CAN scale", but we also know that you need to have a proper hosting to do that. Godaddy was not handling the load and it was just the beginning. So what do you do when you have to scale and that your code isn't total junk? You call a real hosting company like &lt;a href="http://engineyard.com"&gt;EngineYard&lt;/a&gt; or &lt;a href="http://joyent.com"&gt;Joyent&lt;/a&gt;. I was lucky &lt;a href="http://www.workingwithrails.com/person/5421-ezra-zygmuntowicz"&gt;Ezra&lt;/a&gt; was online. I quickly explained to him the situation, we discussed the reason why our site was not doing so great and defined the bottlenecks. It was simple, we needed more humph. The normal waiting time to get a slice on EY was around 2 weeks back then. Ezra knew that we couldn't wait 2 weeks :p He was simply awesome, managed to find us 2 slices, set them up for us and setup our app in less than 2 hours. He even helped us configuring our old server to get NginX to bounce the requests to EY while the DNS was propagating. &lt;/p&gt;

&lt;p&gt;As soon as the switch was done, everything loaded perfectly, not a single request dropped, it was simply great.&lt;/p&gt;

&lt;p&gt;Since we are talking about scaling, hosting and facing issues, I'd like to make a simple point: $349.00 a month for a slice is NOT expensive for what you get. First off, EY slices are setup superbly, you get awesome performances out of them, they come ready for your app and you don't have to do much. Secondly, I'm not a sys admin, I really hate dealing with servers, packages, configuration, compiling crap that won't compile because I'm lame... etc...&lt;br /&gt;
EY has a bunch of experts (both Ruby and Sys admin experts) available 24/7 that always go the extra mile to help you. Last time I checked I couldn't hire a good sys admin for, let's say the price of 3 or 4 slices. Now, we get a team of guys, available, knowing their stuff and helping me for way cheaper than hiring a sys admin dude. The other thing is, I'm a consultant, I don't want to deal with servers and charge my clients for that. I also want them to be reassured and know that "yes, we can scale". The price of an EY/Joyent slice is the price you pay to be confident you can take the load.&lt;/p&gt;

&lt;h1&gt;So what now?&lt;/h1&gt;

&lt;p&gt;We have a lot of optimization to do, we are working on moving more of our stuff to EC2 to avoid being charged for bandwidth twice (user =&gt; EY =&gt; S3), we are setting up a queuing system and we have a lot of nice features to deploy. But one thing for sure, I can focus on my code since I know EY has my back and I don't have to worry about our servers.&lt;/p&gt;

&lt;p&gt;p.s: &lt;a href="http://gumgum.com"&gt;GumGum&lt;/a&gt; is doing great, a lot of people are really interested in the product, new features are coming up (we already auto import content from some major Paparazzi agencies) and we are getting a &lt;a href="http://blog.gumgum.com/2008/02/gumgums-press.html"&gt;good press coverage&lt;/a&gt;&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/W2PHTOWtNJ0" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/2/28/gumgum-launch-or-how-to-avoid-a-disastrous-launch</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-01-30:509</id>
    <published>2008-01-30T08:00:00Z</published>
    <updated>2008-01-30T08:00:48Z</updated>
    <category term="autotest" />
    <category term="BDD" />
    <category term="bdd" />
    <category term="integration" />
    <category term="RSpec" />
    <category term="rspec" />
    <category term="testing" />
    <category term="zentest" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/buFCnd1cpr8/misc-tips-and-tricks" rel="alternate" type="text/html" />
    <title>Misc tips and tricks</title>
<content type="html">
            &lt;p&gt;I haven't posted for quite a long time. The thing is I moved to a new place and I'm really busy on working clients + setting up my new office + dealing with way too much paperwork. &lt;/p&gt;

&lt;p&gt;Anyway, enough excuses, here are few tips that I believe will be useful to some of you:&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://www.zenspider.com/ZSS/Products/ZenTest/"&gt;ZenTest Autotest&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;I love autotest, but you might have noticed that sometimes (especially on big projects), ZenTest might start using more CPU than expected. On my machine, that results in the fan going off and annoying the crap out of me.&lt;/p&gt;

&lt;p&gt;The solution is quite simple, exclude all folders you don't need to monitor. To do that, update ZenTest to version 3.8.X &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo gem update ZenTest
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(older version had a different syntax)&lt;/p&gt;

&lt;p&gt;Now, edit your .autotest that should be located in ~/.autotest  (if it doesn't exist, create it).&lt;/p&gt;

&lt;p&gt;Finally add the following code:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;Autotest&lt;/span&gt;.add_hook &lt;span class="sy"&gt;:initialize&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |at|&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="s"&gt;&lt;span class="dl"&gt;%w{&lt;/span&gt;&lt;span class="k"&gt;.svn .hg .git vendor&lt;/span&gt;&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;.each {|exception| at.add_exception(exception)}&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;I personally freeze rails in vendor and I autotest is way happier when it doesn't have to monitor some extra files. (note that we also exclude folders such as .git or .svn)
(you can also include files etc... read more &lt;a href="http://blog.davidchelimsky.net/articles/2008/01/15/rspec-1-1-2-and-zentest-3-8-0"&gt;there&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;&lt;a href="http://rspec.info"&gt;RSpec&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;RSpec is certainly my favorite Ruby tool and I'm glad to say that most of my &lt;a href="http://sdruby.com/"&gt;SD.rb&lt;/a&gt; friends finally got convinced!&lt;/p&gt;

&lt;p&gt;Now, few people complained to me about spec failures outputting the full stack such as:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt; &lt;span class="co"&gt;The&lt;/span&gt; &lt;span class="co"&gt;Sessions&lt;/span&gt; controller should fail since it&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;s a test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="co"&gt;FAILED&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; expected &lt;span class="pc"&gt;true&lt;/span&gt;, got &lt;span class="pc"&gt;false&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/expectations.rb:&lt;span class="i"&gt;52&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;fail_with'&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/expectations/handler.rb:21:in &lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;handle_matcher&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/expectations/extensions/object.rb:34:in `should&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; ./spec/controllers/sessions_controller_spec.rb:&lt;span class="i"&gt;25&lt;/span&gt;:&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_methods.rb:&lt;span class="i"&gt;78&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;instance_eval'&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_methods.rb:78:in &lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;run_with_description_capturing&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_methods.rb:19:in `execute&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; &lt;span class="rx"&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;span class="k"&gt;opt&lt;/span&gt;&lt;span class="dl"&gt;/&lt;/span&gt;&lt;/span&gt;local/lib/ruby/&lt;span class="fl"&gt;1.8&lt;/span&gt;/timeout.rb:&lt;span class="i"&gt;48&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;timeout'&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_methods.rb:16:in &lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;execute&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:288:in `execute_examples&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:&lt;span class="i"&gt;287&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;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:287:in &lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;execute_examples&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:121:in `run&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:&lt;span class="i"&gt;22&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;run'&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:21: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;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:21:in `run&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/runner/options.rb:&lt;span class="i"&gt;89&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;run_examples'&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/runner/command_line.rb:19:in &lt;/span&gt;&lt;span class="dl"&gt;`&lt;/span&gt;&lt;/span&gt;run&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;&lt;tt&gt;
&lt;/tt&gt; script/spec:4:&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  Finished in 6.035147 seconds&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  400 examples, 1 failure&lt;tt&gt;
&lt;/tt&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;We can really easily change that, open you spec.opts file located in your spec folder.&lt;/p&gt;

&lt;p&gt;it probably looks like that:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  --colour&lt;tt&gt;
&lt;/tt&gt;  --format&lt;tt&gt;
&lt;/tt&gt;  progress&lt;tt&gt;
&lt;/tt&gt;  --loadby&lt;tt&gt;
&lt;/tt&gt;  mtime&lt;tt&gt;
&lt;/tt&gt;  --reverse&lt;tt&gt;
&lt;/tt&gt;  --backtrace&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;Get rid of "--backtrace" and your new failure should look like:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="i"&gt;1&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;The Sessions controller The Sessions controller should fail since it&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;s a test&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt; FAILED&lt;tt&gt;
&lt;/tt&gt;  expected false, got true&lt;tt&gt;
&lt;/tt&gt;  ./spec/controllers/sessions_controller_spec.rb:25:&lt;tt&gt;
&lt;/tt&gt;  script/spec:4:&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  Finished in 0.269956 seconds&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  15 examples, 1 failure&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;h2&gt;Other stuff you may find interesting (in no particular order):&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://opensource.thinkrelevance.com/wiki/spec-converter"&gt;spec converter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://cells.rubyforge.org/overview.html"&gt;Rails Cell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://jointheconversation.org/railsgit"&gt;Git to manage and deploy a Rails app&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://rufy.com/contacts/doc/"&gt;contacts (retrieve user's contacts from yahoo, gmail etc..)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.hashrocket.com/"&gt;Hashrocket&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.amazon.com/Rails-Way-Addison-Wesley-Professional-Ruby/dp/0321445619"&gt;one of the best Rails book of the moment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://famspam.com/"&gt;err's new baby&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.caboo.se/articles/2008/1/30/caboose-conf-2008"&gt;caboose conf 08&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/"&gt;git hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://swxruby.org/"&gt;SWX Ruby (or how to get Rails to talk with Flash even faster)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://ruby.reddit.com"&gt;Ruby Reddit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/buFCnd1cpr8" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/1/30/misc-tips-and-tricks</feedburner:origLink></entry>
  <entry xml:base="http://www.railsontherun.com/">
    <author>
      <name>matt</name>
    </author>
    <id>tag:www.railsontherun.com,2008-01-04:454</id>
    <published>2008-01-04T03:46:00Z</published>
    <updated>2008-01-04T03:47:43Z</updated>
    <category term="matchers" />
    <category term="RSpec" />
    <category term="rspec" />
    <category term="test" />
    <category term="testing" />
    <link href="http://feedproxy.google.com/~r/railsontherun/~3/MUpinI--1hE/rspec-on-rails-matchers-plugin" rel="alternate" type="text/html" />
    <title>RSpec on Rails Matchers plugin</title>
<content type="html">
            &lt;p&gt;&lt;a href="http://rspec.info"&gt;RSpec&lt;/a&gt; is an awesome testing framework. On top of being the first Ruby &lt;a href="http://en.wikipedia.org/wiki/Behavior_driven_development"&gt;BDD&lt;/a&gt; framework the core team is doing a great job in enhancing our testing experience and therefore the quality of our code.&lt;/p&gt;

&lt;p&gt;This time, I don't want to introduce to the &lt;a href="http://rspec.info/changes.html"&gt;latest changes&lt;/a&gt; but instead showing you what &lt;a href="http://joshknowles.com"&gt;Josh Knowles&lt;/a&gt;, &lt;a href="http://www.brynary.com/"&gt;Bryan Helmkamp&lt;/a&gt; and myself came up with.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://code.google.com/p/rspec-on-rails-matchers/"&gt;RSpec on Rails matchers plugin&lt;/a&gt; + &lt;a href="http://rspec-on-rails-matchers.googlecode.com/svn/textmate-bundle/RSpecOnRailsMatchers.tmbundle.zip"&gt;TextMate Bundle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Matchers are some sort of helpers that will help you cleaning up your tests. We simply came up with a collection of matchers that we think will make your like easier.&lt;/p&gt;

&lt;p&gt;We divided the matchers in 3 categories:&lt;/p&gt;

&lt;h2&gt;Associations&lt;/h2&gt;

&lt;p&gt;Verify that the association has been defined. (doesn't verify that the association works!)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Usage examples:&lt;/em&gt;&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@post&lt;/span&gt;.should have_many(&lt;span class="sy"&gt;:comments&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@comment&lt;/span&gt;.should belong_to(&lt;span class="sy"&gt;:post&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@user&lt;/span&gt;.should have_one(&lt;span class="sy"&gt;:social_security_number&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@project&lt;/span&gt;.should have_and_belong_to_many(&lt;span class="sy"&gt;:categories&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;h2&gt;Validations&lt;/h2&gt;

&lt;p&gt;Verify that a validation has been defined. (doesn't test the validation itself)&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;    object.should validate_presence_of(&lt;span class="sy"&gt;:attribute&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    object.should validate_confirmation_of(&lt;span class="sy"&gt;:attribute&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    object.should validate_uniqueness_of(&lt;span class="sy"&gt;:attribute&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    object.should validate_length_of(&lt;span class="sy"&gt;:attribute&lt;/span&gt;, &lt;span class="sy"&gt;:between&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;5&lt;/span&gt;..&lt;span class="i"&gt;10&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    object.should validate_length_of(&lt;span class="sy"&gt;:attribute&lt;/span&gt;, &lt;span class="sy"&gt;:is&lt;/span&gt; =&amp;gt; &lt;span class="i"&gt;5&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;h2&gt;Views&lt;/h2&gt;

&lt;p&gt;My personal favorite matchers, you can now do stuff like:&lt;/p&gt;

&lt;table class="CodeRay"&gt;&lt;tr&gt;
  &lt;td title="click to toggle" class="line_numbers"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;    it &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;should render new form&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;tt&gt;
&lt;/tt&gt;        render &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;/users/new.html.erb&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;        response.should have_form_posting_to(users_path) &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;          with_text_field_for(&lt;span class="sy"&gt;:user_name&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;          with_text_area_for(&lt;span class="sy"&gt;:user_address&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;          with_text_field_for(&lt;span class="sy"&gt;:user_login&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;          with_text_field_for(&lt;span class="sy"&gt;:user_email&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;          with_submit_button&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;p&gt;Check the &lt;a href="http://rspec-on-rails-matchers.googlecode.com/svn/trunk/README"&gt;readme&lt;/a&gt; for more information and details on the added matchers. I personally recommend you try the &lt;a href="http://rspec-on-rails-matchers.googlecode.com/svn/textmate-bundle/RSpecOnRailsMatchers.tmbundle.zip"&gt;TextMate Bundle&lt;/a&gt; on top of being a perfect tool for lazy devs, it also lists all the available matchers and is an excellent way of learning.&lt;/p&gt;

&lt;p&gt;We just released our first release yesterday, this is not a final version and we will keep on improving the code. If you have suggestions and patches feel free to open a ticket &lt;a href="http://code.google.com/p/rspec-on-rails-matchers/issues/lis"&gt;there&lt;/a&gt;.&lt;/p&gt;
          &lt;img src="http://feeds.feedburner.com/~r/railsontherun/~4/MUpinI--1hE" height="1" width="1"/&gt;</content>  <feedburner:origLink>http://www.railsontherun.com/2008/1/4/rspec-on-rails-matchers-plugin</feedburner:origLink></entry>
</feed>
