<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2russianfull.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Dmytro Shteflyuk's Home</title>
	
	<link>http://kpumuk.info</link>
	<description>In my blog I'll try to describe about interesting technologies, my discovery in IT and some useful things about programming.</description>
	<lastBuildDate>Tue, 09 Aug 2011 23:54:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/kpumuk-ru" /><feedburner:info uri="kpumuk-ru" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fkpumuk-ru" 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.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fkpumuk-ru" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Fkpumuk-ru" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/kpumuk-ru" 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%2Fkpumuk-ru" 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%2Fkpumuk-ru" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fkpumuk-ru" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://lenta.yandex.ru/settings.xml?name=feed&amp;url=http%3A%2F%2Ffeeds.feedburner.com%2Fkpumuk-ru" src="http://lenta.yandex.ru/i/addfeed.gif">?????? ? ??????.?????</feedburner:feedFlare><item>
		<title>Advanced Capistrano usage</title>
		<link>http://feedproxy.google.com/~r/kpumuk-ru/~3/PErU06O3AwY/</link>
		<comments>http://kpumuk.info/development/advanced-capistrano-usage/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 19:32:06 +0000</pubDate>
		<dc:creator>Dmytro Shteflyuk</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[campfire]]></category>
		<category><![CDATA[capistrano]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[passenger]]></category>
		<category><![CDATA[Ruby & Rails]]></category>

		<guid isPermaLink="false">http://kpumuk.info/?p=1205</guid>
		<description><![CDATA[One of the most important parts of a development process is an application deployment. There are many tools developed to make this process easy and painless: from the simple inploy to a complex all-in-one chef-based solutions. My tool of choice is Capistrano, simple and incredibly flexible piece of software. Today I&#8217;m going to talk about [...]]]></description>
			<content:encoded><![CDATA[<p>One of the most important parts of a development process is an application deployment. There are many tools developed to make this process easy and painless: from the simple <a href="http://github.com/dcrec1/inploy">inploy</a> to a complex all-in-one <a href="http://github.com/ezmobius/chef-deploy">chef-based</a> solutions. My tool of choice is <a href="http://www.capify.org">Capistrano</a>, simple and incredibly flexible piece of software. Today I&#8217;m going to talk about some advanced Capistrano usage scenarios.</p>
<p class="more"><span id="more-1205"></span></p>
<h3>1. Graceful Passenger restarts</h3>
<p>Passenger user guide contains a simple <a href="http://www.modrails.com/documentation/Users%20guide.html#capistrano">Capistrano recipe</a> for application server restarts. It works pretty well in almost all the cases, but there is a huge problem when you use a multi-server setup: it restarts all Passengers at the same time, so all client requests will hang (or even drop) during the time needed to start your application. The simplest solution is to restart Passengers one by one with some shift in time (for example, 15 seconds — choose this value based on how long it take to get your application up and running), so at any given moment only one of your application servers will be unavailable. In this case Haproxy (you use it, don&#8217;t you?) won&#8217;t send any requests to the restarting server, and most of your users will continue their work without any troubles.</p>
<aside class="note">
<p>All I said above is valid for Passenger 2.x, but keep in mind that Passenger 3 will support <a href="http://blog.phusion.nl/2010/06/18/the-road-to-passenger-3-technology-preview-2-stability-robustness-availability-self-healing/">zero-downtime web server restarts</a> out of the box, so this trick will not be needed anymore. We are all waiting for you, the 3rd!</p>
</aside>
<p>Let me show you how we could achieve this:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">namespace <span style="color:#ff3333; font-weight:bold;">:deploy</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; desc <span style="color:#006600; font-weight:bold;">&lt;&lt;-</span>EOF<br />
&nbsp; &nbsp; Graceful passengers restarts. <span style="color:#9900CC;">By</span> default, it restarts \<br />
&nbsp; &nbsp; passengers on servers with a <span style="color:#006666;">15</span> interval, but \<br />
&nbsp; &nbsp; this delay could be changed with the smart_restart_delay \<br />
&nbsp; &nbsp; variable <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#9966CC; font-weight:bold;">in</span> seconds<span style="color:#006600; font-weight:bold;">&#41;</span>. <span style="color:#9966CC; font-weight:bold;">If</span> you specify <span style="color:#006666;">0</span>, the restart will be \<br />
&nbsp; &nbsp; performed on all your servers immediately.<br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color:#9900CC;">cap</span> production deploy:smart_restart<br />
<br />
&nbsp; &nbsp; Yet another way to restart passenger immediately everywhere is \<br />
&nbsp; &nbsp; to specify NOW environment variable:<br />
<br />
&nbsp; &nbsp; &nbsp; NOW=<span style="color:#006666;">1</span> cap production deploy:smart_restart<br />
&nbsp; EOF<br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:smart_restart</span>, <span style="color:#ff3333; font-weight:bold;">:roles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:app</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; delay = fetch<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:smart_restart_delay</span>, <span style="color:#006666;">15</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">to_i</span><br />
&nbsp; &nbsp; delay = <span style="color:#006666;">0</span> <span style="color:#9966CC; font-weight:bold;">if</span> ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'NOW'</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> delay <span style="color:#006600; font-weight:bold;">&lt;</span>= <span style="color:#006666;">0</span><br />
&nbsp; &nbsp; &nbsp; logger.<span style="color:#9900CC;">debug</span> <span style="color:#996600;">&quot;Restarting passenger&quot;</span><br />
&nbsp; &nbsp; &nbsp; run <span style="color:#996600;">&quot;touch #{shared_path}/restart.txt&quot;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">else</span><br />
&nbsp; &nbsp; &nbsp; logger.<span style="color:#9900CC;">debug</span> <span style="color:#996600;">&quot;Greaseful passengers restart with #{delay} seconds delay&quot;</span><br />
&nbsp; &nbsp; &nbsp; parallel<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:roles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:app</span>, <span style="color:#ff3333; font-weight:bold;">:pty</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>, <span style="color:#ff3333; font-weight:bold;">:shell</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>session<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; find_servers<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:roles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:app</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each_with_index</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>server, idx<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Calculating restart delay for this server</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sleep_time = idx <span style="color:#006600; font-weight:bold;">*</span> delay<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; time_window = sleep_time <span style="color:#006600; font-weight:bold;">&gt;</span> <span style="color:#006666;">0</span> ? <span style="color:#996600;">&quot;after #{sleep_time} seconds delay&quot;</span> : <span style="color:#996600;">'immediately'</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Restart command sleeps a given number of seconds and the touches the restart.txt file</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; touch_cmd &nbsp; = sleep_time <span style="color:#006600; font-weight:bold;">&gt;</span> <span style="color:#006666;">0</span> ? <span style="color:#996600;">&quot;sleep #{sleep_time} &amp;&amp; &quot;</span> : <span style="color:#996600;">''</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; touch_cmd &nbsp;<span style="color:#006600; font-weight:bold;">&lt;&lt;</span> <span style="color:#996600;">&quot;touch #{shared_path}/restart.txt &amp;&amp; echo [`date`] Restarted Passenger #{time_window}&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; restart_cmd = <span style="color:#996600;">&quot;nohup sh -c '(#{touch_cmd}) &amp;' 2&gt;&amp;1 &gt;&gt; #{current_release}/log/restart.log&quot;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Run restart command on a given server</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; session.<span style="color:#9966CC; font-weight:bold;">when</span> <span style="color:#996600;">&quot;server.host == '#{server.host}'&quot;</span>, restart_cmd<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>The trickiest part is at the lines 25-26. There we use the <code class="codecolorer ruby default"><span class="ruby">parallel</span></code> method to run all our commands in parallel, but it has a great limitation: there is no way to substitute command parts on the fly based on server where the command is going to be executed. So instead we are building a condition for each server in the <code class="codecolorer ruby default"><span class="ruby"><span style="color:#ff3333; font-weight:bold;">:app</span></span></code> role, and calculate time shift based on its index.</p>
<aside class="note">
<p>You may have noticed that I use <code class="codecolorer ruby default"><span class="ruby">shared_path</span></code> instead of <code class="codecolorer ruby default"><span class="ruby">current_release</span></code>, and that is not a mistake. Passenger restart may be initiated by changing the modification time (touching) of the <code class="codecolorer text default"><span class="text">tmp/restart.txt</span></code> file, but there is an undocumented issue &#8211; it will, as well, be restarted when the file is gone. It means that when you have just deployed your application and there is no <code class="codecolorer text default"><span class="text">tmp/restart.txt</span></code> file created yet, the server will be restarted immediately, and then, once again, when you touch this file after a delay. The simplest solution for this problem is to put this file into a shared folder where it will stay forever, and then <a href="http://www.modrails.com/documentation/Users%20guide.html#_passengerrestartdir_lt_directory_gt">change Passenger configuration</a> so it will look for the file there: <code class="codecolorer text default"><span class="text">PassengerRestartDir /restart_files/bar</span></code>.</p>
</aside>
<p>Sometimes it&#8217;s necessary to perform an immediate restart (for example, a database migration breaks old code). We use an environment variable to do this: <code class="codecolorer bash default"><span class="bash">cap production deploy:restart <span style="color: #007800;">NOW</span>=<span style="color: #000000;">1</span></span></code></p>
<h3>2. Generating deployment stages on the fly in multi-stage environments</h3>
<p>In Scribd we use a single QA box for testing, with multiple configured applications on it. The only difference between corresponding deployment scripts is an application path (e.g. <em>/var/www/apps/qa/01</em>, <em>/var/www/apps/qa/02</em>, etc.) So how do we keep them DRY? First we have created a single deployment stage called <strong>qa</strong>, and deployed with <code class="codecolorer text default"><span class="text">cap qa deploy QAID=1</span></code>. Works, but smells bad. Today&#8217;s version is much more elegant, but it took some effort to implement:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">1</span>..<span style="color:#006666;">10</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>idx<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; qid = <span style="color:#996600;">'%02d'</span> <span style="color:#006600; font-weight:bold;">%</span> idx<br />
&nbsp; name = <span style="color:#996600;">&quot;qa#{qid}&quot;</span><br />
&nbsp; stages <span style="color:#006600; font-weight:bold;">&lt;&lt;</span> name<br />
<br />
&nbsp; desc <span style="color:#996600;">&quot;Set the target stage to `#{name}'.&quot;</span><br />
&nbsp; task<span style="color:#006600; font-weight:bold;">&#40;</span>name<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; location = fetch<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:stage_dir</span>, <span style="color:#996600;">&quot;config/deploy&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; set <span style="color:#ff3333; font-weight:bold;">:stage</span>, <span style="color:#ff3333; font-weight:bold;">:qa</span><br />
&nbsp; &nbsp; set <span style="color:#ff3333; font-weight:bold;">:qa_id</span>, qid<br />
&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">load</span> <span style="color:#996600;">&quot;#{location}/qa&quot;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#008000; font-style:italic;"># This is a tricky part. We need to re-define [cci]multistage:ensure[/cci] callback</span><br />
<span style="color:#008000; font-style:italic;"># (which is simply raises an exception), so it will not be executed for our newly</span><br />
<span style="color:#008000; font-style:italic;"># defined stages.</span><br />
<span style="color:#9966CC; font-weight:bold;">if</span> callbacks<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:start</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; idx = callbacks<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:start</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">index</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>callback<span style="color:#006600; font-weight:bold;">|</span> callback.<span style="color:#9900CC;">source</span> == <span style="color:#996600;">'multistage:ensure'</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; callbacks<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:start</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">delete_at</span><span style="color:#006600; font-weight:bold;">&#40;</span>idx<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; on <span style="color:#ff3333; font-weight:bold;">:start</span>, <span style="color:#996600;">'multistage:ensure'</span>, <span style="color:#ff3333; font-weight:bold;">:except</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> stages <span style="color:#006600; font-weight:bold;">+</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'multistage:prepare'</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>In the <strong>qa</strong> stage script we set the <code class="codecolorer ruby default"><span class="ruby"><span style="color:#ff3333; font-weight:bold;">:deploy_to</span></span></code> variable from <code class="codecolorer ruby default"><span class="ruby"><span style="color:#ff3333; font-weight:bold;">:qa_id</span></span></code>. Now we can deploy using <code class="codecolorer bash default"><span class="bash">cap qa01 deploy</span></code>. I leave the implementation of <code class="codecolorer bash default"><span class="bash">cap qa deploy</span></code>, which selects a free QA box and then performs deploy there, up to you (check the <a href="#locks">Hint 4: Deploy locks</a> explaining how to prevent stealing QA boxes by overwriting deployments using a simple locks technique).</p>
<h3>3. Campfire notifications</h3>
<p>This is the most straightforward and easy to implement feature:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">begin</span><br />
&nbsp; gem <span style="color:#996600;">'tinder'</span>, <span style="color:#996600;">'&gt;= 1.4.0'</span><br />
&nbsp; <span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'tinder'</span><br />
<span style="color:#9966CC; font-weight:bold;">rescue</span> Gem::<span style="color:#CC00FF; font-weight:bold;">LoadError</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> e<br />
&nbsp; <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;Load error: #{e}&quot;</span><br />
&nbsp; abort <span style="color:#996600;">&quot;Please update tinder, your version is out of date: 'gem install tinder -v 1.4.0'&quot;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
namespace <span style="color:#ff3333; font-weight:bold;">:campfire</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; desc <span style="color:#996600;">&quot;Send a message to the campfire chat room&quot;</span><br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:snitch</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; campfire = <span style="color:#6666ff; font-weight:bold;">Tinder::Campfire</span>.<span style="color:#9900CC;">new</span> <span style="color:#996600;">'SUBDOMAIN'</span>, <span style="color:#ff3333; font-weight:bold;">:ssl</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>, <span style="color:#ff3333; font-weight:bold;">:token</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'YOUR_TOKEN'</span><br />
&nbsp; &nbsp; room = campfire.<span style="color:#9900CC;">find_room_by_name</span> <span style="color:#996600;">'YOUR ROOM'</span><br />
&nbsp; &nbsp; snitch_message = fetch<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:snitch_message</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'MESSAGE'</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span> abort<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'Capfire snitch message is missing. Use set :snitch_message, &quot;Your message&quot;'</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; room.<span style="color:#9900CC;">speak</span><span style="color:#006600; font-weight:bold;">&#40;</span>snitch_message<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; desc <span style="color:#996600;">&quot;Send a message to the campfire chat room about the deploy start&quot;</span><br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:snitch_begin</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; set <span style="color:#ff3333; font-weight:bold;">:snitch_message</span>, <span style="color:#996600;">&quot;BEGIN DEPLOY [#{stage.upcase}]: #{ENV['USER']}, #{branch}/#{real_revision[0, 7]} to #{deploy_to}&quot;</span><br />
&nbsp; &nbsp; snitch<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; desc <span style="color:#996600;">&quot;Send a message to the campfire chat room about the deploy end&quot;</span><br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:snitch_end</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; set <span style="color:#ff3333; font-weight:bold;">:snitch_message</span>, <span style="color:#996600;">&quot;END DEPLOY [#{stage.upcase}]: #{ENV['USER']}, #{branch}/#{real_revision[0, 7]} to #{deploy_to}&quot;</span><br />
&nbsp; &nbsp; snitch<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; desc <span style="color:#996600;">&quot;Send a message to the campfire chat roob about the rollback&quot;</span><br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:snitch_rollback</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; set <span style="color:#ff3333; font-weight:bold;">:snitch_message</span>, <span style="color:#996600;">&quot;ROLLBACK [#{stage.upcase}]: #{ENV['USER']}, #{latest_revision[0, 7]} to #{previous_revision[0, 7]} on #{deploy_to}&quot;</span><br />
&nbsp; &nbsp; snitch<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
<span style="color:#008000; font-style:italic;">#############################################################</span><br />
<span style="color:#008000; font-style:italic;"># Hooks</span><br />
<span style="color:#008000; font-style:italic;">#############################################################</span><br />
<br />
before <span style="color:#ff3333; font-weight:bold;">:deploy</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; campfire.<span style="color:#9900CC;">snitch_begin</span> <span style="color:#9966CC; font-weight:bold;">unless</span> ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'QUIET'</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">to_i</span> <span style="color:#006600; font-weight:bold;">&gt;</span> <span style="color:#006666;">0</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
after <span style="color:#ff3333; font-weight:bold;">:deploy</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; campfire.<span style="color:#9900CC;">snitch_end</span> <span style="color:#9966CC; font-weight:bold;">unless</span> ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'QUIET'</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">to_i</span> <span style="color:#006600; font-weight:bold;">&gt;</span> <span style="color:#006666;">0</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
before <span style="color:#996600;">'deploy:rollback'</span>, <span style="color:#996600;">'campfire:snitch_rollback'</span></div></td></tr></tbody></table></div>
<p>To deploy without notifications use <code class="codecolorer bash default"><span class="bash">cap production deploy <span style="color: #007800;">QUIET</span>=<span style="color: #000000;">1</span></span></code> (but be careful, usually it&#8217;s not a good idea).</p>
<aside class="note">
<p>Do not forget to set the subdomain, your API key, and the room name where notifications will be pushed to. Usually it&#8217;s a good idea to create a separate user (ours is named &#8220;Marshmallow&#8221;) for such notifications (we use it for deployment messages, exceptions occurred on production boxes, CI server messages, etc).</p>
</aside>
<h3 id="locks">4. Deploy locks</h3>
<p>Sometimes it&#8217;s useful to lock deploys to a specific stage. The most common reason is that you pushed a heavy migration to the master and want to run it yourself, before the actual deploy, or performing some production servers maintenance and want to be sure nobody will interfere with your work.</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">namespace <span style="color:#ff3333; font-weight:bold;">:deploy</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; desc <span style="color:#996600;">&quot;Prevent other people from deploying to this environment&quot;</span><br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:lock</span>, <span style="color:#ff3333; font-weight:bold;">:roles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:web</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; check_lock<br />
&nbsp; &nbsp; msg = ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'MESSAGE'</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span> ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'MSG'</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:lock_message</span>, <span style="color:#996600;">'Default lock message. Use MSG=msg to customize it'</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; timestamp = <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span>.<span style="color:#9900CC;">strftime</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;%m/%d/%Y %H:%M:%S %Z&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; lock_message = <span style="color:#996600;">&quot;Deploys locked by #{ENV['USER']} at #{timestamp}: #{msg}&quot;</span><br />
&nbsp; &nbsp; put lock_message, <span style="color:#996600;">&quot;#{shared_path}/system/lock.txt&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:mode</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> 0644<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; desc <span style="color:#996600;">&quot;Check if deploys are OK here or if someone has locked down deploys&quot;</span><br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:check_lock</span>, <span style="color:#ff3333; font-weight:bold;">:roles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:web</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># We use echo in the end to reset exit code when lock file is missing</span><br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># (without it deployment will fail on this command — not exactly what we expected)</span><br />
&nbsp; &nbsp; data = capture<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;cat #{shared_path}/system/lock.txt 2&gt;/dev/null;echo&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">to_s</span>.<span style="color:#9900CC;">strip</span><br />
<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> data != <span style="color:#996600;">''</span> <span style="color:#9966CC; font-weight:bold;">and</span> !<span style="color:#006600; font-weight:bold;">&#40;</span>data =~ <span style="color:#006600; font-weight:bold;">/</span>^Deploys locked by <span style="color:#008000; font-style:italic;">#{ENV['USER']}/)</span><br />
&nbsp; &nbsp; &nbsp; logger.<span style="color:#9900CC;">info</span> <span style="color:#996600;">&quot;<span style="color:#000099;">\e</span>[0;31;1mATTENTION:<span style="color:#000099;">\e</span>[0m #{data}&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'FORCE'</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; logger.<span style="color:#9900CC;">info</span> <span style="color:#996600;">&quot;<span style="color:#000099;">\e</span>[0;33;1mWARNING:<span style="color:#000099;">\e</span>[0m You have forced the deploy&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">else</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; abort <span style="color:#996600;">'Deploys are locked on this machine'</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; desc <span style="color:#996600;">&quot;Remove the deploy lock&quot;</span><br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:unlock</span>, <span style="color:#ff3333; font-weight:bold;">:roles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:web</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; run <span style="color:#996600;">&quot;rm -f #{shared_path}/system/lock.txt&quot;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
before <span style="color:#ff3333; font-weight:bold;">:deploy</span>, <span style="color:#ff3333; font-weight:bold;">:roles</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:web</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; deploy.<span style="color:#9900CC;">check_lock</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>Now use can use <code class="codecolorer bash default"><span class="bash">cap production deploy:lock <span style="color: #007800;">MSG</span>=<span style="color: #ff0000;">&quot;Running heavy migrations&quot;</span></span></code>.</p>
<h3>5. Generating servers list on the fly</h3>
<p>Another interesting and sometimes pretty useful task is to fetch the list of servers for a deploy from some external service. For example, you have an application cloud, and do not want to change your deployment script every time you add, remove, or disable a node. Well, I have a good news for you: it&#8217;s easy!</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">namespace <span style="color:#ff3333; font-weight:bold;">:deploy</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; task <span style="color:#ff3333; font-weight:bold;">:set_nodes_from_remote_resource</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Here you will fetch the list of servers from somewhere</span><br />
&nbsp; &nbsp; nodes = <span style="color:#006600; font-weight:bold;">%</span>w<span style="color:#006600; font-weight:bold;">&#40;</span>app01 app02 app03<span style="color:#006600; font-weight:bold;">&#41;</span><br />
<br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Clear servers lists of :app and :db roles</span><br />
&nbsp; &nbsp; roles<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:app</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">clear</span><br />
&nbsp; &nbsp; roles<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:db</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">clear</span><br />
<br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Fill :app role servers lists</span><br />
&nbsp; &nbsp; nodes.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>node<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; &nbsp; parent.<span style="color:#9900CC;">role</span> <span style="color:#ff3333; font-weight:bold;">:app</span>, node<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># First server in list is a primary node and db node (to run migrations)</span><br />
&nbsp; &nbsp; primary = roles<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:app</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">first</span><br />
&nbsp; &nbsp; primary.<span style="color:#9900CC;">options</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:primary</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#0000FF; font-weight:bold;">true</span><br />
&nbsp; &nbsp; roles<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:db</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">push</span><span style="color:#006600; font-weight:bold;">&#40;</span>primary<span style="color:#006600; font-weight:bold;">&#41;</span><br />
<br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Show information in log about where we are going to deploy to</span><br />
&nbsp; &nbsp; nodes_to_deploy = roles<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:app</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">servers</span>.<span style="color:#9900CC;">map</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>server<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; &nbsp; opts = server.<span style="color:#9900CC;">options</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:primary</span><span style="color:#006600; font-weight:bold;">&#93;</span> ? <span style="color:#996600;">' (primary, db)'</span> : <span style="color:#996600;">''</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;#{server.host}#{opts}&quot;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">', '</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
<br />
&nbsp; &nbsp; logger.<span style="color:#9900CC;">info</span> <span style="color:#996600;">&quot;Deploying to #{nodes_to_deploy}&quot;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
on <span style="color:#ff3333; font-weight:bold;">:start</span>, <span style="color:#996600;">'deploy:set_nodes_from_remote_resource'</span></div></td></tr></tbody></table></div>
<p>When you run <code class="codecolorer bash default"><span class="bash">cap production deploy</span></code>, something like this will be printed to your console:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; triggering start callbacks for `deploy'<br />
&nbsp; * executing `deploy:set_nodes_from_remote_resource'<br />
&nbsp;** Deploying to app01 (primary, db), app02, app03</div></td></tr></tbody></table></div>
<p>That&#8217;s all for today. Deployment automation could be a really tricky task, but with a right tool it turns out to be a pleasure. Do you have any questions, suggestions, or some other example deployment recipes? Do me a favor, put them in a comment! Also I have (surprise!) a Twitter account <a href="http://twitter.com/kpumuk">@kpumuk</a>, and you simply must follow me there. No excuses!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=PErU06O3AwY:YxKgdv_LCZM:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=PErU06O3AwY:YxKgdv_LCZM:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=PErU06O3AwY:YxKgdv_LCZM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=PErU06O3AwY:YxKgdv_LCZM:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=PErU06O3AwY:YxKgdv_LCZM:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=PErU06O3AwY:YxKgdv_LCZM:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=PErU06O3AwY:YxKgdv_LCZM:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=PErU06O3AwY:YxKgdv_LCZM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=PErU06O3AwY:YxKgdv_LCZM:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/kpumuk-ru/~4/PErU06O3AwY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kpumuk.info/development/advanced-capistrano-usage/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://kpumuk.info/development/advanced-capistrano-usage/</feedburner:origLink></item>
		<item>
		<title>Submitting a patch to the Open Source project: composite_primary_keys</title>
		<link>http://feedproxy.google.com/~r/kpumuk-ru/~3/TGfGFM5eIxM/</link>
		<comments>http://kpumuk.info/ruby-on-rails/submitting-a-patch-to-the-open-source-project-composite_primary_keys/#comments</comments>
		<pubDate>Thu, 17 Dec 2009 10:28:12 +0000</pubDate>
		<dc:creator>Dmytro Shteflyuk</dc:creator>
				<category><![CDATA[Ruby & Rails]]></category>
		<category><![CDATA[composite_primary_keys]]></category>
		<category><![CDATA[gems]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://kpumuk.info/?p=1127</guid>
		<description><![CDATA[Not so far ago I have found a weird bug in the Open Source Ruby gem called composite_primary_keys, occurred when you specify :primary_key option for has_one or has_many association. There are two ways to get it fixed: submit an issue and wait till someone will work out this problem or fix it by yourself and [...]]]></description>
			<content:encoded><![CDATA[<p>Not so far ago I have found a weird bug in the Open Source Ruby gem called <a href="http://github.com/drnic/composite_primary_keys">composite_primary_keys</a>, occurred when you specify <code class="codecolorer ruby default"><span class="ruby"><span style="color:#ff3333; font-weight:bold;">:primary_key</span></span></code> option for <code class="codecolorer rails default"><span class="rails"><span style="color:#5A0A0A; font-weight:bold;">has_one</span></span></code> or <code class="codecolorer rails default"><span class="rails"><span style="color:#5A0A0A; font-weight:bold;">has_many</span></span></code> association. There are two ways to get it fixed: submit an <a href="http://github.com/drnic/composite_primary_keys/issues">issue</a> and wait till someone will work out this problem or fix it by yourself and then pull request to get the patch merged into the core. This is a great library and I use it in almost all my project, so I decided to help the author and fix this bug by myself. Here I will show you how to do that.</p>
<p class="more"><span id="more-1127"></span></p>
<p>I have discovered, that composite_primary_keys breaks my SQL queries when <code class="codecolorer ruby default"><span class="ruby"><span style="color:#ff3333; font-weight:bold;">:primary_key</span></span></code> option specified both for <code class="codecolorer rails default"><span class="rails"><span style="color:#5A0A0A; font-weight:bold;">has_many</span></span></code> and <code class="codecolorer rails default"><span class="rails"><span style="color:#5A0A0A; font-weight:bold;">has_one</span></span></code> associations.</p>
<h3>Step 0. Reproducing the bug</h3>
<p>First of all we need to reproduce a bug. Please note: if you know where the problem is, you can skip this step. Let&#8217;s start from a simple example:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">rails cpk_bug <span style="color: #000000; font-weight: bold;">&amp;&amp;</span> <span style="color: #7a0874; font-weight: bold;">cd</span> cpk_bug</div></td></tr></tbody></table></div>
<p>Now we will add dependencies to the <code class="codecolorer text default"><span class="text">config/environment.rb</span></code>:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">config.<span style="color:#9900CC;">gem</span> <span style="color:#996600;">'composite_primary_keys'</span></div></td></tr></tbody></table></div>
<p>and to the  <code class="codecolorer text default"><span class="text">config/environments/test.rb</span></code>:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">config.<span style="color:#9900CC;">gem</span> <span style="color:#996600;">'rspec'</span>, <span style="color:#ff3333; font-weight:bold;">:lib</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'spec'</span><br />
config.<span style="color:#9900CC;">gem</span> <span style="color:#996600;">'rspec-rails'</span>, <span style="color:#ff3333; font-weight:bold;">:lib</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span><br />
config.<span style="color:#9900CC;">gem</span> <span style="color:#996600;">'factory_girl'</span></div></td></tr></tbody></table></div>
<p>Okay. Now we are ready to start. Let&#8217;s generate some migrations:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">script<span style="color: #000000; font-weight: bold;">/</span>generate rspec_model document upload_request_id:integer title:string description:text<br />
script<span style="color: #000000; font-weight: bold;">/</span>generate rspec_model upload_request filename:string state:integer<br />
script<span style="color: #000000; font-weight: bold;">/</span>generate rspec_model copyright_request upload_request_id:integer explanation:text<br />
<span style="color: #c20cb9; font-weight: bold;">rm</span> <span style="color: #660033;">-rf</span> spec<span style="color: #000000; font-weight: bold;">/</span>fixtures<br />
rake db:migrate <span style="color: #000000; font-weight: bold;">&amp;&amp;</span> rake db:test:clone</div></td></tr></tbody></table></div>
<p>Let&#8217;s create our factories:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Factory.<span style="color:#9900CC;">define</span> <span style="color:#ff3333; font-weight:bold;">:copyright_request</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>cr<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; cr.<span style="color:#9900CC;">explanation</span> <span style="color:#996600;">&quot;This document is copyrighted by O'Reilly&quot;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
Factory.<span style="color:#9900CC;">define</span> <span style="color:#ff3333; font-weight:bold;">:document</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>d<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; d.<span style="color:#9900CC;">sequence</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:title</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>n<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#996600;">&quot;Document #{n}&quot;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; d.<span style="color:#9900CC;">description</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>a<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#996600;">&quot;The perfect description for the document '#{a.title}'&quot;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; d.<span style="color:#9900CC;">association</span> <span style="color:#ff3333; font-weight:bold;">:upload_request</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
Factory.<span style="color:#9900CC;">define</span> <span style="color:#ff3333; font-weight:bold;">:upload_request</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>ur<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; ur.<span style="color:#9900CC;">sequence</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:filename</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>n<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#996600;">&quot;file#{'%03d' % n}.pdf&quot;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; ur.<span style="color:#9900CC;">state</span> <span style="color:#006666;">0</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>And our spec which should fail:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'spec/spec_helper'</span><br />
<br />
describe Document <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; context <span style="color:#996600;">'when has copyright requests'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; before <span style="color:#ff3333; font-weight:bold;">:each</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Fake upload request used to desynchronise document and</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># upload request IDs</span><br />
&nbsp; &nbsp; &nbsp; Factory<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:upload_request</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; it <span style="color:#996600;">'should not have any copyright requests when just created'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@document</span> = Factory<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:document</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@document</span>.<span style="color:#9900CC;">copyright_requests</span>.<span style="color:#9900CC;">should</span> == <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; it <span style="color:#996600;">'should return a list of copyright requests from #copyright_requests'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@document</span> = Factory<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:document</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@request1</span> = Factory<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:copyright_request</span>, <span style="color:#ff3333; font-weight:bold;">:upload_request</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0066ff; font-weight:bold;">@document</span>.<span style="color:#9900CC;">upload_request</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@document</span>.<span style="color:#9900CC;">copyright_requests</span>.<span style="color:#9900CC;">should</span> == <span style="color:#006600; font-weight:bold;">&#91;</span>@request1<span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>Ok, it fails because we haven&#8217;t defined our associations on models. Let&#8217;s do it:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">class</span> Document <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span><br />
&nbsp; belongs_to <span style="color:#ff3333; font-weight:bold;">:upload_request</span><br />
&nbsp; <br />
&nbsp; has_many <span style="color:#ff3333; font-weight:bold;">:copyright_requests</span>, <span style="color:#ff3333; font-weight:bold;">:primary_key</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:upload_request_id</span>, <span style="color:#ff3333; font-weight:bold;">:foreign_key</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:upload_request_id</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
<span style="color:#9966CC; font-weight:bold;">class</span> UploadRequest <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
<span style="color:#9966CC; font-weight:bold;">class</span> CopyrightRequest <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span><br />
&nbsp; belongs_to <span style="color:#ff3333; font-weight:bold;">:upload_request</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>Woohoo! Specs are failing with an error we&#8217;re trying to reproduce:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">~/cpk_bug$ spec spec<br />
..F.<br />
<br />
1)<br />
'Document when has copyright requests should return a list of copyright requests from #copyright_requests' FAILED<br />
expected: [#&lt;CopyrightRequest id: 1, upload_request_id: 2, explanation: &quot;This document is copyrighted by O'Reilly&quot;, created_at: &quot;2009-12-07 11:19:11&quot;, updated_at: &quot;2009-12-07 11:19:11&quot;&gt;],<br />
&nbsp; &nbsp; &nbsp;got: [] (using ==)<br />
/Users/kpumuk/cpk_bug/spec/models/document_spec.rb:20:<br />
<br />
Finished in 0.155708 seconds<br />
<br />
4 examples, 1 failure</div></td></tr></tbody></table></div>
<h3>Step 1. Setting up an environment for composite_primary_keys gem</h3>
<p>In general to submit a patch to the Open Source project hosted by GitHub you have to perform the following steps: fork the repository on GitHub, write tests which fail, write a patch, ensure it works, push your changes to your fork repository, and submit a pull request. Let&#8217;s do just that!</p>
<p>To fork the repository I will use a perfect <a href="http://github.com/drnic/github-gem">github</a> gem by Dr Nic (BTW, he is the author of composite_primary_keys!)</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #c20cb9; font-weight: bold;">sudo</span> gem <span style="color: #c20cb9; font-weight: bold;">install</span> github<br />
gh clone drnic<span style="color: #000000; font-weight: bold;">/</span>composite_primary_keys<br />
<span style="color: #7a0874; font-weight: bold;">cd</span> composite_primary_keys<br />
gh fork</div></td></tr></tbody></table></div>
<p>Now let&#8217;s configure our test environment and run tests:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">rake local:setup<br />
rake mysql:build_databases<br />
rake test_mysql</div></td></tr></tbody></table></div>
<p>You should see something like this:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Using native MySQL<br />
Started<br />
...................................................................................<br />
Finished in 0.487679 seconds.<br />
<br />
83 tests, 262 assertions, 0 failures, 0 errors</div></td></tr></tbody></table></div>
<p>If you have any problems, check the <code class="codecolorer text default"><span class="text">test/README_tests.txt</span></code> file for help.</p>
<h3>Step 2. Reproducing failing tests inside composite_primary_keys test suite</h3>
<p>We are doing TDD, right? So before any fixes we have to write a failing test first. Gem we&#8217;re hacking has a powerful test suite with many database tables created, so all we need is just to add associations to one of models, which will cover our issue.</p>
<p>First, add this to the <code class="codecolorer text default"><span class="text">test/fixtures/membership.rb</span></code> model:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; has_many <span style="color:#ff3333; font-weight:bold;">:readings</span>, <span style="color:#ff3333; font-weight:bold;">:primary_key</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:user_id</span>, <span style="color:#ff3333; font-weight:bold;">:foreign_key</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:user_id</span><br />
&nbsp; has_one <span style="color:#ff3333; font-weight:bold;">:reading</span>, <span style="color:#ff3333; font-weight:bold;">:primary_key</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:user_id</span>, <span style="color:#ff3333; font-weight:bold;">:foreign_key</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:user_id</span>, <span style="color:#ff3333; font-weight:bold;">:order</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'id DESC'</span></div></td></tr></tbody></table></div>
<p>And this tests set goes to the <code class="codecolorer text default"><span class="text">test/test_associations.rb</span></code>:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> test_has_many_with_primary_key<br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@membership</span> = Membership.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span>, <span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; assert_equal <span style="color:#006666;">2</span>, <span style="color:#0066ff; font-weight:bold;">@membership</span>.<span style="color:#9900CC;">readings</span>.<span style="color:#9900CC;">size</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> test_has_one_with_primary_key<br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@membership</span> = Membership.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span>, <span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; assert_equal <span style="color:#006666;">2</span>, <span style="color:#0066ff; font-weight:bold;">@membership</span>.<span style="color:#9900CC;">reading</span>.<span style="color:#9900CC;">id</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> test_joins_has_many_with_primary_key<br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@membership</span> = Membership.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:first</span>, <span style="color:#ff3333; font-weight:bold;">:joins</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:readings</span>, <span style="color:#ff3333; font-weight:bold;">:conditions</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:readings</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">1</span> <span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; assert_equal <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span>, <span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#93;</span>, <span style="color:#0066ff; font-weight:bold;">@membership</span>.<span style="color:#9900CC;">id</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> test_joins_has_one_with_primary_key<br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@membership</span> = Membership.<span style="color:#9900CC;">find</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:first</span>, <span style="color:#ff3333; font-weight:bold;">:joins</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:reading</span>, <span style="color:#ff3333; font-weight:bold;">:conditions</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:readings</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">2</span> <span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; assert_equal <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span>, <span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#93;</span>, <span style="color:#0066ff; font-weight:bold;">@membership</span>.<span style="color:#9900CC;">id</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>Now <code class="codecolorer text default"><span class="text">rake test_mysql</span></code> produces following error (there are 4 of them, I will show only the first one):</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; 1) Error:<br />
test_has_many_with_primary_key(TestAssociations):<br />
ActiveRecord::StatementInvalid: Mysql::Error: Operand should contain 1 column(s): SELECT * FROM `readings` WHERE (`readings`.`user_id` = 1,1) <br />
...</div></td></tr></tbody></table></div>
<p>Well, that are the errors we are working on. Time to fix them!</p>
<h3>Step 3. Fixing the bug</h3>
<p>I will not explain how I fixed that, you can check my <a href="http://github.com/kpumuk/composite_primary_keys/commit/3e29891cf521186290570e3e489de079b085e193">commit</a> for details. Here is the diff:</p>
<div class="codecolorer-container diff twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br /></div></td><td><div class="diff codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">diff --git a/lib/composite_primary_keys/associations.rb b/lib/composite_primary_keys/associations.rb<br />
index 6b63664..<span style="color: #440088;">9a9</span>e173 <span style="">100644</span><br />
<span style="color: #888822;">--- a/lib/composite_primary_keys/associations.rb</span><br />
<span style="color: #888822;">+++ b/lib/composite_primary_keys/associations.rb</span><br />
<span style="color: #440088;">@@ -180,11 +180,12 @@ module ActiveRecord::Associations::ClassMethods</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;raise AssociationNotSupported, &quot;Polymorphic joins not supported for composite keys&quot;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;foreign_key = options<span style="">&#91;</span>:foreign_key<span style="">&#93;</span> || reflection.active_record.name.foreign_key<br />
<span style="color: #00b000;">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;primary_key = options<span style="">&#91;</span>:primary_key<span style="">&#93;</span> || parent.primary_key</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot; LEFT OUTER JOIN %s ON %s &quot; % <span style="">&#91;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;table_name_and_alias,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;composite_join_clause<span style="">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;full_keys<span style="">&#40;</span>aliased_table_name, foreign_key<span style="">&#41;</span>,<br />
<span style="color: #991111;">- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;full_keys<span style="">&#40;</span>parent.aliased_table_name, parent.primary_key<span style="">&#41;</span><span style="">&#41;</span>,</span><br />
<span style="color: #00b000;">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;full_keys<span style="">&#40;</span>parent.aliased_table_name, primary_key<span style="">&#41;</span><span style="">&#41;</span>,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span style="">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;end<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;when :belongs_to<br />
<span style="color: #440088;">@@ -338,7 +339,7 @@ module ActiveRecord::Associations</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@finder_sql &lt;&lt; &quot; AND <span style="">&#40;</span>#<span style="">&#123;</span>conditions<span style="">&#125;</span><span style="">&#41;</span>&quot; if conditions<br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else<br />
<span style="color: #991111;">- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@finder_sql = full_columns_equals<span style="">&#40;</span>@reflection.klass.table_name, @reflection.primary_key_name, @owner.quoted_id<span style="">&#41;</span></span><br />
<span style="color: #00b000;">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@finder_sql = full_columns_equals<span style="">&#40;</span>@reflection.klass.table_name, @reflection.primary_key_name, owner_quoted_id<span style="">&#41;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@finder_sql &lt;&lt; &quot; AND <span style="">&#40;</span>#<span style="">&#123;</span>conditions<span style="">&#125;</span><span style="">&#41;</span>&quot; if conditions<br />
&nbsp; &nbsp; &nbsp; &nbsp;end<br />
&nbsp;<br />
<span style="color: #440088;">@@ -386,7 +387,7 @@ module ActiveRecord::Associations</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;#<span style="">&#123;</span>@reflection.klass.quoted_table_name<span style="">&#125;</span>.#<span style="">&#123;</span>@reflection.options<span style="">&#91;</span>:as<span style="">&#93;</span><span style="">&#125;</span>_id = #<span style="">&#123;</span>@owner.quoted_id<span style="">&#125;</span> AND &quot; + <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;#<span style="">&#123;</span>@reflection.klass.quoted_table_name<span style="">&#125;</span>.#<span style="">&#123;</span>@reflection.options<span style="">&#91;</span>:as<span style="">&#93;</span><span style="">&#125;</span>_type = #<span style="">&#123;</span>@owner.class.quote_value<span style="">&#40;</span>@owner.class.base_class.name.to_s<span style="">&#41;</span><span style="">&#125;</span>&quot;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;else<br />
<span style="color: #991111;">- &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@finder_sql = full_columns_equals<span style="">&#40;</span>@reflection.klass.table_name, @reflection.primary_key_name, @owner.quoted_id<span style="">&#41;</span></span><br />
<span style="color: #00b000;">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;@finder_sql = full_columns_equals<span style="">&#40;</span>@reflection.klass.table_name, @reflection.primary_key_name, owner_quoted_id<span style="">&#41;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp;end<br />
&nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp;@finder_sql &lt;&lt; &quot; AND <span style="">&#40;</span>#<span style="">&#123;</span>conditions<span style="">&#125;</span><span style="">&#41;</span>&quot; if conditions</div></td></tr></tbody></table></div>
<p>Run tests to get the following output:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">~/cpk_bug/composite_primary_keys (master)$ rake test_mysql<br />
Using native MySQL<br />
Started<br />
.......................................................................................<br />
Finished in 0.511129 seconds.<br />
<br />
87 tests, 266 assertions, 0 failures, 0 errors</div></td></tr></tbody></table></div>
<p>We are done for now!</p>
<h3>Step 4. Committing changes and pulling request</h3>
<p>It&#8217;s time to commit our changes now:</p>
<div class="codecolorer-container bash twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="bash codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">~<span style="color: #000000; font-weight: bold;">/</span>cpk_bug<span style="color: #000000; font-weight: bold;">/</span>composite_primary_keys <span style="color: #7a0874; font-weight: bold;">&#40;</span>master<span style="color: #7a0874; font-weight: bold;">&#41;</span>$ <span style="color: #c20cb9; font-weight: bold;">git add</span> .<br />
~<span style="color: #000000; font-weight: bold;">/</span>cpk_bug<span style="color: #000000; font-weight: bold;">/</span>composite_primary_keys <span style="color: #7a0874; font-weight: bold;">&#40;</span>master<span style="color: #7a0874; font-weight: bold;">&#41;</span>$ <span style="color: #c20cb9; font-weight: bold;">git commit</span> <span style="color: #660033;">-m</span> <span style="color: #ff0000;">'Fixed several bugs in has_one and has_many associations when :primary_key specified'</span><br />
<span style="color: #7a0874; font-weight: bold;">&#91;</span>master 3e29891<span style="color: #7a0874; font-weight: bold;">&#93;</span> Fixed several bugs <span style="color: #000000; font-weight: bold;">in</span> has_one and has_many associations when :primary_key specified<br />
&nbsp;<span style="color: #000000;">3</span> files changed, <span style="color: #000000;">31</span> insertions<span style="color: #7a0874; font-weight: bold;">&#40;</span>+<span style="color: #7a0874; font-weight: bold;">&#41;</span>, <span style="color: #000000;">3</span> deletions<span style="color: #7a0874; font-weight: bold;">&#40;</span>-<span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
~<span style="color: #000000; font-weight: bold;">/</span>cpk_bug<span style="color: #000000; font-weight: bold;">/</span>composite_primary_keys <span style="color: #7a0874; font-weight: bold;">&#40;</span>master<span style="color: #7a0874; font-weight: bold;">&#41;</span>$ <span style="color: #c20cb9; font-weight: bold;">git push</span><br />
Counting objects: <span style="color: #000000;">16</span>, done.<br />
Delta compression using up to <span style="color: #000000;">2</span> threads.<br />
Compressing objects: <span style="color: #000000;">100</span><span style="color: #000000; font-weight: bold;">%</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">9</span><span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">9</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>, done.<br />
Writing objects: <span style="color: #000000;">100</span><span style="color: #000000; font-weight: bold;">%</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #000000;">9</span><span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">9</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>, <span style="color: #000000;">2.14</span> KiB, done.<br />
Total <span style="color: #000000;">9</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>delta <span style="color: #000000;">7</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>, reused <span style="color: #000000;">0</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>delta <span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#41;</span><br />
To <span style="color: #c20cb9; font-weight: bold;">git</span><span style="color: #000000; font-weight: bold;">@</span>github.com:kpumuk<span style="color: #000000; font-weight: bold;">/</span>composite_primary_keys.git<br />
&nbsp; &nbsp;050d832..3e29891 &nbsp;HEAD -<span style="color: #000000; font-weight: bold;">&gt;</span> master<br />
~<span style="color: #000000; font-weight: bold;">/</span>cpk_bug<span style="color: #000000; font-weight: bold;">/</span>composite_primary_keys <span style="color: #7a0874; font-weight: bold;">&#40;</span>master<span style="color: #7a0874; font-weight: bold;">&#41;</span>$ gh home</div></td></tr></tbody></table></div>
<p>Okay, the next step is a pull request. Last command opened a browser window with your fork. Navigate to the latest commit and press the &#8220;Pull Request&#8221; button (at the time of writing this article <code class="codecolorer text default"><span class="text">gh pull-request</span></code> didn&#8217;t worked, and you can try to fix by yourself to understand the workflow):</p>
<p><img src="http://kpumuk.info/wp-content/uploads/2009/12/Commit-3e29891cf521186290570e3e489de079b085e193-to-kpumuk_s-composite_primary_keys-GitHub.png" alt="Patching the composite_primary_keys gem" title="Patching the composite_primary_keys gem" width="633" height="654" /></p>
<p>That&#8217;s all, we have contributed to the community! Today Darrin Holst merged my commit into the core, and you can find it <a href="http://github.com/drnic/composite_primary_keys/commit/3e29891cf521186290570e3e489de079b085e193">here</a>. Not all things went smooth (I forgot to add a fixture, so tests were failing on first run), but he helped me a lot to get it working. That&#8217;s how Open Source works: we help each other to develop high quality software.</p>
<h3>Credits</h3>
<p>First of all, thanks to <a href="http://drnicwilliams.com/">Dr Nic</a> for the great plugin, one of the best piece of functionality I can&#8217;t imagine life without. Thanks to <a href="http://darrinholst.com/">Darrin Holst</a> for his patience and great help in debugging tests problem, and also for merging my commit into the composite_primary_keys core. Thanks to <a href="http://github.com/">GitHub</a> for the great Open Source code hosting solution, which makes working on Open Source projects so exciting.</p>
<p>Do you have comments or suggestions? You are welcome! Also, I will be happy if you <a href="http://twitter.com/kpumuk">follow me</a> in Twitter.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=TGfGFM5eIxM:7GDspcR2ync:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=TGfGFM5eIxM:7GDspcR2ync:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=TGfGFM5eIxM:7GDspcR2ync:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=TGfGFM5eIxM:7GDspcR2ync:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=TGfGFM5eIxM:7GDspcR2ync:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=TGfGFM5eIxM:7GDspcR2ync:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=TGfGFM5eIxM:7GDspcR2ync:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=TGfGFM5eIxM:7GDspcR2ync:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=TGfGFM5eIxM:7GDspcR2ync:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/kpumuk-ru/~4/TGfGFM5eIxM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kpumuk.info/ruby-on-rails/submitting-a-patch-to-the-open-source-project-composite_primary_keys/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://kpumuk.info/ruby-on-rails/submitting-a-patch-to-the-open-source-project-composite_primary_keys/</feedburner:origLink></item>
		<item>
		<title>My top 7 RSpec best practices</title>
		<link>http://feedproxy.google.com/~r/kpumuk-ru/~3/J1zVam3qShc/</link>
		<comments>http://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/#comments</comments>
		<pubDate>Wed, 25 Nov 2009 16:22:31 +0000</pubDate>
		<dc:creator>Dmytro Shteflyuk</dc:creator>
				<category><![CDATA[Ruby & Rails]]></category>
		<category><![CDATA[factory]]></category>
		<category><![CDATA[fixtures]]></category>
		<category><![CDATA[mock]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rake]]></category>
		<category><![CDATA[RSpec]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://kpumuk.info/?p=1080</guid>
		<description><![CDATA[I use RSpec in all my projects. It&#8217;s really hard to overemphasize how helpful it is and how much easier becomes your life if you have good specs coverage. But its outstanding flexibility enables many ways to make your specs awful: horribly slow, over-bloated, even non-readable sometimes. I do not want to teach you BDD [...]]]></description>
			<content:encoded><![CDATA[<p>I use RSpec in <a href="http://github.com/kpumuk/">all</a> <a href="http://www.scribd.com/">my</a> <a href="http://github.com/kpumuk/sphinx/">projects</a>. It&#8217;s really hard to overemphasize how helpful it is and how much easier becomes your life if you have good specs coverage. But its outstanding flexibility enables many ways to make your specs awful: horribly slow, over-bloated, even non-readable sometimes. I do not want to <a href="/library/david-chelimsky/the-rspec-book-behaviour-driven-development-with-rspec-cucumber-and-friends/">teach you BDD and RSpec</a> here, but instead I will give you some ideas how to improve your specs quality and increase efficiency of your BDD workflow.</p>
<p class="more"><span id="more-1080"></span></p>
<h3>1. Use <code class="codecolorer ruby default"><span class="ruby">before <span style="color:#ff3333; font-weight:bold;">:all</span></span></code> block carefully</h3>
<p>Sometimes it looks like a good idea to create a test data in <code class="codecolorer ruby default"><span class="ruby">before <span style="color:#ff3333; font-weight:bold;">:all</span></span></code> block. But be careful — these blocks are not wrapped in a transaction, so the data will not be rolled back after the test. In this case you should clear your data in the <code class="codecolorer ruby default"><span class="ruby">after <span style="color:#ff3333; font-weight:bold;">:all</span></span></code> block manually.</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">describe Friendship <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; before <span style="color:#ff3333; font-weight:bold;">:all</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@users</span> = <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">1</span>..<span style="color:#006666;">5</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">collect</span> <span style="color:#006600; font-weight:bold;">&#123;</span> Factory<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:user</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; after <span style="color:#ff3333; font-weight:bold;">:all</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@users</span>.<span style="color:#9900CC;">each</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>user<span style="color:#006600; font-weight:bold;">|</span> user.<span style="color:#9900CC;">destroy</span>! <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; it <span style="color:#996600;">'should do something'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Something interesting with @users</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>Another option is to move your <code class="codecolorer ruby default"><span class="ruby">before <span style="color:#ff3333; font-weight:bold;">:all</span></span></code> blocks to <code class="codecolorer ruby default"><span class="ruby">before <span style="color:#ff3333; font-weight:bold;">:each</span></span></code> to make them rolled back automatically.</p>
<h3>2. For each test create exactly what it needs</h3>
<p>Fixtures are cool when you start working on a project. But they quickly become painful while project grows: you add a new field to a fixture and break a half of your tests. There are tons of plugins which could simplify test data creation, I personally recommend <a href="http://github.com/thoughtbot/factory_girl">factory_girl</a>: it&#8217;s pretty slick and easy to use.</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Factory.<span style="color:#9900CC;">define</span> <span style="color:#ff3333; font-weight:bold;">:user</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>f<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; f.<span style="color:#9900CC;">sequence</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:login</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>n<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#996600;">&quot;user#{n}&quot;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; f.<span style="color:#9900CC;">email</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>a<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#996600;">&quot;#{a.login}@example.com&quot;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; f.<span style="color:#9900CC;">description</span> <span style="color:#996600;">&quot;Ruby on Rails Developer&quot;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
<span style="color:#008000; font-style:italic;"># Somewhere in specs</span><br />
<span style="color:#0066ff; font-weight:bold;">@user</span> = Factory<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:user</span>, <span style="color:#ff3333; font-weight:bold;">:admin</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span><span style="color:#006600; font-weight:bold;">&#41;</span></div></td></tr></tbody></table></div>
<h3>3. Do not create hundreds of records for a particular spec</h3>
<p>Sometimes you want to test a method which operates on large set of records (filtering, trimming, etc). For example, this method returns 50 most popular videos (and no more). The straight approach is to create 51 record and make sure, that the size of the returned array is 50. When I saw a code snippet like this in our project first time, I was surprised. There was a few more pieces sharing this behavior, so here is my advice: add a parameter to the method, which will limit the number of records to return. In this case you can create 3 records, and pass 2 as a parameter.</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">describe User <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; it <span style="color:#996600;">'should return top users in User.top method'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@users</span> = <span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">1</span>..<span style="color:#006666;">3</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">collect</span> <span style="color:#006600; font-weight:bold;">&#123;</span> Factory<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:user</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; top_users = User.<span style="color:#9900CC;">top</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">all</span><br />
&nbsp; &nbsp; top_users.<span style="color:#9900CC;">should</span> have<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">entries</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
<span style="color:#9966CC; font-weight:bold;">class</span> User <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span><br />
&nbsp; <span style="color:#008000; font-style:italic;"># Select N top users. Returns 10 entries when called without arguments.</span><br />
&nbsp; <span style="color:#008000; font-style:italic;"># &nbsp; User.top.all.size &nbsp; &nbsp;# =&gt; 10</span><br />
&nbsp; <span style="color:#008000; font-style:italic;"># &nbsp; User.top(2).all.size # =&gt; 2</span><br />
&nbsp; <span style="color:#008000; font-style:italic;">#</span><br />
&nbsp; named_scope <span style="color:#ff3333; font-weight:bold;">:top</span>, <span style="color:#CC0066; font-weight:bold;">lambda</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|*</span>args<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:limit</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#40;</span>args.<span style="color:#9900CC;">size</span> <span style="color:#006600; font-weight:bold;">&gt;</span> <span style="color:#006666;">0</span> ? args<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">0</span><span style="color:#006600; font-weight:bold;">&#93;</span> : <span style="color:#006666;">10</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#125;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<h3>4. Do not over-mock</h3>
<p>Mocking is interesting and sometimes very useful technology. You may mock just everything so you spec will not hit the database. But there is a catch: your model code may be changed some day causing callers to break. Since you mock everything, you will never get failing specs. So now you should update all your mocks to fit a new interface. Also you would not be able to find SQL queries errors if you have mocked them. Instead of this I use integration approach: controller should talk to models, which have to hit the database. Real database with real data (OK, not so real). The practice 2 can help you in test data creation.</p>
<p>Bad:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">describe VideosController <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; describe <span style="color:#996600;">'.create action'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; it <span style="color:#996600;">'should assign top videos'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; params = <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:title</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'new video'</span>, <span style="color:#ff3333; font-weight:bold;">:description</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'video description'</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@video</span> = mock_model<span style="color:#006600; font-weight:bold;">&#40;</span>Video<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; Video.<span style="color:#9900CC;">should_receive</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:new</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">and_return</span><span style="color:#006600; font-weight:bold;">&#40;</span>@video<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@video</span>.<span style="color:#9900CC;">should_receive</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:update_attributes</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">with</span><span style="color:#006600; font-weight:bold;">&#40;</span>params<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">and_return</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF; font-weight:bold;">true</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; get <span style="color:#ff3333; font-weight:bold;">:index</span>, <span style="color:#ff3333; font-weight:bold;">:video</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> params<br />
&nbsp; &nbsp; &nbsp; assigns<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:video</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">should</span> be<span style="color:#006600; font-weight:bold;">&#40;</span>@video<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>Good:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">describe VideosController <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; describe <span style="color:#996600;">'.create action'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; it <span style="color:#996600;">'should assign top videos'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; params = <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:title</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'new video'</span>, <span style="color:#ff3333; font-weight:bold;">:description</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'video description'</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; get <span style="color:#ff3333; font-weight:bold;">:index</span>, <span style="color:#ff3333; font-weight:bold;">:video</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> params<br />
&nbsp; &nbsp; &nbsp; assigns<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:video</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">should_not</span> be_new_record<br />
&nbsp; &nbsp; &nbsp; assigns<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:video</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">title</span>.<span style="color:#9900CC;">should</span> == params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:title</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; assigns<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:video</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">description</span>.<span style="color:#9900CC;">should</span> == params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:description</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>But you can use mocks to skip records retrieving from the database (make sure you have specs covering corresponding model code). Let me explain this. For example, you need to render 20 entries in an RSS feed. You could create 21 record in the database using a factory, and then ensure only 20 of them were retrieved, or you could mock your finder method and check its parameter. You may not like magic numbers like 20 in this particular case, and this is a good point. Just move this magic number to the <a href="/ruby-on-rails/flexible-application-configuration-in-ruby-on-rails/">config</a> and ensure it was used to do the retrieval.</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">describe VideosController <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; describe <span style="color:#996600;">'.index action'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; it <span style="color:#996600;">'should assign top videos'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@videos</span> = <span style="color:#006600; font-weight:bold;">&#91;</span>mock_model<span style="color:#006600; font-weight:bold;">&#40;</span>Video<span style="color:#006600; font-weight:bold;">&#41;</span>, mock_model<span style="color:#006600; font-weight:bold;">&#40;</span>Video<span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; Video.<span style="color:#9900CC;">should_receive</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:top</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">with</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">50</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">and_return</span><span style="color:#006600; font-weight:bold;">&#40;</span>@videos<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; get <span style="color:#ff3333; font-weight:bold;">:index</span><br />
&nbsp; &nbsp; &nbsp; assigns<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:top_videos</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">should</span> be<span style="color:#006600; font-weight:bold;">&#40;</span>@videos<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<h3>5. Use contexts</h3>
<p>RSpec spec specifies how particular code should work. Usually, in the beginning you tell what you are going to describe in this spec, and inside describe block you specify what the code should do:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">describe Video <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; it <span style="color:#996600;">'should return 5 records in Video.top method'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; Video.<span style="color:#9900CC;">top</span>.<span style="color:#9900CC;">should</span> have<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">5</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">items</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>Usually you have more than one <code class="codecolorer ruby default"><span class="ruby">it</span></code> block for each method. To group related specs I recommend to use nested <code class="codecolorer ruby default"><span class="ruby">describe</span></code> blocks. Since <code class="codecolorer ruby default"><span class="ruby">describe</span></code> is aliased to <code class="codecolorer ruby default"><span class="ruby">context</span></code> when placed inside another <code class="codecolorer ruby default"><span class="ruby">describe</span></code>, I think it&#8217;s a good idea to use it for specs grouping. Each context may have its own <code class="codecolorer ruby default"><span class="ruby">before</span></code> and <code class="codecolorer ruby default"><span class="ruby">after</span></code> blocks (in this case parent blocks will be called right before child ones).</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">describe Video <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; describe <span style="color:#996600;">'.top'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; it <span style="color:#996600;">'should return 5 records'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; Video.<span style="color:#9900CC;">top</span>.<span style="color:#9900CC;">should</span> have<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006666;">5</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">items</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; context <span style="color:#996600;">'when just created'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; before <span style="color:#ff3333; font-weight:bold;">:each</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@video</span> = Video.<span style="color:#9900CC;">new</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># ...</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<h3>6. Create several test suites to speed up your workflow</h3>
<p>There are many things you can do to make your BDD more efficient. We will take a look at two of them: creating a separate test suites and running recently modified specs.</p>
<p>There are several standard test suites configured in RSpec by default: <code class="codecolorer text default"><span class="text">spec:controllers</span></code>, <code class="codecolorer text default"><span class="text">spec:views</span></code>, <code class="codecolorer text default"><span class="text">spec:helpers</span></code>, <code class="codecolorer text default"><span class="text">spec:lib</span></code>. Check the <code class="codecolorer text default"><span class="text">rake -T spec</span></code> output to get a list of available RSpec tasks. Let&#8217;s create a simple Rake tasks generator for spec suites:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">SPEC_SUITES = <span style="color:#006600; font-weight:bold;">&#91;</span><br />
&nbsp; <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:acl</span>, <span style="color:#ff3333; font-weight:bold;">:title</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'access control'</span>, <span style="color:#ff3333; font-weight:bold;">:files</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">%</span>w<span style="color:#006600; font-weight:bold;">&#40;</span>spec<span style="color:#006600; font-weight:bold;">/</span>controllers<span style="color:#006600; font-weight:bold;">/**/</span>acl_spec.<span style="color:#9900CC;">rb</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#125;</span>,<br />
&nbsp; <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:amazon</span>, <span style="color:#ff3333; font-weight:bold;">:title</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'Amazon libraries'</span>, <span style="color:#ff3333; font-weight:bold;">:dirs</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">%</span>w<span style="color:#006600; font-weight:bold;">&#40;</span>spec<span style="color:#006600; font-weight:bold;">/</span>lib<span style="color:#006600; font-weight:bold;">/</span>amazon<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
<span style="color:#006600; font-weight:bold;">&#93;</span><br />
<br />
namespace <span style="color:#ff3333; font-weight:bold;">:spec</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; namespace <span style="color:#ff3333; font-weight:bold;">:suite</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; SPEC_SUITES.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>suite<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; &nbsp; desc <span style="color:#996600;">&quot;Run all specs in #{suite[:title]} spec suite&quot;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#6666ff; font-weight:bold;">Spec::Rake::SpecTask</span>.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>suite<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:id</span><span style="color:#006600; font-weight:bold;">&#93;</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>t<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; spec_files = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> suite<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:files</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; suite<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:files</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">each</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>glob<span style="color:#006600; font-weight:bold;">|</span> spec_files <span style="color:#006600; font-weight:bold;">+</span>= <span style="color:#CC00FF; font-weight:bold;">Dir</span><span style="color:#006600; font-weight:bold;">&#91;</span>glob<span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> suite<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:dirs</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; suite<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:dirs</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">each</span> <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#006600; font-weight:bold;">|</span>glob<span style="color:#006600; font-weight:bold;">|</span> spec_files <span style="color:#006600; font-weight:bold;">+</span>= <span style="color:#CC00FF; font-weight:bold;">Dir</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;#{glob}/**/*_spec.rb&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; t.<span style="color:#9900CC;">spec_opts</span> = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'--options'</span>, <span style="color:#996600;">&quot;<span style="color:#000099;">\&quot;</span>#{Rails.root}/spec/spec.opts<span style="color:#000099;">\&quot;</span>&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; t.<span style="color:#9900CC;">spec_files</span> = spec_files<br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>Check what tasks are available now:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">~/test$ rake -T spec:suite<br />
<br />
(in /Users/kpumuk/test)<br />
rake spec:suite:acl &nbsp; &nbsp; # Run all specs in access control spec suite<br />
rake spec:suite:amazon &nbsp;# Run all specs in Amazon libraries spec suite</div></td></tr></tbody></table></div>
<p>It was easy! And now let&#8217;s take a look at the Rake task for running the recently touched specs (last 10 minutes).</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#008000; font-style:italic;"># Grab recently touched specs</span><br />
<span style="color:#9966CC; font-weight:bold;">def</span> recent_specs<span style="color:#006600; font-weight:bold;">&#40;</span>touched_since<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; recent_specs = <span style="color:#CC00FF; font-weight:bold;">Dir</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'app/**/*'</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">map</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>path<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">mtime</span><span style="color:#006600; font-weight:bold;">&#40;</span>path<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&gt;</span> touched_since<br />
&nbsp; &nbsp; &nbsp; spec = <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'spec'</span>, <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">dirname</span><span style="color:#006600; font-weight:bold;">&#40;</span>path<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#CC0066; font-weight:bold;">split</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;/&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span>..<span style="color:#006600; font-weight:bold;">-</span><span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">join</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'/'</span><span style="color:#006600; font-weight:bold;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; <span style="color:#996600;">&quot;#{File.basename(path, &quot;</span>.<span style="color:#006600; font-weight:bold;">*</span><span style="color:#996600;">&quot;)}_spec.rb&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; spec <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">exists</span>?<span style="color:#006600; font-weight:bold;">&#40;</span>spec<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span>.<span style="color:#9900CC;">compact</span><br />
<br />
&nbsp; recent_specs <span style="color:#006600; font-weight:bold;">+</span>= <span style="color:#CC00FF; font-weight:bold;">Dir</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'spec/**/*_spec.rb'</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#CC0066; font-weight:bold;">select</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>path<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">mtime</span><span style="color:#006600; font-weight:bold;">&#40;</span>path<span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">&gt;</span> touched_since<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span>.<span style="color:#9900CC;">uniq</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
namespace <span style="color:#ff3333; font-weight:bold;">:spec</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; desc <span style="color:#996600;">'Run all recent specs in spec directory touched in last 10 minutes'</span><br />
&nbsp; <span style="color:#6666ff; font-weight:bold;">Spec::Rake::SpecTask</span>.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:recent</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>t<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; t.<span style="color:#9900CC;">spec_opts</span> = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'--options'</span>, <span style="color:#996600;">&quot;<span style="color:#000099;">\&quot;</span>#{RAILS_ROOT}/spec/spec.opts<span style="color:#000099;">\&quot;</span>&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; t.<span style="color:#9900CC;">spec_files</span> = recent_specs<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span> <span style="color:#006600; font-weight:bold;">-</span> <span style="color:#006666;">10</span>.<span style="color:#9900CC;">minutes</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>And don&#8217;t forget to check <a href="http://gemcutter.org/gems/ZenTest">autospec</a> and <a href="http://gemcutter.org/gems/watchr">watchr</a> gems.</p>
<h3>7. Stop <code class="codecolorer text default"><span class="text">spec_helper</span></code> from being loaded multiple times</h3>
<p>Just don&#8217;t do that. If you got a big project, there is a chance that the <code class="codecolorer text default"><span class="text">spec_helper</span></code> will be required in a many different ways: <code class="codecolorer ruby default"><span class="ruby"><span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">expand_path</span></span></code>, <code class="codecolorer ruby default"><span class="ruby"><span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">join</span></span></code>, etc.,— which results in it being loaded several times and it slows down your test suite!</p>
<p>To avoid this, add the following code at the top of your <code class="codecolorer text default"><span class="text">spec_helper.rb</span></code>:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#008000; font-style:italic;"># figure out where we are being loaded from</span><br />
<span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#ff6633; font-weight:bold;">$LOADED_FEATURES</span>.<span style="color:#9900CC;">grep</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#006600; font-weight:bold;">/</span>spec\<span style="color:#006600; font-weight:bold;">/</span>spec_helper\.<span style="color:#9900CC;">rb</span><span style="color:#006600; font-weight:bold;">/</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">any</span>?<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">begin</span><br />
&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">raise</span> <span style="color:#996600;">&quot;foo&quot;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">rescue</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> e<br />
&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#006600; font-weight:bold;">&lt;&lt;-</span>MSG<br />
&nbsp; ===================================================<br />
&nbsp; It looks like spec_helper.<span style="color:#9900CC;">rb</span> has been loaded<br />
&nbsp; multiple times. <span style="color:#9900CC;">Normalize</span> the <span style="color:#CC0066; font-weight:bold;">require</span> to:<br />
<br />
&nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">&quot;spec/spec_helper&quot;</span><br />
<br />
&nbsp; Things like <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">join</span> <span style="color:#9966CC; font-weight:bold;">and</span> <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">expand_path</span> will<br />
&nbsp; cause it to be loaded multiple times.<br />
<br />
&nbsp; <span style="color:#9900CC;">Loaded</span> this time from:<br />
<br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;">#{e.backtrace.join(&quot;\n &nbsp; &nbsp;&quot;)}</span><br />
&nbsp; ===================================================<br />
&nbsp; &nbsp; MSG<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>It will show where you&#8217;ve tried to load <code class="codecolorer text default"><span class="text">spec_helper</span></code> from so you will be able to fix it immediately. Also there is an interesting snippet of code <a href="http://pragmatig.wordpress.com/2009/09/24/stop-spec_helper-from-being-loaded-multiple-times/">here</a>, which will find and replace all wrong includes.</p>
<h3>Conclusion</h3>
<p>RSpec is not a silver bullet. You can have 100% coverage and fine-grained specs, but it does not mean your application is completely bug-free. Refactor your specs, increase your programming level, and refactor again. Write specs for any issue that you, your QAs or users have faced. And remember: <strong>do not over-mock</strong>.</p>
<h3>Credits</h3>
<p>This is my first article written completely in Google Wave in collaboration with several good Russian rubyists. Thank you all, guys. I want to acknowledge the editorial help of <a href="http://erka.kpumuk.info/">Roman Dmytrenko</a> and <a href="http://kovyrin.net/">Alexey Kovyrin</a>. Robby Russell <a href="http://www.robbyonrails.com/articles/2007/02/08/is-bdd-kinkier-than-tdd">created a great picture</a> illustrating how sexy is RSpec. And thank you all my readers for your attention.</p>
<p>Did you like this article? You should follow me in Twitter <a href="http://twitter.com/kpumuk/">here</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=J1zVam3qShc:NlhBYpPaDDg:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=J1zVam3qShc:NlhBYpPaDDg:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=J1zVam3qShc:NlhBYpPaDDg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=J1zVam3qShc:NlhBYpPaDDg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=J1zVam3qShc:NlhBYpPaDDg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=J1zVam3qShc:NlhBYpPaDDg:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=J1zVam3qShc:NlhBYpPaDDg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=J1zVam3qShc:NlhBYpPaDDg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=J1zVam3qShc:NlhBYpPaDDg:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/kpumuk-ru/~4/J1zVam3qShc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		<feedburner:origLink>http://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/</feedburner:origLink></item>
		<item>
		<title>Weekly Link Dump #2</title>
		<link>http://feedproxy.google.com/~r/kpumuk-ru/~3/hTLZFL_r6eQ/</link>
		<comments>http://kpumuk.info/links/weekly-link-dump-2/#comments</comments>
		<pubDate>Tue, 22 Sep 2009 13:51:04 +0000</pubDate>
		<dc:creator>Dmytro Shteflyuk</dc:creator>
				<category><![CDATA[Links]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[cvs]]></category>
		<category><![CDATA[font]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[gource]]></category>
		<category><![CDATA[linkdump]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[struct]]></category>
		<category><![CDATA[visualization]]></category>

		<guid isPermaLink="false">http://kpumuk.info/?p=1035</guid>
		<description><![CDATA[Time to post some interesting stuff I&#8217;ve found in Internet last week. Today we going to talk about CSS font stacks, Ruby structs, extract_options! method came from Active Support, bash scripting, software version control visualization. When I started posting links, I decided not to mention articles posted by Smashing Magazine, thoughtbot and other sites which [...]]]></description>
			<content:encoded><![CDATA[<p>Time to post some interesting stuff I&#8217;ve found in Internet last week. Today we going to talk about CSS font stacks, Ruby structs, <code class="codecolorer ruby default"><span class="ruby">extract_options!</span></code> method came from Active Support, bash scripting, software version control visualization.</p>
<p class="more"><span id="more-1035"></span></p>
<div class="link-entry">
  <h2><a href="http://www.smashingmagazine.com/2009/09/22/complete-guide-to-css-font-stacks/" target="_blank" title="Open &quot;Guide to CSS Font Stacks: Techniques and Resources&quot; in a new window">Guide to CSS Font Stacks: Techniques and Resources</a></h2>
  <p class="link-info">
    <a class="thumbnail" href="http://www.smashingmagazine.com/2009/09/22/complete-guide-to-css-font-stacks/" target="_blank" title="Open &quot;Guide to CSS Font Stacks: Techniques and Resources&quot; in a new window" style="float:right;margin-left:10px;">
      <img src="/wp-content/uploads/2009/09/CSSFontStacks.png" alt="Guide to CSS Font Stacks: Techniques and Resources" width="256" height="256" />
    </a> by Cameron Chapman
  </p>
  <blockquote><div>CSS Font stacks are one of those things that elude a lot of designers. Many stick to the basic stacks Dreamweaver auto-recommends or go even more basic by just specifying a single web-safe font.</p>
<p>But doing either of those things means you’re missing out on some great typography options. Font stacks can make it possible to show at least some of your visitors your site’s typography exactly the way you intend without showing everyone else a default font. Read on for more information on using and creating effective font stacks with CSS.</div></blockquote>
</div>

<p>When I started posting links, I decided not to mention articles posted by Smashing Magazine, thoughtbot and other sites which everyone reads. But this is totally awesome: a complete guide on font faces, list of font tools and articles about typography. I promise, I will not publish links from Smashing Magazine ever again.</p>
<div class="link-entry">
  <h2><a href="http://blog.rubybestpractices.com/posts/rklemme/017-Struct.html" target="_blank" title="Open &quot;Structs inside out&quot; in a new window">Structs inside out</a></h2>
  <p class="link-info">
    <a class="thumbnail" href="http://blog.rubybestpractices.com/posts/rklemme/017-Struct.html" target="_blank" title="Open &quot;Structs inside out&quot; in a new window" style="float:right;margin-left:10px;">
      <img src="/wp-content/uploads/2009/09/StructsInsideOut.png" alt="Structs inside out" width="256" height="256" />
    </a> by Robert Klemme
  </p>
  <blockquote><div>Today we’re back to normal blog mode, where each article stands for itself. Muppet Labs are closed and we will be continuing our journey across the Ruby universe starting with an indepth look at Ruby’s <code class="codecolorer ruby default"><span class="ruby"><span style="color:#CC00FF; font-weight:bold;">Struct</span></span></code> class — Ruby’s Swiss army knife for structured data.</p>
<p><code class="codecolorer ruby default"><span class="ruby"><span style="color:#CC00FF; font-weight:bold;">Struct</span></span></code> can be used without any additional <code class="codecolorer ruby default"><span class="ruby"><span style="color:#CC0066; font-weight:bold;">require</span></span></code> statement — it’s just there. This means it comes with zero additional overhead during initial interpreter startup — one of the many advantage of using <code class="codecolorer ruby default"><span class="ruby"><span style="color:#CC00FF; font-weight:bold;">Struct</span></span></code>. But first let’s look at the basics.</div></blockquote>
</div>

<p>Great Ruby <code class="codecolorer ruby default"><span class="ruby"><span style="color:#CC00FF; font-weight:bold;">Struct</span></span></code> class usage examples.</p>
<div class="link-entry">
  <h2><a href="http://www.simonecarletti.com/blog/2009/09/inside-ruby-on-rails-extract_options-from-arrays/" target="_blank" title="Open &quot;Inside Ruby on Rails: extract_options! from Arrays&quot; in a new window">Inside Ruby on Rails: extract_options! from Arrays</a></h2>
  <p class="link-info">
    <a class="thumbnail" href="http://www.simonecarletti.com/blog/2009/09/inside-ruby-on-rails-extract_options-from-arrays/" target="_blank" title="Open &quot;Inside Ruby on Rails: extract_options! from Arrays&quot; in a new window" style="float:right;margin-left:10px;">
      <img src="/wp-content/uploads/2009/09/ExtractOptionsFromArrays.png" alt="Inside Ruby on Rails: extract_options! from Arrays" width="256" height="256" />
    </a> by Simone Carletti
  </p>
  <blockquote><div>How many times did you see a method call like the following one in your Rails application: <code class="codecolorer ruby default"><span class="ruby">my_method <span style="color:#ff3333; font-weight:bold;">:arg1</span>, <span style="color:#ff3333; font-weight:bold;">:foo</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span></span></code>?</p>
<p>What makes my_method quite special is the ability to pass an arbitrary number of parameters (:arg1, :arg2…) followed by a list of keyword/value options.</p>
<p>This is made possible by a really helpful method provided by ActiveSupport called <code class="codecolorer ruby default"><span class="ruby">extract_options!</span></code>. What this core extension does is to extract the options from the given set of arguments. When no options are available, the method returns a blank Hash.</div></blockquote>
</div>

<p>Nice Ruby on Rails method I didn&#8217;t know.</p>
<div class="link-entry">
  <h2><a href="http://tldp.org/LDP/abs/html/" target="_blank" title="Open &quot;Advanced Bash-Scripting Guide&quot; in a new window">Advanced Bash-Scripting Guide</a></h2>
  <p class="link-info">
    <a class="thumbnail" href="http://tldp.org/LDP/abs/html/" target="_blank" title="Open &quot;Advanced Bash-Scripting Guide&quot; in a new window" style="float:right;margin-left:10px;">
      <img src="/wp-content/uploads/2009/09/AdvancedBashScriptingGuide.png" alt="Advanced Bash-Scripting Guide" width="256" height="256" />
    </a> by Mendel Cooper
  </p>
  <blockquote><div>The shell is a command interpreter. More than just the insulating layer between the operating system kernel and the user, it&#8217;s also a fairly powerful programming language. A shell program, called a script, is an easy-to-use tool for building applications by &#8220;gluing together&#8221; system calls, tools, utilities, and compiled binaries. Virtually the entire repertoire of UNIX commands, utilities, and tools is available for invocation by a shell script. If that were not enough, internal shell commands, such as testing and loop constructs, lend additional power and flexibility to scripts. Shell scripts are especially well suited for administrative system tasks and other routine repetitive tasks not requiring the bells and whistles of a full-blown tightly structured programming language.</div></blockquote>
</div>

<p>Old good guide for the bash scripting. Must read for any developer.</p>
<div class="link-entry">
  <h2><a href="http://code.google.com/p/gource/" target="_blank" title="Open &quot;gource — software version control visualization&quot; in a new window">gource — software version control visualization</a></h2>
  <p class="link-info">
    <a class="thumbnail" href="http://code.google.com/p/gource/" target="_blank" title="Open &quot;gource — software version control visualization&quot; in a new window" style="float:right;margin-left:10px;">
      <img src="/wp-content/uploads/2009/09/Gource.png" alt="gource — software version control visualization" width="256" height="256" />
    </a> by Andrew Caudwell
  </p>
  <blockquote><div>Gource is a software version control visualization tool for Git and CVS.</p>
<p>Software projects are displayed by Gource as an animated tree with the root directory of the project at its centre. Directories appear as branches with files as leaves. Developers can be seen working on the tree at the times they contributed to the project.</div></blockquote>
</div>

<p>This freaking awesome tool produces animated visualization of source code history based on Git or CVS reporsitory. Also take a look at the <a href="http://vis.cs.ucdavis.edu/~ogawa/codeswarm/" target="_blank">code_swarm</a> project, which does very similar things.</p>
<p>PS. Did you notice a new threaded comments structure in this blog? Also I have rewritten theme layout a little, so there is HTML5 here now.</p>
<p>ЗЗЫ. Журналисты WebStream.com.ua взяли у меня интервью. Читаем <a href="http://webstream.com.ua/2009/09/interview-dmytro-shteflyuk-scribd-ruby-on-rails-developer.html">здесь</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=hTLZFL_r6eQ:eCaQCoWXyyk:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=hTLZFL_r6eQ:eCaQCoWXyyk:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=hTLZFL_r6eQ:eCaQCoWXyyk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=hTLZFL_r6eQ:eCaQCoWXyyk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=hTLZFL_r6eQ:eCaQCoWXyyk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=hTLZFL_r6eQ:eCaQCoWXyyk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=hTLZFL_r6eQ:eCaQCoWXyyk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=hTLZFL_r6eQ:eCaQCoWXyyk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=hTLZFL_r6eQ:eCaQCoWXyyk:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/kpumuk-ru/~4/hTLZFL_r6eQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kpumuk.info/links/weekly-link-dump-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://kpumuk.info/links/weekly-link-dump-2/</feedburner:origLink></item>
		<item>
		<title>Weekly Link Dump #1</title>
		<link>http://feedproxy.google.com/~r/kpumuk-ru/~3/ua2p8bcTAfU/</link>
		<comments>http://kpumuk.info/links/weekly-link-dump-1/#comments</comments>
		<pubDate>Mon, 14 Sep 2009 09:48:01 +0000</pubDate>
		<dc:creator>Dmytro Shteflyuk</dc:creator>
				<category><![CDATA[Links]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[linkdump]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[subversion]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://kpumuk.info/?p=971</guid>
		<description><![CDATA[This is a first link dump in this blog, where I will list all interesting links that I have found in Internet. I plan to post link dumps once a week, so stay tuned to read most useful stuff with no effort. Todays topics are: organizing your CSS, top mistakes made by WordPress plugins authors, [...]]]></description>
			<content:encoded><![CDATA[<p>This is a first link dump in this blog, where I will list all interesting links that I have found in Internet. I plan to post link dumps once a week, so stay tuned to read most useful stuff with no effort. Todays topics are: organizing your CSS, top mistakes made by WordPress plugins authors, ways MySQL uses indexes, and the git version control advantages over the Subversion.</p>
<p class="more"><span id="more-971"></span></p>
<div class="link-entry">
  <h2><a href="http://mirificampress.com/permalink/beautiful_css_organizing_your_stylesheets" target="_blank" title="Open &quot;Beautiful CSS: Organizing Your Stylesheets&quot; in a new window">Beautiful CSS: Organizing Your Stylesheets</a></h2>
  <p class="link-info">
    <a class="thumbnail" href="http://mirificampress.com/permalink/beautiful_css_organizing_your_stylesheets" target="_blank" title="Open &quot;Beautiful CSS: Organizing Your Stylesheets&quot; in a new window" style="float:right;margin-left:10px;">
      <img src="/wp-content/uploads/2009/09/BeautifulCSS.png" alt="Beautiful CSS: Organizing Your Stylesheets" width="256" height="256" />
    </a> by Matthew Griffin
  </p>
  <blockquote><div>When I first took the plunge into CSS several years ago, one of my biggest frustrations was stylesheet organization. I scoured source code from popular sites trying to figure how they accomplished various layout effects. But tracking back and forth from stylesheets to HTML proved to be a difficult task. Unfortunately , that separation of style and content that makes CSS so awesome can also make it difficult to understand. Adding to that difficulty is the fact that each designer may have a different way of organizing stylesheets. If you inherit someone else&#8217;s site, this can cause some problems. In a perfect world everyone&#8217;s CSS would be well-organized, easy to scale, and easy to understand. We may not be able to attain such CSS Nirvana but we can at least make it easier on ourselves and those we work with by following this set of guidelines.<br />
</div></blockquote>
</div>

<p>A nice article about organization of your CSS code. Author recommends to split your CSS code to several sections (universal styles, library styles, template layouts, individual page styles.) Also he proposes to indent styles related to nested HTML elements.</p>
<div class="link-entry">
  <h2><a href="http://planetozh.com/blog/2009/09/top-10-most-common-coding-mistakes-in-wordpress-plugins/" target="_blank" title="Open &quot;Top 10 Most Common Coding Mistakes in WordPress Plugins&quot; in a new window">Top 10 Most Common Coding Mistakes in WordPress Plugins</a></h2>
  <p class="link-info">
    <a class="thumbnail" href="http://planetozh.com/blog/2009/09/top-10-most-common-coding-mistakes-in-wordpress-plugins/" target="_blank" title="Open &quot;Top 10 Most Common Coding Mistakes in WordPress Plugins&quot; in a new window" style="float:right;margin-left:10px;">
      <img src="/wp-content/uploads/2009/09/WordPressCodingMistakes.png" alt="Top 10 Most Common Coding Mistakes in WordPress Plugins" width="256" height="256" />
    </a> by Ozh
  </p>
  <blockquote><div>As promised, I&#8217;m going to share a list of the most common mistakes, errors, misunderstandings, bad habits or wrong design decisions I&#8217;ve encountered while reviewing all these 43 plugins. Some are highly critical stuff (I&#8217;ve contacted 3 plugins authors after finding serious security holes in their plugin), some are more potential annoyances than real bugs, or are just causing a waste of server resources that could be avoided, but all have something in common: they&#8217;re trivial to fix. I&#8217;ve classified them in two parts: 10 bad code signs, plus a bonus with design decisions that suck. If you consider yourself a semi experienced coder or better, be sure to skip this article, you&#8217;re not going to learn a thing.</div></blockquote>
</div>

<p>A comprehensive list of common pitfalls of WordPress plugins authors. If you maintain a plugin, please read this article carefully, most of mistakes are quite common (yes, I found several issues with <a href="/projects/wordpress-plugins/">my ones</a></p>
<div class="link-entry">
  <h2><a href="http://www.mysqlperformanceblog.com/2009/09/12/3-ways-mysql-uses-indexes/" target="_blank" title="Open &quot;3 ways MySQL uses indexes&quot; in a new window">3 ways MySQL uses indexes</a></h2>
  <p class="link-info">
    <a class="thumbnail" href="http://www.mysqlperformanceblog.com/2009/09/12/3-ways-mysql-uses-indexes/" target="_blank" title="Open &quot;3 ways MySQL uses indexes&quot; in a new window" style="float:right;margin-left:10px;">
      <img src="/wp-content/uploads/2009/09/MySQLIndexes.png" alt="3 ways MySQL uses indexes" width="256" height="256" />
    </a> by Peter Zaitsev
  </p>
  <blockquote><div>I often see people confuse different ways MySQL can use indexing, getting wrong ideas on what query performance they should expect. There are 3 main ways how MySQL can use the indexes for query execution, which are not mutually exclusive, in fact some queries will use indexes for all 3 purposes listed here.</div></blockquote>
</div>

<p>You should read it. Period! Article covers all ways how MySQL uses indexes: filtering rows, sorting data, and reading data.</p>
<div class="link-entry">
  <h2><a href="http://carsonified.com/blog/web-apps/why-you-should-switch-from-subversion-to-git/" target="_blank" title="Open &quot;Why You Should Switch from Subversion to Git&quot; in a new window">Why You Should Switch from Subversion to Git</a></h2>
  <p class="link-info">
    <a class="thumbnail" href="http://carsonified.com/blog/web-apps/why-you-should-switch-from-subversion-to-git/" target="_blank" title="Open &quot;Why You Should Switch from Subversion to Git&quot; in a new window" style="float:right;margin-left:10px;">
      <img src="/wp-content/uploads/2009/09/SwitchToGit.png" alt="Why You Should Switch from Subversion to Git" width="256" height="256" />
    </a> by Scott Chacon
  </p>
  <blockquote><div>You may have heard some hubbub over distributed version control systems recently. You may dismiss it as the next hot thing, the newest flavor of kool-aid currently quenching the collective thirst of the bandwagon jumpers. You, however, have been using Subversion quite happily for some time now. It has treated you pretty well, you know it just fine and you are comfortable with it – I mean, it’s just version control, right?</div></blockquote>
</div>

<p>Yet another article about git and what features make it so wonderful tool for any developer. Author covers main features of this version control system, and explains how it could improve your work and boost your productivity. Hey Subversion (SourceSafe, CVS, etc) users, I do not accept any excuses, you definitely should read it. Yes, right now!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=ua2p8bcTAfU:mI8W5CBhBK8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=ua2p8bcTAfU:mI8W5CBhBK8:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=ua2p8bcTAfU:mI8W5CBhBK8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=ua2p8bcTAfU:mI8W5CBhBK8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=ua2p8bcTAfU:mI8W5CBhBK8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=ua2p8bcTAfU:mI8W5CBhBK8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=ua2p8bcTAfU:mI8W5CBhBK8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=ua2p8bcTAfU:mI8W5CBhBK8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=ua2p8bcTAfU:mI8W5CBhBK8:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/kpumuk-ru/~4/ua2p8bcTAfU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kpumuk.info/links/weekly-link-dump-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://kpumuk.info/links/weekly-link-dump-1/</feedburner:origLink></item>
		<item>
		<title>In reply to latest articles in Thoughtbot blog</title>
		<link>http://feedproxy.google.com/~r/kpumuk-ru/~3/gIsVweYV3VA/</link>
		<comments>http://kpumuk.info/links/in-reply-to-latest-articles-in-thoughtbot-blog/#comments</comments>
		<pubDate>Thu, 10 Sep 2009 10:33:51 +0000</pubDate>
		<dc:creator>Dmytro Shteflyuk</dc:creator>
				<category><![CDATA[Links]]></category>
		<category><![CDATA[friends]]></category>
		<category><![CDATA[humor]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[stupid]]></category>
		<category><![CDATA[thoughtbot]]></category>

		<guid isPermaLink="false">http://kpumuk.info/?p=960</guid>
		<description><![CDATA[Last few weeks Thoughtbot publish lots of really stupid (gsub syntax manual; are you serious?) articles (WTF is Best practice: index every boolean column) in their blog. And yesterdays article about tailing your Rails log is the absolute leader, it&#8217;s freaking awesome. Hey guys, I&#8217;m waiting for other articles in this series: &#8220;@ in attribute [...]]]></description>
			<content:encoded><![CDATA[<p>Last few weeks Thoughtbot publish lots of really <a href="http://robots.thoughtbot.com/post/183070874/gsub-with-a-block">stupid</a> (<code class="codecolorer ruby default"><span class="ruby"><span style="color:#CC0066; font-weight:bold;">gsub</span></span></code> syntax manual; are you serious?) <a href="http://robots.thoughtbot.com/post/163627511/a-grand-piano-for-your-violin">articles</a> (WTF is <em>Best practice: index every boolean column</em>) in <a href="http://robots.thoughtbot.com/">their blog</a>. And yesterdays article about <a href="http://robots.thoughtbot.com/post/184016186/catch-a-tiger-by-the-tail">tailing your Rails log</a> is the absolute leader, it&#8217;s freaking awesome. Hey guys, I&#8217;m waiting for other articles in this series: &#8220;@ in attribute names, what does it mean?&#8221;, &#8220;<code class="codecolorer ruby default"><span class="ruby"><span style="color:#9966CC; font-weight:bold;">if</span></span></code>-<code class="codecolorer ruby default"><span class="ruby"><span style="color:#9966CC; font-weight:bold;">then</span></span></code>-<code class="codecolorer ruby default"><span class="ruby"><span style="color:#9966CC; font-weight:bold;">else</span></span></code> statement usage best practices for Ruby on Rails senior developers&#8221;, &#8220;how to install a gem&#8221;.</p>
<p>Hey robots, we have a reply to your outstanding articles: <a href="http://blog.startika.com/2009/09/10/a-wonderful-way-to-list-your-project-files/">A wonderful way to list your project files</a>. Please read it carefully, you definitely will find something useful for you! Thanks to <a href="http://twitter.com/labria">@labria</a> for his great exploration.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=gIsVweYV3VA:mnTwEnxUtxI:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=gIsVweYV3VA:mnTwEnxUtxI:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=gIsVweYV3VA:mnTwEnxUtxI:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=gIsVweYV3VA:mnTwEnxUtxI:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=gIsVweYV3VA:mnTwEnxUtxI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=gIsVweYV3VA:mnTwEnxUtxI:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=gIsVweYV3VA:mnTwEnxUtxI:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=gIsVweYV3VA:mnTwEnxUtxI:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=gIsVweYV3VA:mnTwEnxUtxI:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/kpumuk-ru/~4/gIsVweYV3VA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kpumuk.info/links/in-reply-to-latest-articles-in-thoughtbot-blog/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://kpumuk.info/links/in-reply-to-latest-articles-in-thoughtbot-blog/</feedburner:origLink></item>
		<item>
		<title>Simplifying your Ruby on Rails code: Presenter pattern, cells plugin</title>
		<link>http://feedproxy.google.com/~r/kpumuk-ru/~3/cQi-1uJhFqg/</link>
		<comments>http://kpumuk.info/ruby-on-rails/simplifying-your-ruby-on-rails-code/#comments</comments>
		<pubDate>Wed, 09 Sep 2009 05:41:14 +0000</pubDate>
		<dc:creator>Dmytro Shteflyuk</dc:creator>
				<category><![CDATA[Ruby & Rails]]></category>
		<category><![CDATA[cells]]></category>
		<category><![CDATA[Development]]></category>
		<category><![CDATA[patterns]]></category>
		<category><![CDATA[presenter]]></category>
		<category><![CDATA[refactoring]]></category>
		<category><![CDATA[RSpec]]></category>

		<guid isPermaLink="false">http://kpumuk.info/?p=937</guid>
		<description><![CDATA[Today we will talk about code organization in Ruby on Rails projects. As everybody knows, Ruby on Rails is a conventional framework, which means you should follow framework architects&#8217; decisions (put your controllers inside app/controllers, move all your logic into models, etc.) But there are many open questions around those conventions. In this write-up I [...]]]></description>
			<content:encoded><![CDATA[<p>Today we will talk about code organization in Ruby on Rails projects. As everybody knows, Ruby on Rails is a conventional framework, which means you should follow framework architects&#8217; decisions (put your controllers inside <code class="codecolorer text default"><span class="text">app/controllers</span></code>, move all your logic into models, etc.) But there are many open questions around those conventions. In this write-up I will try to summarize my personal experience and show how I usually solve these problems.</p>
<p class="more"><span id="more-937"></span></p>
<p>Here is the list of questions we will talk about:</p>
<ol>
<li>
<p>You have some logic in your view, which uses your models extensively. There are no places in other views with such logic. The classic recommendation is to move this code into a model, but after a short time your models become bloated with stupid one-off helper methods. The solution: <a href="#presenter">pattern Presenter</a>.</p>
</li>
<li>
<p>Your constructor contains a lot of code to retrieve some values for your views from the database or another storage. You have a lot of <code class="codecolorer ruby default"><span class="ruby">fragment_exist?</span></code> calls to ensure no of your data is loaded when corresponding fragment is already in cache. It&#8217;s really hard to test a particular action because of it&#8217;s size. The solution: <a href="#presenter">pattern Presenter</a>.</p>
</li>
<li>
<p>You have a partial, used everywhere on the site. It accepts a lot of parameters to configure how rendered code should look like. The header of this partial, which initializes default values of parameters, becomes larger and larger. The solution: <a href="#cells">cells plugin</a>.</p>
</li>
</ol>
<p><em>Please note: sample application is available on <a href="http://github.com/kpumuk/presenter-example/">GitHub</a>.</em></p>
<h3><a name="presenter"></a>Presenter Pattern</h3>
<p>Okay, you have an idea when to use this patterns. Let&#8217;s look at the example:</p>
<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br /></div></td><td><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">class</span> HomeController <span style="color:#006600; font-weight:bold;">&lt;</span> ApplicationController<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#5A0A0A; font-weight:bold;">show</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">unless</span> fragment_exist?<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'home/top_videos'</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@top_videos</span> = Video.<span style="color:#9900CC;">top</span>.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:limit</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">10</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">unless</span> fragment_exist?<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'home/categories'</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@categories</span> = Category.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:order</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'name DESC'</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">unless</span> fragment_exist?<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'home/featured_videos'</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@featured_videos</span> = Video.<span style="color:#9900CC;">featured</span>.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:limit</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">5</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">unless</span> fragment_exist?<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'home/latest_videos'</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@latest_videos</span> = Video.<span style="color:#9900CC;">latest</span>.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:limit</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">5</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>And the view:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h1</span>&gt;</span>Home page<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h1</span>&gt;</span><br />
<br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;top_videos&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h2</span>&gt;</span>Top videos<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;% cache<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'home/top_videos'</span><span style="color: #66cc66;">&#41;</span> do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render <span style="color: #ff0000;">'videos'</span>, :videos <span style="color: #66cc66;">=</span>&gt;</span> @top_videos, :hide_description =&gt; true %&gt;<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tabs&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ul</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;taxonomy&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#&quot;</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;categories&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;current&quot;</span>&gt;</span>Categories<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">ul</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;categories_panel&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h2</span>&gt;</span>Categories<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% cache<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'home/categories'</span><span style="color: #66cc66;">&#41;</span> do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render <span style="color: #ff0000;">'categories'</span> %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;box&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;latest&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h2</span>&gt;</span>Latest videos<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% cache<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'home/latest_videos'</span><span style="color: #66cc66;">&#41;</span> do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render <span style="color: #ff0000;">'videos'</span>, :videos <span style="color: #66cc66;">=</span>&gt;</span> @latest_videos, :hide_thumbnail =&gt; true %&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;featured&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h2</span>&gt;</span>Featured videos<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% cache<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'home/featured_videos'</span><span style="color: #66cc66;">&#41;</span> do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render <span style="color: #ff0000;">'videos'</span>, :videos <span style="color: #66cc66;">=</span>&gt;</span> @featured_videos, :hide_thumbnail =&gt; true %&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span></div></td></tr></tbody></table></div>
<p><em>Note: this code is available in the <a href="http://github.com/kpumuk/presenter-example/tree/0a7ee4dae94cd45415456943bc9c56a4dab2cdae">first commit</a> of my <a href="http://github.com/kpumuk/presenter-example/">presenter example</a> project.</em></p>
<p>Scary code, isn&#8217;t it? So let&#8217;s refactor it using Presenter pattern. I prefer to put presenters into a separate folder <code class="codecolorer text default"><span class="text">app/presenters</span></code>, so first we should add it to Rails load path. Add this line to your <code class="codecolorer text default"><span class="text">config/environment.rb</span></code>:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">config.<span style="color:#9900CC;">load_paths</span> <span style="color:#006600; font-weight:bold;">+</span>= <span style="color:#006600; font-weight:bold;">%</span>W<span style="color:#006600; font-weight:bold;">&#40;</span><br />
&nbsp; <span style="color:#008000; font-style:italic;">#{Rails.root}/app/presenters </span><br />
<span style="color:#006600; font-weight:bold;">&#41;</span></div></td></tr></tbody></table></div>
<p>Now we are ready to write our presenter (<code class="codecolorer text default"><span class="text">app/presenters/home_presenters/show_presenter.rb</span></code>):</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">module</span> HomePresenters<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">class</span> ShowPresenter<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> top_videos<br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@top_videos</span> <span style="color:#006600; font-weight:bold;">||</span>= Video.<span style="color:#9900CC;">top</span>.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:limit</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">10</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> categories<br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@categories</span> <span style="color:#006600; font-weight:bold;">||</span>= Category.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:order</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'name DESC'</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> featured_videos<br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@featured_videos</span> <span style="color:#006600; font-weight:bold;">||</span>= Video.<span style="color:#9900CC;">featured</span>.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:limit</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">5</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> latest_videos<br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@latest_videos</span> <span style="color:#006600; font-weight:bold;">||</span>= Video.<span style="color:#9900CC;">latest</span>.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:limit</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">5</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>Sometimes presenters depend on parameters, so feel free to add an <code class="codecolorer ruby default"><span class="ruby">initialize</span></code> method. It could accept particular params or whole params collection:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>video_id<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#0066ff; font-weight:bold;">@video_id</span> = video_id<br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>Now let&#8217;s refactor our controller:</p>
<div class="codecolorer-container rails twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="rails codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">class</span> HomeController <span style="color:#006600; font-weight:bold;">&lt;</span> ApplicationController<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#5A0A0A; font-weight:bold;">show</span><br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@presenter</span> = <span style="color:#6666ff; font-weight:bold;">HomePresenters::ShowPresenter</span>.<span style="color:#5A0A0A; font-weight:bold;">new</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>Whoa, that&#8217;s nice! View now is little different:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h1</span>&gt;</span>Home page<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h1</span>&gt;</span><br />
<br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;top_videos&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h2</span>&gt;</span>Top videos<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;% cache<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'home/top_videos'</span><span style="color: #66cc66;">&#41;</span> do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render <span style="color: #ff0000;">'videos'</span>, :videos <span style="color: #66cc66;">=</span>&gt;</span> @presenter.top_videos, :hide_description =&gt; true %&gt;<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tabs&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ul</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;taxonomy&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#&quot;</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;categories&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;current&quot;</span>&gt;</span>Categories<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">ul</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;categories_panel&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h2</span>&gt;</span>Categories<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% cache<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'home/categories'</span><span style="color: #66cc66;">&#41;</span> do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render <span style="color: #ff0000;">'categories'</span> %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;box&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;latest&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h2</span>&gt;</span>Latest videos<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% cache<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'home/latest_videos'</span><span style="color: #66cc66;">&#41;</span> do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render <span style="color: #ff0000;">'videos'</span>, :videos <span style="color: #66cc66;">=</span>&gt;</span> @presenter.latest_videos, :hide_thumbnail =&gt; true %&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;featured&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h2</span>&gt;</span>Featured videos<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% cache<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'home/featured_videos'</span><span style="color: #66cc66;">&#41;</span> do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render <span style="color: #ff0000;">'videos'</span>, :videos <span style="color: #66cc66;">=</span>&gt;</span> @presenter.featured_videos, :hide_thumbnail =&gt; true %&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span></div></td></tr></tbody></table></div>
<p>Presenters testing is much easier than testing of bloated controllers:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">describe <span style="color:#6666ff; font-weight:bold;">HomePresenters::ShowPresenter</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; before <span style="color:#ff3333; font-weight:bold;">:each</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@presenter</span> = <span style="color:#6666ff; font-weight:bold;">HomePresenters::ShowPresenter</span>.<span style="color:#9900CC;">new</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <br />
&nbsp; it <span style="color:#996600;">'should respond to :top_videos'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; expect <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#0066ff; font-weight:bold;">@presenter</span>.<span style="color:#9900CC;">top_videos</span> <span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">to_not</span> raise_error<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; it <span style="color:#996600;">'should respond to :categories'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; expect <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#0066ff; font-weight:bold;">@presenter</span>.<span style="color:#9900CC;">categories</span> <span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">to_not</span> raise_error<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; it <span style="color:#996600;">'should respond to :featured_videos'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; expect <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#0066ff; font-weight:bold;">@presenter</span>.<span style="color:#9900CC;">featured_videos</span> <span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">to_not</span> raise_error<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; it <span style="color:#996600;">'should respond to :latest_videos'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; expect <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#0066ff; font-weight:bold;">@presenter</span>.<span style="color:#9900CC;">latest_videos</span> <span style="color:#006600; font-weight:bold;">&#125;</span>.<span style="color:#9900CC;">to_not</span> raise_error<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p><em>Please note: this code is available in the <a href="http://github.com/kpumuk/presenter-example/tree/f45caacafdded44e0896ce5542ba4158145ca188">second commit</a> of my <a href="http://github.com/kpumuk/presenter-example/">presenter example</a> project.</em></p>
<p><em>Please note: <strong>you should not do any manipulations on models in presenters</strong>. They only decorate models with helper methods to be used inside controllers or views, nothing else. <a href="http://www.subelsky.com/2008/01/presenter-classes-help-with-rails.html">There are several articles</a> describing a Conductor pattern as a presenter, do not repeat their mistakes. See the first link in the list below to get an idea about the differences.</em></p>
<p>Related links:</p>
<ul>
<li><a href="http://blog.new-bamboo.co.uk/2007/8/31/presenters-conductors-on-rails">Presenters &amp; Conductors on Rails</a></li>
<li><a href="http://htmltimes.com/presenters-in-Ruby-on-Rails-applications.php">Presenters in Ruby on Rails Applications</a></li>
<li><a href="http://blog.jayfields.com/2006/09/rails-model-view-controller-presenter.html">Rails Model View Controller + Presenter?</a></li>
<li><a href="http://blog.jayfields.com/2007/09/railsconf-europe-07-presenter-links.html">RailsConf Europe 07: Presenter Links</a></li>
</ul>
<h3><a name="cells"></a>Cells Plugin</h3>
<p>Okay, now we have a clean controller. But what about views? Let&#8217;s take a look at the <code class="codecolorer text default"><span class="text">videos</span></code> partial:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;%</span><br />
<span style="color: #009900;"> &nbsp;hide_thumbnail &nbsp; <span style="color: #66cc66;">=</span> hide_thumbnail <span style="color: #66cc66;">===</span> true;</span><br />
<span style="color: #009900;"> &nbsp;hide_description <span style="color: #66cc66;">=</span> hide_description <span style="color: #66cc66;">===</span> true;</span><br />
<span style="color: #009900;"> &nbsp;css_class &nbsp; &nbsp; &nbsp;||<span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'videos'</span></span><br />
<span style="color: #009900;"> &nbsp;<span style="color: #000066;">style</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;||<span style="color: #66cc66;">=</span> :div</span><br />
<span style="color: #009900;"> &nbsp;case <span style="color: #000066;">style</span>.to_sym</span><br />
<span style="color: #009900;"> &nbsp; &nbsp;when :section</span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp;parent_tag <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'section'</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp;child_tag <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'div'</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;when :list</span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp;parent_tag <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'ul'</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp;child_tag <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'li'</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp;else</span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp;parent_tag <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'div'</span></span><br />
<span style="color: #009900;"> &nbsp; &nbsp; &nbsp;child_tag <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'div'</span></span><br />
<span style="color: #009900;"> &nbsp;end</span><br />
<span style="color: #009900;">%&gt;</span><br />
<br />
<span style="color: #009900;">&lt;% content_tag parent_tag, :<span style="color: #000066;">class</span> <span style="color: #66cc66;">=</span>&gt;</span> css_class do %&gt;<br />
&nbsp; <span style="color: #009900;">&lt;% videos.each do |video| %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;% content_tag child_tag do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h3</span>&gt;&lt;%<span style="color: #66cc66;">=</span> h video.<span style="color: #000066;">title</span> %&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h3</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> image_tag<span style="color: #66cc66;">&#40;</span>video.thumbnail_url, :<span style="color: #000066;">class</span> <span style="color: #66cc66;">=</span>&gt;</span> 'thumb') unless hide_thumbnail %&gt;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'&lt;p&gt;</span></span>%s<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">p</span>&gt;</span>' % h(video.description) unless hide_description %&gt;<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
<span style="color: #009900;">&lt;% end %&gt;</span></div></td></tr></tbody></table></div>
<p>So, what the heck? Is this a view or a controller? Remember old PHP days, with all this spaghetti code? That is it. It&#8217;s hard to test, it looks scary, it bad. So here <a href="http://github.com/apotonick/cells/">cells</a> plugin comes to the stage.</p>
<p>First, we need to install the plugin:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">script/plugin install git://github.com/apotonick/cells.git</div></td></tr></tbody></table></div>
<p>Now let&#8217;s generate a cell:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">script/generate cell Video videos</div></td></tr></tbody></table></div>
<p>And write some code (<code class="codecolorer text default"><span class="text">app/cells/video.rb</span></code>):</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">class</span> VideoCell <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">Cell::Base</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> videos<br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@videos</span> = <span style="color:#0066ff; font-weight:bold;">@opts</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:videos</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@hide_thumbnail</span> = <span style="color:#0066ff; font-weight:bold;">@opts</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:hide_thumbnail</span><span style="color:#006600; font-weight:bold;">&#93;</span> === <span style="color:#0000FF; font-weight:bold;">true</span>;<br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@hide_description</span> = <span style="color:#0066ff; font-weight:bold;">@opts</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:hide_description</span><span style="color:#006600; font-weight:bold;">&#93;</span> === <span style="color:#0000FF; font-weight:bold;">true</span>;<br />
&nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@css_class</span> = <span style="color:#0066ff; font-weight:bold;">@opts</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:css_class</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span> <span style="color:#996600;">'videos'</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; view = <span style="color:#006600; font-weight:bold;">&#40;</span>@opts<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:style</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span> <span style="color:#ff3333; font-weight:bold;">:div</span><span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#9900CC;">to_sym</span><br />
&nbsp; &nbsp; view = <span style="color:#ff3333; font-weight:bold;">:div</span> <span style="color:#9966CC; font-weight:bold;">unless</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:section</span>, <span style="color:#ff3333; font-weight:bold;">:list</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9966CC; font-weight:bold;">include</span>?<span style="color:#006600; font-weight:bold;">&#40;</span>view<span style="color:#006600; font-weight:bold;">&#41;</span><br />
<br />
&nbsp; &nbsp; render <span style="color:#ff3333; font-weight:bold;">:view</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;videos_#{view}&quot;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p><code class="codecolorer text default"><span class="text">app/cells/video/videos_section.html.erb</span></code>:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;section <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;&lt;%= @css_class %&gt;</span></span>&quot;&gt;<br />
&nbsp; <span style="color: #009900;">&lt;% @videos.each do |video| %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render :partial <span style="color: #66cc66;">=</span>&gt;</span> 'video', :locals =&gt; { :video =&gt; video } %&gt;<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span>section&gt;</span></div></td></tr></tbody></table></div>
<p><code class="codecolorer text default"><span class="text">app/cells/video/videos_list.html.erb</span></code>:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ul</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;&lt;%= @css_class %&gt;</span></span>&quot;&gt;<br />
&nbsp; <span style="color: #009900;">&lt;% @videos.each do |video| %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render :partial <span style="color: #66cc66;">=</span>&gt;</span> 'video', :locals =&gt; { :video =&gt; video } %&gt;<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">ul</span>&gt;</span></div></td></tr></tbody></table></div>
<p><code class="codecolorer text default"><span class="text">app/cells/video/videos_div.html.erb</span></code>:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;&lt;%= @css_class %&gt;</span></span>&quot;&gt;<br />
&nbsp; <span style="color: #009900;">&lt;% @videos.each do |video| %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render :partial <span style="color: #66cc66;">=</span>&gt;</span> 'video', :locals =&gt; { :video =&gt; video } %&gt;<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span></div></td></tr></tbody></table></div>
<p><code class="codecolorer text default"><span class="text">app/cells/video/_video.html.erb</span></code>:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h3</span>&gt;&lt;%<span style="color: #66cc66;">=</span> h video.<span style="color: #000066;">title</span> %&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h3</span>&gt;</span><br />
<span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> image_tag<span style="color: #66cc66;">&#40;</span>video.thumbnail_url, :<span style="color: #000066;">class</span> <span style="color: #66cc66;">=</span>&gt;</span> 'thumb') unless @hide_thumbnail %&gt;<br />
<span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'&lt;p&gt;</span></span>%s<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">p</span>&gt;</span>' % h(video.description) unless @hide_description %&gt;</div></td></tr></tbody></table></div>
<p>And the view:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h1</span>&gt;</span>Home page<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h1</span>&gt;</span><br />
<br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;top_videos&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h2</span>&gt;</span>Top videos<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;% cache<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'home/top_videos'</span><span style="color: #66cc66;">&#41;</span> do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render_cell :video, :videos, :videos <span style="color: #66cc66;">=</span>&gt;</span> @presenter.top_videos, :hide_description =&gt; true %&gt;<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tabs&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ul</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;taxonomy&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#&quot;</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;categories&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;current&quot;</span>&gt;</span>Categories<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">ul</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;categories_panel&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h2</span>&gt;</span>Categories<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% cache<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'home/categories'</span><span style="color: #66cc66;">&#41;</span> do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render <span style="color: #ff0000;">'categories'</span> %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<br />
<span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;box&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;latest&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h2</span>&gt;</span>Latest videos<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% cache<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'home/latest_videos'</span><span style="color: #66cc66;">&#41;</span> do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render_cell :video, :videos, :videos <span style="color: #66cc66;">=</span>&gt;</span> @presenter.latest_videos, :hide_thumbnail =&gt; true %&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;featured&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">h2</span>&gt;</span>Featured videos<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">h2</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% cache<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'home/featured_videos'</span><span style="color: #66cc66;">&#41;</span> do %&gt;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render_cell :video, :videos, :videos <span style="color: #66cc66;">=</span>&gt;</span> @presenter.featured_videos, :hide_thumbnail =&gt; true %&gt;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% end %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span></div></td></tr></tbody></table></div>
<p>Wow! That&#8217;s pretty easy to read and modify. All the logic is in the code now, all the views are easy to read, and moreover: it&#8217;s more than easy to test now! I have a little plugin called <a href="http://github.com/kpumuk/rspec-cells/">rspec-cells</a>, and I have committed a patch yesterday to get it working with the latest RSpec. Here is how you spec could look like:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">describe VideoCell <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; context <span style="color:#996600;">'.videos'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; it <span style="color:#996600;">'should initialize :videos variable'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; videos = mock<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'Videos'</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; render_cell <span style="color:#ff3333; font-weight:bold;">:videos</span>, <span style="color:#ff3333; font-weight:bold;">:videos</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> videos<br />
&nbsp; &nbsp; &nbsp; assigns<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:videos</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">should</span> be<span style="color:#006600; font-weight:bold;">&#40;</span>videos<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>So it looks almost like a classic Ruby on Rails controller spec. I hope to review the code in nearest feature and will send a pull request to the cells plugin author. Of course, if you<br />
found a bug, feel free to <a href="/contact">contact me</a>.</p>
<p><em>Please note: this code is available in the <a href="http://github.com/kpumuk/presenter-example/tree/7d9ebe8a092a57a0e914bc5a0223efa72e888785">third commit</a> of my <a href="http://github.com/kpumuk/presenter-example/">presenter example</a> project.</em></p>
<p>Related links:</p>
<ul>
<li><a href="http://cells.rubyforge.org/">Cells project home page</a></li>
<li><a href="http://github.com/apotonick/cells/">Cells project on GitHub</a></li>
<li><a href="http://github.com/kpumuk/rspec-cells/">rspec-cells project on GitHub</a></li>
</ul>
<p>That&#8217;s all I wanted to show you today. I think a <a href="http://github.com/kpumuk/presenter-example/">Presenter Example</a> project will be updated periodically, so follow it on GitHub, <a href="http://kpumuk.info/twitter">follow me in Twitter</a> or on <a href="http://github.com/kpumuk/">GitHub</a> to get instant updates. Also take a look at the <a href="http://github.com/kpumuk/rspec-cells/">rspec-cells</a> plugin, maybe you will have some time to make it better.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=cQi-1uJhFqg:0iVX5DNtXbI:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=cQi-1uJhFqg:0iVX5DNtXbI:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=cQi-1uJhFqg:0iVX5DNtXbI:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=cQi-1uJhFqg:0iVX5DNtXbI:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=cQi-1uJhFqg:0iVX5DNtXbI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=cQi-1uJhFqg:0iVX5DNtXbI:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=cQi-1uJhFqg:0iVX5DNtXbI:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=cQi-1uJhFqg:0iVX5DNtXbI:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=cQi-1uJhFqg:0iVX5DNtXbI:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/kpumuk-ru/~4/cQi-1uJhFqg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kpumuk.info/ruby-on-rails/simplifying-your-ruby-on-rails-code/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		<feedburner:origLink>http://kpumuk.info/ruby-on-rails/simplifying-your-ruby-on-rails-code/</feedburner:origLink></item>
		<item>
		<title>Scribd open source projects</title>
		<link>http://feedproxy.google.com/~r/kpumuk-ru/~3/SKCiCjE3EhE/</link>
		<comments>http://kpumuk.info/development/scribd-open-source-projects/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 02:06:05 +0000</pubDate>
		<dc:creator>Dmytro Shteflyuk</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Ruby & Rails]]></category>
		<category><![CDATA[cocoa]]></category>
		<category><![CDATA[email]]></category>
		<category><![CDATA[merb]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[opensource]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[profile]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[scribd]]></category>
		<category><![CDATA[sessions]]></category>
		<category><![CDATA[sphinx]]></category>

		<guid isPermaLink="false">http://kpumuk.info/?p=918</guid>
		<description><![CDATA[It&#8217;s time to summarize what we have done for the Open Source community. Scribd is pretty open company, we release a lot of code into the public after a time (sometimes it is short, sometimes it is not). Here I want to mention all the code we have opensourced. Please take into account that time [...]]]></description>
			<content:encoded><![CDATA[<p>It&#8217;s time to summarize what we have done for the Open Source community. Scribd is pretty open company, we release a lot of code into the public after a time (sometimes it is short, sometimes it is not). Here I want to mention all the code we have opensourced. Please take into account that time is moving on, so we are publishing more and more code. I will update this post periodically, so stay tuned. <a href="http://twitter.com/kpumuk/">Follow me</a> on Twitter to get instant updates.</p>
<p class="more"><span id="more-918"></span></p>
<h3>Table of Contents</h3>
<p>Here is the list of our projects in alphabetical order:</p>
<ul>
<li><a href="#bounces-handler">bounces-handler</a> &#8212; Email Bounces Processing System with Rails plugin to prevent Rails mailers from sending any messages to a blocked addresses.</li>
<li><a href="#db-charmer">db-charmer</a> &#8212; ActiveRecord Connections Magic (slaves, multiple connections, etc).</li>
<li><a href="#easy-prof">easy-prof</a> &#8212; Simple and easy to use Ruby code profiler, which could be used as a Rails plugin.</li>
<li><a href="#rails-fast-sessions">Fast Sessions</a> &#8212; Sessions class for ActiveRecord sessions store created to work fast (really fast).</li>
<li><a href="#loops">loops</a> &#8212; Simple background loops framework for Ruby on Rails and Merb.</li>
<li><a href="#magic-enum">magic-enum</a> &#8212; Method used to define ENUM-like attributes in your model (int fields actually).</li>
<li><a href="#rlibsphinxclient">rlibsphinxclient</a> &#8212; A Ruby wrapper for pure C searchd client API library.</li>
<li><a href="#rscribd">rscribd</a> &#8212; Ruby client library for the Scribd API.</li>
<li><a href="#rspec-cells">Rspec Cells</a> &#8212; A library for testing applications that are using Cells in RSpec.</li>
<li><a href="#scribd-uploader">Scribd Desktop Uploader</a> &#8212; A fully native Cocoa Macintosh uploader app for the Scribd.com website.</li>
</ul>
<h3><a name="bounces-handler" href="http://github.com/kovyrin/bounces-handler/">bounces-handler</a></h3>
<p>Bounces-handler package is a simple set of scripts to automatically process email bounces and ISP’s feedback loops emails, maintain your mailing blacklists and a Ruby on Rails plugin to use those blacklists in your RoR applications.</p>
<p>This piece of software has been developed as a part of more global work on mailing quality improvement in Scribd.com, but it was one of the most critical steps after setting up reverse DNS records, DKIM and SPF.</p>
<p>Links: <a href="http://github.com/kovyrin/bounces-handler/">Project Home Page on GitHub</a> | <a href="http://kovyrin.net/2008/08/03/bounce-handler-released/">Introduction Blog Post</a> | <a href="http://rdoc.info/projects/kovyrin/bounces-handler">RDoc Documentation</a>.</p>
<h3><a name="db-charmer" href="http://github.com/kovyrin/db-charmer/">db-charmer</a></h3>
<p>DbCharmer is a simple yet powerful plugin for ActiveRecord that does a few things:</p>
<ul>
<li>Allows you to easily manage AR models’ connections (switch_connection_to method)</li>
<li>Allows you to switch AR models’ default connections to a separate servers/databases</li>
<li>Allows you to easily choose where your query should go (Model.on_db methods)</li>
<li>Allows you to automatically send read queries to your slaves while masters would handle all the updates.</li>
<li>Adds multiple databases migrations to ActiveRecord</li>
</ul>
<p>It requires Ruby on Rails version 2.3 or later. The main purpose of this plugin is to put all the databases-related code we have been using in Scribd for a while into a single easy-to use package.</p>
<p>Links: <a href="http://github.com/kovyrin/db-charmer/">Project Home Page on GitHub</a> | <a href="http://github.com/kovyrin/db-charmer-sandbox/">Test Rails Application on GitHub</a> | <a href="http://rdoc.info/projects/kovyrin/db-charmer">RDoc Documentation</a>.</p>
<h3><a name="easy-prof" href="http://github.com/kpumuk/easy-prof/">easy-prof</a></h3>
<p>Simple and easy to use Ruby code profiler, which could be used as a Rails plugin. The main idea behind the easy-prof is creating check points and your code and measuring time needed to execute code blocks. Here is the example of easy-prof output:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[home#index] Benchmark results:<br />
[home#index] debug: Logged in user home page<br />
[home#index] progress: 0.7002 s [find top videos]<br />
[home#index] progress: 0.0452 s [build categories list]<br />
[home#index] progress: 0.0019 s [build tag cloud]<br />
[home#index] progress: 0.0032 s [find featured videos]<br />
[home#index] progress: 0.0324 s [find latest videos]<br />
[home#index] debug: VIEW STARTED<br />
[home#index] progress: 0.0649 s [top videos render]<br />
[home#index] progress: 0.0014 s [categories render]<br />
[home#index] progress: 2.5887 s [tag cloud render]<br />
[home#index] progress: 0.0488 s [latest videos render]<br />
[home#index] progress: 0.1053 s [featured video render]<br />
[home#index] results: 3.592 s</div></td></tr></tbody></table></div>
<p>From this output you can see what checkpoints takes longer to reach, and what code fragments are pretty fast.</p>
<p>Links: <a href="http://github.com/kpumuk/easy-prof/">Project Home Page on GitHub</a> | <a href="http://kpumuk.info/ror-plugins/creating-a-simple-but-powerful-profiler-for-ruby-on-rails/">Introduction Blog Post</a> | <a href="http://rdoc.info/projects/kpumuk/easy-prof">RDoc Documentation</a>.</p>
<h3><a name="rails-fast-sessions" href="http://code.google.com/p/rails-fast-sessions/">Fast Sessions</a></h3>
<p>FastSessions is a sessions class for ActiveRecord sessions store created to work fast (really fast). It uses some techniques which are not so widely known in developers&#8217; community and only when they cause huge problems, performance consultants are trying to help with them.</p>
<p>FastSessions plugin was born as a hack created for Scribd.com (large RoR-based web project), which was suffering from InnoDB auto-increment table-level locks on sessions table.</p>
<p>So, first of all, we removed id field from the table. Next step was to make lookups faster and we&#8217;ve used a following technique: instead of using (<code class="codecolorer text default"><span class="text">session_id</span></code>) as a lookup key, we started using (<code class="codecolorer text default"><span class="text">CRC32(session_id), session_id)</span></code> — two-columns key which really helps MySQL to find sessions faster because key cardinality is higher (so, mysql is able to find a record earlier w/o checking a lots of index rows). We&#8217;ve benchmarked this approach and it shows 10–15% performance gain on large sessions tables.</p>
<p>And last, but most powerful change we&#8217;ve tried to make was to not create database records for empty sessions and to not save sessions data back to database if this data has not been changed during current request processing. With this change we basically reduce inserts number by 50-90% (depends 0n application).</p>
<p>All of these changes were implemented and you can use them automatically after a simple plugin installation.</p>
<p>There is a <a href="http://github.com/mudge/fast_sessions/">fork</a> patched by <a href="http://github.com/mudge/">mudge</a> for full compatibility with Ruby on Rails version 2.3 or later.</p>
<p>Links: <a href="http://code.google.com/p/rails-fast-sessions/">Project Home Page on Google Code</a> | <a href="http://kovyrin.net/2008/02/06/fastsessions-rails-plugin-released/">Introduction Blog Post</a> | <a href="http://github.com/mudge/fast_sessions/">Fork on GitHub Compatible with Rails 2.3 and Later</a>.</p>
<h3><a name="loops" href="http://github.com/kovyrin/loops/">loops</a></h3>
<p>loops is a small and lightweight library for Ruby on Rails,  Merb and other frameworks created to support simple background loops in your application which are usually used to do some background data processing on your servers (queue workers, batch tasks processors, etc).</p>
<p>Originally loops plugin was created to make our own loops code more organized. We used to have tens of different modules with methods that were called with script/runner and then used with nohup and other not so convenient backgrounding techniques. When you have such a number of loops/workers to run in background it becomes a nightmare to manage them on a regular basis (restarts, code upgrades, status/health checking, etc).</p>
<p>After a short time of writing our loops in more organized ways we were able to generalize most of the loops code so now our loops look like a classes with a single mandatory public method called run. Everything else (spawning many workers, managing them, logging, backgrounding, pid-files management, etc) is handled by the plugin itself.</p>
<p>Links: <a href="http://github.com/kovyrin/loops/">Project Home Page on GitHub</a> | <a href="http://kovyrin.net/2009/02/17/loops-plugin-for-rails-and-merb-released/">Introduction Blog Post</a> | <a href="http://rdoc.info/projects/kovyrin/loops">RDoc Documentation</a>.</p>
<h3><a name="magic-enum" href="http://github.com/kovyrin/magic-enum/">magic-enum</a></h3>
<p>Method used to define ENUM-like attributes in your model (int fields actually). It&#8217;s easier to show what it does in code rather than to explain in plain English:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Statuses = <span style="color:#006600; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color:#ff3333; font-weight:bold;">:unknown</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">0</span>,<br />
&nbsp; <span style="color:#ff3333; font-weight:bold;">:draft</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">1</span>,<br />
&nbsp; <span style="color:#ff3333; font-weight:bold;">:published</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">2</span>,<br />
&nbsp; <span style="color:#ff3333; font-weight:bold;">:approved</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">3</span><br />
<span style="color:#006600; font-weight:bold;">&#125;</span><br />
define_enum <span style="color:#ff3333; font-weight:bold;">:status</span>, <span style="color:#ff3333; font-weight:bold;">:default</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">1</span>, <span style="color:#ff3333; font-weight:bold;">:raise_on_invalid</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span>, <span style="color:#ff3333; font-weight:bold;">:simple_accessors</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">true</span></div></td></tr></tbody></table></div>
<p>is identical to</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">Statuses = <span style="color:#006600; font-weight:bold;">&#123;</span><br />
&nbsp; <span style="color:#ff3333; font-weight:bold;">:unknown</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">0</span>,<br />
&nbsp; <span style="color:#ff3333; font-weight:bold;">:draft</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">1</span>,<br />
&nbsp; <span style="color:#ff3333; font-weight:bold;">:published</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">2</span>,<br />
&nbsp; <span style="color:#ff3333; font-weight:bold;">:approved</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">3</span><br />
<span style="color:#006600; font-weight:bold;">&#125;</span><br />
StatusesInverted = Statuses.<span style="color:#9900CC;">invert</span><br />
<br />
<span style="color:#9966CC; font-weight:bold;">def</span> status<br />
&nbsp; StatusesInverted<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#0000FF; font-weight:bold;">self</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:status</span><span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">to_i</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span> StatusesInverted<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006666;">1</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
<span style="color:#9966CC; font-weight:bold;">def</span> status=<span style="color:#006600; font-weight:bold;">&#40;</span>value<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#CC0066; font-weight:bold;">raise</span> <span style="color:#CC00FF; font-weight:bold;">ArgumentError</span>, <span style="color:#996600;">&quot;Invalid value <span style="color:#000099;">\&quot;</span>#{value}<span style="color:#000099;">\&quot;</span> for :status attribute of the #{self.class} model&quot;</span> <span style="color:#9966CC; font-weight:bold;">if</span> <br />
&nbsp; Statuses<span style="color:#006600; font-weight:bold;">&#91;</span>value<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#0000FF; font-weight:bold;">nil</span>?<br />
&nbsp; <span style="color:#0000FF; font-weight:bold;">self</span><span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:status</span><span style="color:#006600; font-weight:bold;">&#93;</span> = Statuses<span style="color:#006600; font-weight:bold;">&#91;</span>value<span style="color:#006600; font-weight:bold;">&#93;</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
<span style="color:#9966CC; font-weight:bold;">def</span> unknown?<br />
&nbsp; status == <span style="color:#ff3333; font-weight:bold;">:unknown</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
<span style="color:#9966CC; font-weight:bold;">def</span> draft?<br />
&nbsp; status == <span style="color:#ff3333; font-weight:bold;">:draft</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
<span style="color:#9966CC; font-weight:bold;">def</span> published?<br />
&nbsp; status == <span style="color:#ff3333; font-weight:bold;">:published</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
<span style="color:#9966CC; font-weight:bold;">def</span> approved?<br />
&nbsp; status == <span style="color:#ff3333; font-weight:bold;">:approved</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>This plugin was originally developed for <a href="http://www.bestechvideos.com/">Best Tech Videos</a>and later was cleaned up in Scribd repository and released to the public.</p>
<p>Links: <a href="http://github.com/kovyrin/magic-enum/">Project Home Page on GitHub</a> | <a href="http://rdoc.info/projects/kovyrin/magic-enum/">RDoc Documentation</a>.</p>
<h3><a name="rlibsphinxclient" href="http://github.com/kpumuk/rlibsphinxclient/">rlibsphinxclient</a></h3>
<p>A Ruby wrapper for pure C searchd client API library. It works much faster than any Ruby client for Sphinx, so you can check it to ensure you application works as fast as possible.</p>
<p>Please note: this is *highly experimental* library so use it at your own risk.</p>
<p>Links: <a href="http://github.com/kpumuk/rlibsphinxclient/">Project Home Page on GitHub</a> | <a href="http://rdoc.info/projects/kpumuk/rlibsphinxclient/">RDoc Documentation</a>.</p>
<h3><a name="rscribd" href="http://github.com/scribd/rscribd/">rscribd</a></h3>
<p>Ruby client library for the Scribd API. This gem provides a simple and powerful library for the Scribd API, allowing you to write Ruby applications or Ruby on Rails websites that upload, convert, display, search, and control documents in many formats. For more information on the Scribd platform, visit the <a href="http://www.scribd.com/developers">Scribd Platform Documentation</a> page.</p>
<p>The main features are:</p>
<ul>
<li>Upload your documents to Scribd&#8217;s servers and access them using the gem</li>
<li>Upload local files or from remote web sites</li>
<li>Search, tag, and organize documents</li>
<li>Associate documents with your users&#8217; accounts</li>
</ul>
<p>Links: <a href="http://github.com/scribd/rscribd/">Project Home Page on GitHub</a> | <a href="http://www.scribd.com/developers">Scribd Platform Documentation</a> | <a href="http://rdoc.info/projects/scribd/rscribd">RDoc Documentation</a>.</p>
<h3><a name="rspec-cells" href="http://github.com/kpumuk/rspec-cells/">Rspec Cells</a></h3>
<p>This plugin allows you to test your cells easily using RSpec. Basically, it adds an example group especially for cells, with several helpers to perform cells rendering.</p>
<p>If you are not sure what is cells, please visit its <a href="http://cells.rubyforge.org/">home page</a>.</p>
<p>Spec for a regular cell could look like:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">describe VideoCell <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; integrate_views<br />
<br />
&nbsp; &nbsp; context <span style="color:#996600;">'.videos'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; it <span style="color:#996600;">'should initialize :videos variable'</span> <span style="color:#9966CC; font-weight:bold;">do</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:id</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#006666;">10</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; session<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:user_id</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#006666;">20</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; opts<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:opt</span><span style="color:#006600; font-weight:bold;">&#93;</span> = <span style="color:#996600;">'value'</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; result = render_cell <span style="color:#ff3333; font-weight:bold;">:videos</span>, <span style="color:#006600; font-weight:bold;">&#123;</span> <span style="color:#ff3333; font-weight:bold;">:videos</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">&#125;</span>, <span style="color:#ff3333; font-weight:bold;">:slug</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'hello'</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; result.<span style="color:#9900CC;">should</span> have_tag<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'div'</span>, :<span style="color:#9966CC; font-weight:bold;">class</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#ff3333; font-weight:bold;">:videos</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>Links: <a href="http://github.com/kpumuk/rspec-cells/">Project Home Page on GitHub</a> | <a href="http://cells.rubyforge.org/">Cells Home Page</a> | <a href="http://github.com/apotonick/cells/">Cells Home Page on GitHub</a>.</p>
<h3><a name="scribd-uploader" href="http://github.com/RISCfuture/scribd-uploader/">Scribd Desktop Uploader</a></h3>
<p>A fully native Cocoa Macintosh uploader app for the Scribd.com website. Supports following features:</p>
<ul>
<li>Upload many files at once from your desktop.</li>
<li>Edit titles, tags, and other metadata before uploading.</li>
<li>Quickly and easily manage bulk uploads, straight from your desktop.</li>
<li>Right-click to start uploading files directly to Scribd (Windows only).</li>
</ul>
<p>Links: <a href="http://github.com/RISCfuture/scribd-uploader/">Project Home Page on GitHub</a> | <a href="http://www.scribd.com/tools/uploader/">Home Page on Scribd.com</a>.</p>
<h3><a name="changelog"></a>Changelog</h3>
<ul>
<li><strong>September 9, 2009</strong>
<ul>
<li>Fixed a link to GitHub homepage of the <a href="#rspec-cells">rspec-cells</a> plugin.</li>
</ul>
</li>
<li><strong>September 8, 2009</strong>
<ul>
<li>Added <a href="#rspec-cells">rspec-cells</a> plugin.</li>
</ul>
</li>
</ul>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=SKCiCjE3EhE:gZVsHp-MI-8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=SKCiCjE3EhE:gZVsHp-MI-8:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=SKCiCjE3EhE:gZVsHp-MI-8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=SKCiCjE3EhE:gZVsHp-MI-8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=SKCiCjE3EhE:gZVsHp-MI-8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=SKCiCjE3EhE:gZVsHp-MI-8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=SKCiCjE3EhE:gZVsHp-MI-8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=SKCiCjE3EhE:gZVsHp-MI-8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=SKCiCjE3EhE:gZVsHp-MI-8:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/kpumuk-ru/~4/SKCiCjE3EhE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kpumuk.info/development/scribd-open-source-projects/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://kpumuk.info/development/scribd-open-source-projects/</feedburner:origLink></item>
		<item>
		<title>Creating a simple but powerful profiler for Ruby on Rails</title>
		<link>http://feedproxy.google.com/~r/kpumuk-ru/~3/9EeyVMhuUM8/</link>
		<comments>http://kpumuk.info/ruby-on-rails/creating-a-simple-but-powerful-profiler-for-ruby-on-rails/#comments</comments>
		<pubDate>Wed, 26 Aug 2009 21:23:15 +0000</pubDate>
		<dc:creator>Dmytro Shteflyuk</dc:creator>
				<category><![CDATA[Ruby & Rails]]></category>
		<category><![CDATA[easy-prof]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[profiling]]></category>

		<guid isPermaLink="false">http://kpumuk.info/ruby-on-rails/creating-a-simple-but-powerful-profiler-for-ruby-on-rails/</guid>
		<description><![CDATA[You are developing a large Web application. Controllers are full of complex data retrieving logic, views contain tons of blocks, partials, loops. One day you will receive an email with user complaints about some of your pages slowness. There are many profiling tools, some of them are easy (ruby-prof), others are large and complex (newrelic), [...]]]></description>
			<content:encoded><![CDATA[<p>You are developing a large Web application. Controllers are full of complex data retrieving logic, views contain tons of blocks, partials, loops. One day you will receive an email with user complaints about some of your pages slowness. There are many profiling tools, some of them are easy (ruby-prof), others are large and complex (newrelic), but regardless of this it&#8217;s really hard to find the particular place where you have a real bottleneck. So we created really simple, but über-useful tool for ruby code profiling.</p>
<p class="more"><span id="more-900"></span></p>
<p>First of all, we need to decide what features we need from this tool. Don&#8217;t know about you, but all I need is to measure execution time of particular ruby code block. Here is what I mean:</p>
<div class="codecolorer-container text twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br /></div></td><td><div class="text codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">[home#index] debug: Logged in user home page<br />
[home#index] progress: 0.7002 s [find top videos]<br />
[home#index] progress: 0.0452 s [build categories list]<br />
[home#index] progress: 0.0019 s [build tag cloud]<br />
[home#index] progress: 0.0032 s [find featured videos]<br />
[home#index] progress: 0.0324 s [find latest videos]<br />
[home#index] debug: VIEW STARTED<br />
[home#index] progress: 0.0649 s [top videos render]<br />
[home#index] progress: 0.0014 s [categories render]<br />
[home#index] progress: 2.5887 s [tag cloud render]<br />
[home#index] progress: 0.0488 s [latest videos render]<br />
[home#index] progress: 0.1053 s [featured video render]<br />
[home#index] results: 3.592 seconds</div></td></tr></tbody></table></div>
<p>So what do we see from this output? There are two slow blocks: top videos retrieving and tag cloud rendering. Now we just know what to do to make this page faster.</p>
<p>Let&#8217;s write the code:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br />90<br />91<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">module</span> EasyProfiler<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">class</span> Profile<br />
&nbsp; &nbsp; @@profile_results = <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span><br />
<br />
&nbsp; &nbsp; cattr_accessor <span style="color:#ff3333; font-weight:bold;">:enable_profiling</span><br />
&nbsp; &nbsp; @@enable_profiling = <span style="color:#0000FF; font-weight:bold;">false</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; cattr_accessor <span style="color:#ff3333; font-weight:bold;">:print_limit</span><br />
&nbsp; &nbsp; @@print_limit = <span style="color:#006666;">0.01</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">start</span><span style="color:#006600; font-weight:bold;">&#40;</span>name, options = <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:enabled</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span>= @@enable_profiling<br />
&nbsp; &nbsp; &nbsp; options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:limit</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span>= @@print_limit<br />
&nbsp; &nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> NoProfileInstance.<span style="color:#9900CC;">new</span> <span style="color:#9966CC; font-weight:bold;">unless</span> options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:enabled</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> @@profile_results<span style="color:#006600; font-weight:bold;">&#91;</span>name<span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;EasyProfiler::Profile.start() collision! '#{name}' is already started!&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> NoProfileInstance.<span style="color:#9900CC;">new</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; @@profile_results<span style="color:#006600; font-weight:bold;">&#91;</span>name<span style="color:#006600; font-weight:bold;">&#93;</span> = ProfileInstance.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>name, options<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">stop</span><span style="color:#006600; font-weight:bold;">&#40;</span>name, options = <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:enabled</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span>= @@enable_profiling<br />
&nbsp; &nbsp; &nbsp; options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:limit</span><span style="color:#006600; font-weight:bold;">&#93;</span> <span style="color:#006600; font-weight:bold;">||</span>= @@print_limit<br />
&nbsp; &nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> <span style="color:#9966CC; font-weight:bold;">unless</span> options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:enabled</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">unless</span> @@profile_results<span style="color:#006600; font-weight:bold;">&#91;</span>name<span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">puts</span> <span style="color:#996600;">&quot;EasyProfiler::Profile.stop() error! '#{name}' is not started yet!&quot;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:#0000FF; font-weight:bold;">return</span> <span style="color:#0000FF; font-weight:bold;">false</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; total = @@profile_results<span style="color:#006600; font-weight:bold;">&#91;</span>name<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">total</span><br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">if</span> total <span style="color:#006600; font-weight:bold;">&gt;</span> options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:limit</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; @@profile_results<span style="color:#006600; font-weight:bold;">&#91;</span>name<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">buffer_checkpoint</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;results: %0.4f seconds&quot;</span> <span style="color:#006600; font-weight:bold;">%</span> total<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; @@profile_results<span style="color:#006600; font-weight:bold;">&#91;</span>name<span style="color:#006600; font-weight:bold;">&#93;</span>.<span style="color:#9900CC;">dump_results</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; @@profile_results.<span style="color:#9900CC;">delete</span><span style="color:#006600; font-weight:bold;">&#40;</span>name<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">class</span> ProfileInstance<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>name, options = <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@name</span> = name<br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@start</span> = <span style="color:#0066ff; font-weight:bold;">@progress</span> = <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span>.<span style="color:#9900CC;">to_f</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@buffer</span> = <span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#006600; font-weight:bold;">&#93;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> progress<span style="color:#006600; font-weight:bold;">&#40;</span>message<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; progress = <span style="color:#006600; font-weight:bold;">&#40;</span>now = <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span>.<span style="color:#9900CC;">to_f</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#006600; font-weight:bold;">-</span> <span style="color:#0066ff; font-weight:bold;">@progress</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@progress</span> = now<br />
&nbsp; &nbsp; &nbsp; buffer_checkpoint<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;progress: %0.4f seconds [#{message}]&quot;</span> <span style="color:#006600; font-weight:bold;">%</span> progress<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> debug<span style="color:#006600; font-weight:bold;">&#40;</span>message<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@progress</span> = <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span>.<span style="color:#9900CC;">to_f</span><br />
&nbsp; &nbsp; &nbsp; buffer_checkpoint<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;debug: #{message}&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> total<br />
&nbsp; &nbsp; &nbsp; <span style="color:#CC00FF; font-weight:bold;">Time</span>.<span style="color:#9900CC;">now</span>.<span style="color:#9900CC;">to_f</span> <span style="color:#006600; font-weight:bold;">-</span> <span style="color:#0066ff; font-weight:bold;">@start</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> buffer_checkpoint<span style="color:#006600; font-weight:bold;">&#40;</span>message<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@buffer</span> <span style="color:#006600; font-weight:bold;">&lt;&lt;</span> message<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> dump_results<br />
&nbsp; &nbsp; &nbsp; profile_logger.<span style="color:#9900CC;">info</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;[#{@name}] Benchmark results:&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@buffer</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>message<span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; profile_logger.<span style="color:#9900CC;">info</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;[#{@name}] #{message}&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> profile_logger<br />
&nbsp; &nbsp; &nbsp; root = <span style="color:#CC00FF; font-weight:bold;">Object</span>.<span style="color:#9900CC;">const_defined</span>?<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:RAILS_ROOT</span><span style="color:#006600; font-weight:bold;">&#41;</span> ? <span style="color:#996600;">&quot;#{RAILS_ROOT}/log&quot;</span> : <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">dirname</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#0000FF; font-weight:bold;">__FILE__</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@profile_logger</span> <span style="color:#006600; font-weight:bold;">||</span>= <span style="color:#CC00FF; font-weight:bold;">Logger</span>.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>root <span style="color:#006600; font-weight:bold;">+</span> <span style="color:#996600;">'/profile.log'</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">class</span> NoProfileInstance<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> progress<span style="color:#006600; font-weight:bold;">&#40;</span>message<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> debug<span style="color:#006600; font-weight:bold;">&#40;</span>message<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>We have defined two class attributes: <code class="codecolorer ruby default"><span class="ruby"><span style="color:#6666ff; font-weight:bold;">EasyProfiler::Profile</span>.<span style="color:#9900CC;">enable_profiling</span></span></code> (to be able to disable or enable profiler globally) and <code class="codecolorer ruby default"><span class="ruby"><span style="color:#6666ff; font-weight:bold;">EasyProfiler::Profile</span>.<span style="color:#9900CC;">print_limit</span></span></code> (to filter out from log code blocks that are fast enough).</p>
<p>Then we defined two methods, which accept name of profile session (for example, &#8220;home#index&#8221;), and hash of options. Possible options are <code class="codecolorer ruby default"><span class="ruby"><span style="color:#ff3333; font-weight:bold;">:enabled</span></span></code> (to enable profiling of particular block) and <code class="codecolorer ruby default"><span class="ruby"><span style="color:#ff3333; font-weight:bold;">:limit</span></span></code> (limit in seconds to filter out fast code fragments).</p>
<p>Method <code class="codecolorer ruby default"><span class="ruby">start</span></code> returns an instance of profiler, which will be used to print check points. It contains two useful methods: <code class="codecolorer ruby default"><span class="ruby">debug</span></code> (to display custom message) and <code class="codecolorer ruby default"><span class="ruby">progress</span></code> (to display a message along with time spent since last checkpoint). Both methods define a new checkpoint.</p>
<p>To simplify usage, let&#8217;s create a helper:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">module</span> <span style="color:#CC00FF; font-weight:bold;">Kernel</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> easy_profiler<span style="color:#006600; font-weight:bold;">&#40;</span>name, options = <span style="color:#006600; font-weight:bold;">&#123;</span><span style="color:#006600; font-weight:bold;">&#125;</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">yield</span> <span style="color:#6666ff; font-weight:bold;">EasyProfiler::Profile</span>.<span style="color:#9900CC;">start</span><span style="color:#006600; font-weight:bold;">&#40;</span>name, options<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">ensure</span><br />
&nbsp; &nbsp; <span style="color:#6666ff; font-weight:bold;">EasyProfiler::Profile</span>.<span style="color:#9900CC;">stop</span><span style="color:#006600; font-weight:bold;">&#40;</span>name, options<span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>And now example:</p>
<div class="codecolorer-container ruby twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br /></div></td><td><div class="ruby codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color:#9966CC; font-weight:bold;">class</span> HomeController <span style="color:#006600; font-weight:bold;">&lt;</span> ApplicationController<br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> index<br />
&nbsp; &nbsp; easy_profiler<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">'home#index'</span>, <span style="color:#ff3333; font-weight:bold;">:enabled</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> profile_request?, <span style="color:#ff3333; font-weight:bold;">:limit</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">2</span><span style="color:#006600; font-weight:bold;">&#41;</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span><span style="color:#CC0066; font-weight:bold;">p</span><span style="color:#006600; font-weight:bold;">|</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">p</span>.<span style="color:#9900CC;">progress</span> <span style="color:#996600;">'logged in user home page'</span><br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@top_videos</span> = Video.<span style="color:#9900CC;">top</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:limit</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">10</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">p</span>.<span style="color:#9900CC;">progress</span> <span style="color:#996600;">'find top videos'</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@categories</span> = Category.<span style="color:#9900CC;">all</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:order</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">'name DESC'</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">p</span>.<span style="color:#9900CC;">progress</span> <span style="color:#996600;">'build categories list'</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@tag_cloud</span> = Tag.<span style="color:#9900CC;">tag_cloud</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:limit</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">200</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">p</span>.<span style="color:#9900CC;">progress</span> <span style="color:#996600;">'build tag cloud'</span><br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@featured_videos</span> = Video.<span style="color:#9900CC;">featured</span><span style="color:#006600; font-weight:bold;">&#40;</span>limit <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">5</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">p</span>.<span style="color:#9900CC;">progress</span> <span style="color:#996600;">'find featured videos'</span><br />
<br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@latest_videos</span> = Video.<span style="color:#9900CC;">latest</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:limit</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#006666;">5</span><span style="color:#006600; font-weight:bold;">&#41;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">p</span>.<span style="color:#9900CC;">progress</span> <span style="color:#996600;">'find latest videos'</span><br />
&nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; <span style="color:#0066ff; font-weight:bold;">@profiler</span> = <span style="color:#CC0066; font-weight:bold;">p</span><br />
&nbsp; &nbsp; &nbsp; <span style="color:#CC0066; font-weight:bold;">p</span>.<span style="color:#9900CC;">debug</span> <span style="color:#996600;">'VIEW STARTED'</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
&nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<br />
&nbsp; private<br />
&nbsp; <br />
&nbsp; &nbsp; <span style="color:#008000; font-style:italic;"># Method returns +true+ if current request should ouput profiling information</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">def</span> profile_request?<br />
&nbsp; &nbsp; &nbsp; params<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">'_with_profiling'</span><span style="color:#006600; font-weight:bold;">&#93;</span> == <span style="color:#996600;">'yes'</span><br />
&nbsp; &nbsp; <span style="color:#9966CC; font-weight:bold;">end</span><br />
<span style="color:#9966CC; font-weight:bold;">end</span></div></td></tr></tbody></table></div>
<p>and view:</p>
<div class="codecolorer-container html4strict twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br /></div></td><td><div class="html4strict codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;top_videos&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render :partial <span style="color: #66cc66;">=</span>&gt;</span> 'top_videos' %&gt;<br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;% @profiler.progress <span style="color: #ff0000;">'top videos render'</span> %&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; <br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tabs&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ul</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;taxonomy&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#&quot;</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;categories&quot;</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;current&quot;</span>&gt;</span>Categories<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">li</span>&gt;&lt;<span style="color: #000000; font-weight: bold;">a</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;#&quot;</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tags&quot;</span>&gt;</span>Tags<span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">a</span>&gt;&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">li</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">ul</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;categories_panel&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render :partial <span style="color: #66cc66;">=</span>&gt;</span> 'categories' %&gt;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% @profiler.progress <span style="color: #ff0000;">'categories render'</span> %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;categories_panel hidden&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render :partial <span style="color: #66cc66;">=</span>&gt;</span> 'tag_cloud' %&gt;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% @profiler.progress <span style="color: #ff0000;">'tag cloud render'</span> %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; <br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">class</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;box&quot;</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;latest&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render :partial <span style="color: #66cc66;">=</span>&gt;</span> 'videos', :videos =&gt; @latest_videos %&gt;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% @profiler.progress <span style="color: #ff0000;">'latest videos render'</span> %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;featured&quot;</span>&gt;</span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;%<span style="color: #66cc66;">=</span> render :partial <span style="color: #66cc66;">=</span>&gt;</span> 'videos', :videos =&gt; @featured_videos %&gt;<br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;">&lt;% @profiler.progress <span style="color: #ff0000;">'featured video render'</span> %&gt;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span><br />
&nbsp; <span style="color: #009900;">&lt;<span style="color: #66cc66;">/</span><span style="color: #000000; font-weight: bold;">div</span>&gt;</span></div></td></tr></tbody></table></div>
<p>As you can see from this example, profiler will be enabled only when you pass a <tt>_with_profiling</tt> parameter with value <tt>yes</tt>: <tt>http://example.com/home?_with_profiling=yes</tt>.</p>
<p>That&#8217;s all. If you have any question, feel free to post a comment or <a href="/contact">contact me</a>.</p>
<p>Update: I have created a Rails plugin called <a href="http://github.com/kpumuk/easy-prof/">easy-prof</a>, which is hosted on GitHub. It&#8217;s more powerful and feature complete, so feel free to grab sources and play with it by yourself (check the RDoc documentation at <a href="http://rdoc.info/projects/kpumuk/easy-prof">rdoc.info</a>). Do not forget to drop me a line about your feelings.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=9EeyVMhuUM8:D53VBadYbqs:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=9EeyVMhuUM8:D53VBadYbqs:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=9EeyVMhuUM8:D53VBadYbqs:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=9EeyVMhuUM8:D53VBadYbqs:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=9EeyVMhuUM8:D53VBadYbqs:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=9EeyVMhuUM8:D53VBadYbqs:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=9EeyVMhuUM8:D53VBadYbqs:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=9EeyVMhuUM8:D53VBadYbqs:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=9EeyVMhuUM8:D53VBadYbqs:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/kpumuk-ru/~4/9EeyVMhuUM8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kpumuk.info/ruby-on-rails/creating-a-simple-but-powerful-profiler-for-ruby-on-rails/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://kpumuk.info/ruby-on-rails/creating-a-simple-but-powerful-profiler-for-ruby-on-rails/</feedburner:origLink></item>
		<item>
		<title>10 recommendations on using HTML5 today (aka Homo-Adminus Blog 2.0 HTML5ified)</title>
		<link>http://feedproxy.google.com/~r/kpumuk-ru/~3/UfVMQfnVlHU/</link>
		<comments>http://kpumuk.info/development/10-recommendations-on-using-html5-today/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 14:00:14 +0000</pubDate>
		<dc:creator>Dmytro Shteflyuk</dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Links]]></category>
		<category><![CDATA[friends]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[Internet]]></category>

		<guid isPermaLink="false">http://kpumuk.info/?p=751</guid>
		<description><![CDATA[There was a lot of articles about HTML5 last days, so when Alexey Kovyrin asked me to help him with his new blog design I saw no other choice but using HTML5. There are a lot of new features added since HTML4, and some of them could be used today, like new elements &#60;header&#62;, &#60;footer&#62;, [...]]]></description>
			<content:encoded><![CDATA[<p>There was a lot of articles about HTML5 last days, so when <a href="http://kovyrin.net/">Alexey Kovyrin</a> asked me to help him with his new blog design I saw no other choice but using HTML5. There are a lot of new features added since HTML4, and some of them could be used today, like new elements <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;header<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code>, <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;footer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code>, <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;nav<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code>, <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;article<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code>, <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;section<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code>, etc. I think this is a nice addition to the HTML, because these elements add more sense to an unstructured markup. There is a buzzword &#8220;semantic&#8221; exists to describe this, but I don&#8217;t like buzzwords, so I would call it &#8220;sense&#8221;. So what features we could get from HTML5, that are supported by all modern browsers?</p>
<p class="more"><span id="more-751"></span></p>
<p>Ok, there is not so much of a difference between HTML4 and HTML5 from web-developer standpoint, just some <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span>&gt;</span></span></code> elements are replaced with more meaningful ones (I&#8217;m talking about <a href="http://www.w3.org/TR/html5-diff/#language">markup</a> now, not about new <a href="http://www.w3.org/TR/html5-diff/#apis">APIs</a>. Here is what I mean:</p>
<div class="codecolorer-container xml twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br /></div></td><td><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #00bbdd;">&lt;!DOCTYPE html&gt;</span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;html</span> <span style="color: #000066;">lang</span>=<span style="color: #ff0000;">&quot;en&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Homo-Adminus Blog<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/title<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;link</span> <span style="color: #000066;">rel</span>=<span style="color: #ff0000;">&quot;stylesheet&quot;</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;style.css&quot;</span> <span style="color: #000066;">type</span>=<span style="color: #ff0000;">&quot;text/css&quot;</span> <span style="color: #000066;">media</span>=<span style="color: #ff0000;">&quot;screen&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span><br />
&nbsp; &nbsp; <span style="color: #808080; font-style: italic;">&lt;!--[if IE]&gt;</span><br />
<span style="color: #808080; font-style: italic;">&nbsp; &nbsp; &lt;script src=&quot; http://html5shiv.googlecode.com/svn/trunk/html5.js&quot;&gt;&lt;/script&gt;</span><br />
<span style="color: #808080; font-style: italic;">&nbsp; &nbsp; &lt;![endif]--&gt;</span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/head<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;container&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;header</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;page-header&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;nav</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;menu&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Home<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Resume/CV<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Projects<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Photos<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Contact<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/nav<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/header<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;div</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;page-content&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;section</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;content&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;article<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;header<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;h2<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Loops plugin for rails and merb released<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/h2<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;p</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;meta&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Posted by Scoundrel under<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Development<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>My Projects<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Networks<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/header<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;aside<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;time</span> <span style="color: #000066;">datetime</span>=<span style="color: #ff0000;">&quot;2008-08-20&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Sun 20<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;br</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>Aug<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;br</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>2008<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/time<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/aside<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;section</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;text&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Article content goes here.<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/section<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;footer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Tags:<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span> <span style="color: #000066;">rel</span>=<span style="color: #ff0000;">&quot;tag&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>github<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span> <span style="color: #000066;">rel</span>=<span style="color: #ff0000;">&quot;tag&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>plugin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#comments&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>1 Comment<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> |<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Bookmark on del.icio.us<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/p<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/footer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/article<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/section<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;footer</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;page-footer&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Copyright <span style="color: #ddbb00;">&amp;#169;</span> 2009 <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Alexey Kovyrin<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> |<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Designed by <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Tatiana Kovyrina<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/footer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;nav</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;sidebar&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;section</span> <span style="color: #000066;">id</span>=<span style="color: #ff0000;">&quot;categories&quot;</span> <span style="color: #000066;">class</span>=<span style="color: #ff0000;">&quot;left&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;header<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;h3<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>Categories<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/h3<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/header<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Admin-tips<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> (26)<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Blog<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> (2)<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;li<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;a</span> <span style="color: #000066;">href</span>=<span style="color: #ff0000;">&quot;#&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>Databases<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span> (33)<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/li<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/ul<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/section<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/nav<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/div<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/body<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/html<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></td></tr></tbody></table></div>
<p>In a few words: the only difference is that we use new HTML elements instead of descriptive CSS class names and IDs. I&#8217;m not going to describe all new features of HTML5 here, the good introduction could be found <a href="http://www.sitepoint.com/article/html-5-snapshot-2009/">here</a> or <a href="http://net.tutsplus.com/tutorials/html-css-techniques/html-5-and-css-3-the-techniques-youll-soon-be-using/">here</a>.</p>
<p>Here are my recommendations on using HTML5 today:</p>
<ol>
<li>
<p>To enable new HTML5 elements in IE you should use <code class="codecolorer javascript default"><span class="javascript">document.<span style="color: #660066;">createElement</span></span></code> &#8212; see lines 6-8, explanation is <a href="http://remysharp.com/2009/01/07/html5-enabling-script/">here</a>.</p>
</li>
<li>
<p>Ensure that new HTML5 elements are block level:</p>
<div class="codecolorer-container css twitlight" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;"><table cellspacing="0" cellpadding="0"><tbody><tr><td style="padding:5px;text-align:center;color:#888888;background-color:#EEEEEE;border-right: 1px solid #9F9F9F;font: normal 12px/1.4em Monaco, Lucida Console, monospace;"><div>1<br />2<br />3<br />4<br />5<br /></div></td><td><div class="css codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">header<span style="color: #00AA00;">,</span> footer<span style="color: #00AA00;">,</span> section<span style="color: #00AA00;">,</span> nav<span style="color: #00AA00;">,</span> article<span style="color: #00AA00;">,</span> aside <span style="color: #00AA00;">&#123;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">margin</span><span style="color: #00AA00;">:</span> <span style="color: #933;">0px</span><span style="color: #00AA00;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">padding</span><span style="color: #00AA00;">:</span> <span style="color: #933;">0px</span><span style="color: #00AA00;">;</span><br />
&nbsp; &nbsp; <span style="color: #000000; font-weight: bold;">display</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">block</span><span style="color: #00AA00;">;</span><br />
<span style="color: #00AA00;">&#125;</span></div></td></tr></tbody></table></div>
</li>
<li>
<p>Use <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;section<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code> element if you need to add a block of specific content, like categories list (lines 54-61). Use good old <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span>&gt;</span></span></code> to add a markup element with no specific sense (for example, <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">div</span> <span style="color: #000066;">id</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;container&quot;</span>&gt;</span></span></code> on line 11).</p>
</li>
<li>
<p>Use <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;nav<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code> element to create any sort of navigation panes (top-level menu, sidebar, footer links). <strong>Do not use <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;aside<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code> to create sidebars &#8212; this is wrong!</strong></p>
</li>
<li>
<p><code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;header<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code> and <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;footer<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code> elements are good candidates to wrap any heading (logo, top level navigation, and almost everything that visually is under the main content) and bottom (article metadata, page footer, bottom links, and almost everything that visually is below the main content) information. You can use these elements inside other elements like <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;nav<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code>, <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;article<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code>, or <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;section<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code>, so use them.</p>
</li>
<li>
<p>New element <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;article<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code> contains a block of information inside the main content area. It could be an article or blog post, a comment, a particular book description in bookstore, etc. Be creative and use this exciting element to fill your pages with a sense.</p>
</li>
<li>
<p>The most controversial element is <code class="codecolorer xml default"><span class="xml"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;aside<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></span></code>. Lots of articles about HTML5 in the Internet suggest to use it for the sidebar navigation, but that is absolutely wrong. Use this tag to take some information out of primary content. Good candidates are footnotes or side notes, quotes, comment author&#8217;s avatar, etc. Yes, I&#8217;ll repeat: be creative.</p>
</li>
<li>
<p>Almost everything you do in HTML4 is valid for HTML5: use unordered lists <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ul</span>&gt;</span></span></code> of list items where order does not matter, use ordered lists <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">ol</span>&gt;</span></span></code> otherwise. Use tables (yes, <code class="codecolorer html4strict default"><span class="html4strict"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">table</span>&gt;</span></span></code>) for tabular data structures (and not for layout). Paragraphs, emphasizes, quotes, and much more elements should take their own place in your markup.</p>
</li>
<li>
<p>Use <a href="http://html5.validator.nu/">validator</a> to ensure you are doing it right.</p>
</li>
<li>
<p>Read the code. The good place to start from is <a href="http://html5gallery.com/">HTML5 Gallery</a>.</p>
</li>
</ol>
<p>You can start using HTML5 right now. It&#8217;s our future, and we need to know, how would it look like.</p>
<p>PS. Did you notice the nice code syntax highlighting in this blog? I&#8217;m using <a href="http://kpumuk.info/projects/wordpress-plugins/codecolorer/">CodeColorer &#8212; the best syntax highlighting plugin for WordPress</a>. Try it and you will stay with it forever!</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=UfVMQfnVlHU:VCPpESqfrBU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=UfVMQfnVlHU:VCPpESqfrBU:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=UfVMQfnVlHU:VCPpESqfrBU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=UfVMQfnVlHU:VCPpESqfrBU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=UfVMQfnVlHU:VCPpESqfrBU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=UfVMQfnVlHU:VCPpESqfrBU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=UfVMQfnVlHU:VCPpESqfrBU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/kpumuk-ru?a=UfVMQfnVlHU:VCPpESqfrBU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/kpumuk-ru?i=UfVMQfnVlHU:VCPpESqfrBU:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/kpumuk-ru/~4/UfVMQfnVlHU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://kpumuk.info/development/10-recommendations-on-using-html5-today/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		<feedburner:origLink>http://kpumuk.info/development/10-recommendations-on-using-html5-today/</feedburner:origLink></item>
	</channel>
</rss>
