<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

    <title>Tomash Corner</title>
    <generator uri="https://github.com/jekyll/jekyll">Jekyll v2.4.0</generator>
		<icon>/apple-touch-icon-precomposed.png</icon>
    <subtitle>Homepages are dead anyway</subtitle>
    <link href="/atom.xml" rel="self"/>
    <link href="/" rel="alternate" type="text/html"/>
    <updated>2015-03-24T11:02:45+01:00</updated>
    <id>/</id>
    <author>
			<name>Tomash</name>
			<uri>/</uri>
			<email>tomekrs@o2.pl</email>
		</author>

    
    <entry>
        <title>Integrating with Dropbox API for fun and profit</title>
        <link href="/blog/2012/09/04/integrating-with-dropbox-api-for-fun-and-profit/"/>
        <updated>2012-09-04T00:00:00+02:00</updated>
        <id>/blog/2012/09/04/integrating-with-dropbox-api-for-fun-and-profit</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Integrating with Dropbox &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; for fun and profit&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;04 Sep 2012 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h2&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;Integrating with Dropbox &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; and using its one, relatively new feature, resulted in both improved user experience and reduced operation costs for my store with music. Includes technical details and code.&lt;/p&gt;
&lt;h2&gt;A Shameless Plug&lt;/h2&gt;
&lt;p&gt;If you follow me on Twitter (or any other social service), you probably know that in may I&amp;#8217;ve launched my first startup, &lt;a href=&quot;http://musicrage.org&quot;&gt;MusicRage.org&lt;/a&gt; which is about, basically, selling time-limited packages of independent music with strict time limit (a package is available to buy for two weeks), priced with pay-what-you-want model. Yes, it is heavily inspired by &lt;a href=&quot;http://www.humblebundle.com/&quot;&gt;HumbleBundle&lt;/a&gt; , but for music.&lt;/p&gt;
&lt;p&gt;You can see for yourself, as at the time of publishing this blog post we&amp;#8217;re running fourth round of packages, with four different genres (rock, electronic, indie/alternative and comedy).&lt;/p&gt;
&lt;h2&gt;The problem with buying music on the internet&amp;#8230;&lt;/h2&gt;
&lt;p&gt;&amp;#8230; is not only the actual buying, but downloading and managing bought files. One usually needs to either download and decompress an archive file (usually zip) containing the whole album or, in worst-case-scenario, download every. Single. File. Separately. This is one of the things that Apple did properly with iTunes: combining buying, managing and listening of music in one, convenient application. But this is also something that a store nowhere close to iTunes market share is able to pull off.&lt;/p&gt;
&lt;p&gt;When MusicRage launched, we&amp;#8217;ve offered both &amp;#8220;classical&amp;#8221; ways of downloading bought files: either single files or a zip archive with whole album in desired format (be it &lt;span class=&quot;caps&quot;&gt;WAV&lt;/span&gt; or MP3). But, for a whole package of four albums, that still means downloading (click, select destination, &amp;#8216;save&amp;#8217;) and unzipping (click, select destination, &amp;#8216;extract&amp;#8217;) four zipfiles. I&amp;#8217;m not even touching the idea of downloading all files separately.&lt;/p&gt;
&lt;p&gt;There should certainly be a more convenient way of getting bought music, maybe even more convenient than what every BitTorrent client does (download a whole folder of ready-to-play files). I agree with Gabe Newell that customers want to buy content and support creators, &lt;a href=&quot;http://www.escapistmagazine.com/news/view/114391-Valves-Gabe-Newell-Says-Piracy-Is-a-Service-Problem&quot;&gt;it&amp;#8217;s just that the service usually sucks&lt;/a&gt; .&lt;/p&gt;
&lt;h2&gt;Enter Dropbox&lt;/h2&gt;
&lt;p&gt;I love &lt;a href=&quot;https://www.dropbox.com/&quot;&gt;Dropbox&lt;/a&gt; . They have solved the problem of backing up, synchronizing and collaborating on files in a way that&amp;#8217;s painless for user and doesn&amp;#8217;t require technical knowledge.&lt;/p&gt;
&lt;p&gt;What&amp;#8217;s even better, less than a year ago, &lt;a href=&quot;https://blog.dropbox.com/index.php/the-dropbox-api/&quot;&gt;Dropbox has launched their &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;&lt;/a&gt; that allows third-party applications to interact with user&amp;#8217;s Dropbox, in a way that&amp;#8217;s both secure (by default applications can operate only within a specified directory in user&amp;#8217;s Dropbox account) and convenient (authorizing applications via OAuth).&lt;/p&gt;
&lt;p&gt;Dropbox integration could do for MusicRage what iTunes does: have all the music files of a given album downloaded, backed up and ready-to-play with whole operation stripped down to single click of &amp;#8220;add this album to my Dropbox&amp;#8221;. Use a cool &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; that could also reduce our operations costs (see below)? There was simply no reason for me to refuse such idea.&lt;/p&gt;
&lt;p&gt;How Dropbox could reduce our operations costs? We host our downloadable files on S3, which has many upsides (bandwidth, scalability, security) and one downside (it costs). If we could find a way to put the files on Dropbox once and then make them copy to other users&amp;#8217; accounts within Dropbox infrastructure, that could remove the need to upload file for every single user. Which saves time and bandwidth for everyone.&lt;/p&gt;
&lt;h2&gt;A short story of copy_ref&lt;/h2&gt;
&lt;p&gt;There was once a functionality of Dropbox that prevented multiple uploading of same file by different users: when the application has detected that a file of this size and hash is already on Dropbox, it would just copy it internally (probably make a hardlink, I have no idea about Dropbox&amp;#8217; internals) and therefore finish &amp;#8220;upload&amp;#8221; of even largest file in a split second.&lt;/p&gt;
&lt;p&gt;This feature been disabled after &lt;a href=&quot;http://www.fozworks.com/blog/2009/12/19/dropbox-knows-quite-a-lot-actually/&quot;&gt;concerns have been raised&lt;/a&gt; and some &lt;a href=&quot;https://github.com/driverdan/dropship&quot;&gt;applications that exploit this feature have appeared&lt;/a&gt; . Other parts of it (uploading only changed parts, similar to how RSync works) are still there, but if we were to upload MusicRage files onto users&amp;#8217; Dropbox, for every file we&amp;#8217;d still have to do at least one full upload for every single user. Not the effectiveness I&amp;#8217;ve been hoping for.&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t want to initiate a Dropbox upload for every single file added-to-dropbox by every single MusicRage customer. It takes a noticeable time, so would require background job workers and, since uploaded by our servers, puts us at risk of hitting the limit of our upload bandwidth (it&amp;#8217;s exactly the reason why I&amp;#8217;ve decided to host downloadables on S3 in the first place). Might make the dropboxy experience actually worse than manual file download. No way.&lt;/p&gt;
&lt;p&gt;But then, a few months ago, &lt;a href=&quot;https://www.dropbox.com/developers/blog/16&quot;&gt;copy_ref has been introduced&lt;/a&gt; which is basically the same functionality, but implemented in a secure and non-exploitable way. It&amp;#8217;s available only via &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; and application needs to know the exact reference hash of the file already stored on Dropbox to make a quick copy. Which is &lt;b&gt;exactly&lt;/b&gt; what I was looking for!&lt;/p&gt;
&lt;h2&gt;Choose your &lt;del&gt;poison&lt;/del&gt; gem&lt;/h2&gt;
&lt;p&gt;MusicRage is a Ruby On Rails application, so I began looking for decent gem that&amp;#8217;d wrap Dropbox &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; in some nice Ruby objects.&lt;/p&gt;
&lt;p&gt;Copy_ref has been introduced 6 months ago (as of writing this blog post, obviously), but &lt;a href=&quot;https://rubygems.org/gems/dropbox-sdk&quot;&gt;official Dropbox gem&lt;/a&gt; still doesn&amp;#8217;t have support for it. I&amp;#8217;ve of course found that out after some experiments, registering MusicRage as a Dropbox application and basically producing some working code.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s &lt;a href=&quot;https://rubygems.org/gems/dropbox&quot;&gt;an another Ruby gem for interacting with Dropbox &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;&lt;/a&gt;, but I&amp;#8217;ve closed my browser tab after reading about authorizing by (de)serializing OAuth session object. That&amp;#8217;s not how you do OAuth and I&amp;#8217;m not going that way.&lt;/p&gt;
&lt;p&gt;Finally I&amp;#8217;ve settled for &lt;a href=&quot;https://rubygems.org/gems/dropbox-api&quot;&gt;dropbox-api&lt;/a&gt; gem that&amp;#8217;s not only supporting copy_ref part of Dropbox &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;, but also has more ruby-esque library design than the official one. I was positively surprised after finding out that it&amp;#8217;s actually written and maintained by &lt;a href=&quot;http://www.bunsch.pl/&quot;&gt;Marcin Bunsch&lt;/a&gt; , a guy I know (and admire).&lt;/p&gt;
&lt;h2&gt;Getting (finally) dirty&lt;/h2&gt;
&lt;p&gt;Enough fluff. I like sharing code and ideas, and I&amp;#8217;m all out of ideas. Let&amp;#8217;s get down to the actual Ruby code that lets a webapp like MusicRage use Dropbox &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; and its copy_ref part for great justice!&lt;/p&gt;
&lt;p&gt;First, a standard setup of application key-secret pair in an initializer:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# config/initializers/dropbox.rb&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# you might want to put the key and secret in a configuration file&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# that&amp;#39;s not versioned with application code&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Dropbox&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app_key&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;xxxyyyzzz&amp;#39;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Dropbox&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app_secret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;aaabbbccc&amp;#39;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# &amp;#39;sandbox&amp;#39; mode because designated app-exclusive directory is fine for us&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Dropbox&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mode&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;sandbox&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Before user can request application to add files to his Dropbox, he needs authorize the application with Dropbox first:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# app/controllers/dropbox_controller.rb&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;authorize&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Dropbox&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;OAuth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:authorize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;request_token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_request_token&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:request_token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request_token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:request_token_secret&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request_token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secret&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request_token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;authorize_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:oauth_callback&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order_authorized_callback_dropbox_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;authorized_callback&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Dropbox&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;OAuth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:authorize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;request_token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OAuth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RequestToken&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;consumer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:request_token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:request_token_secret&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;access_token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request_token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_access_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:oauth_verifier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:oauth_token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# MusicRage doesn&amp;#39;t have &amp;#39;Users&amp;#39;, just Orders accessed with secure URLs&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# that&amp;#39;s why we save key-secret pair on Order, not User basis&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dropbox_access_key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;token&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dropbox_access_secret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secret&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order_download_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course due to copy_ref constraints, every single file should store its copy_ref after being uploaded to Dropbox. Here&amp;#8217;s a part of &amp;#8220;Dropbox seed&amp;#8221; script that goes through newly-added albums, asks the Dropbox for given file and saves its copy_ref in the database:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# script/dropbox_seed.rb&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# album_asset is an instance of ActiveRecord model&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;album&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tracks&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;album_asset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;original_filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;find_original_file_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;album_asset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;df&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;$client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;relative_file_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;album&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original_filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;df&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;copy_ref&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;copy_ref&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;album_asset&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update_attribute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:dropbox_copy_ref&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now that we have copy_refs and a user willing to get these files into his Dropbox, let&amp;#8217;s try the simplest, most-straightforward way to use them (synchronously, therefore with an optimistic assumption, for now, that the time for all those copy_ref &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; calls will be before the request times out):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# app/controllers/dropbox_controller.rb&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# that&amp;#39;s some ugly code, a proof-of-concept&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;add_album&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Check if user has no dropbox session, redirect to authorize if so&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;authorize&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dropbox_access_key&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;present?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dropbox_access_secret&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;present?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Dropbox&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;API&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dropbox_access_key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:secret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dropbox_access_secret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;album&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;albums&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:album_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;album&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tracks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:format&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dropbox_copy_ref&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;present?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;copy_from_copy_ref&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dropbox_copy_ref&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;album&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dropbox_directory_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aa&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asset_spaced_filename&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;flash&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:notice&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Added &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; files to your Dropbox&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;order_download_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;access_token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And&amp;#8230; here it is. The code presented here is ugly and from the feature-spike time, but proven to work exactly as expected. It&amp;#8217;s the least-working code, so do yourself a favor and refactor it!&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Adding this single feature results in everyone winning:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;User: it improves user experience (getting album with a single click)&lt;/li&gt;
	&lt;li&gt;MusicRage: decreasing operation costs&lt;/li&gt;
	&lt;li&gt;Dropbox: engaging users to use Dropbox more (maybe upgrade to a paid account)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This might sound mighty fluffy, but I&amp;#8217;m all in for situations where some work (in this case, a few lines of code) makes everyone involved win.&lt;/p&gt;
&lt;p&gt;If you ever do an application that provides user with large or multitude of files, think about how many clicks it will require to use these files. Because maybe there&amp;#8217;s a service your application could leverage to improve the experience.&lt;/p&gt;
&lt;p&gt;Oh, and if you haven&amp;#8217;t yet, check out &lt;a href=&quot;http://musicrage.org&quot;&gt;MusicRage.org&lt;/a&gt; , there&amp;#8217;s some really awesome music there.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>A new laptop</title>
        <link href="/blog/2012/02/25/a-new-laptop/"/>
        <updated>2012-02-25T00:00:00+01:00</updated>
        <id>/blog/2012/02/25/a-new-laptop</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;A new laptop&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;25 Feb 2012 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h2&gt;Requirements&lt;/h2&gt;
&lt;p&gt;My previous, worn but reliable (and still kicking) everyday laptop, Asus K80S, got over 3 years old this winter. It was getting old, not only in terms of performance (Core2Duo and 2GBs of &lt;span class=&quot;caps&quot;&gt;RAM&lt;/span&gt; was enough of a spec for everyday programming work under Ubuntu), but also in terms of comfort: below 2 hours battery time started to be an issue recently, during long train or plane trips, or when doing some coding at the cafes.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve decided to upgrade. I wanted my laptop light and thin: below 2 kg, without optical drive. I wanted a decent performance: at least i3, preferred i5. And, last but very important, I wanted at least 4-5 hours of battery time when working (text editor, rails server, occasional test run) in Linux.&lt;/p&gt;
&lt;p&gt;After some research I&amp;#8217;ve settled for Asus U36SD. Asus, because this brand has never failed me (despite around dozen Asus laptops being in the family since quite a few years) and &lt;a href=&quot;http://lifehacker.com/5524704/laptop+reliability-study-highlights-the-most-sturdy-laptop-makers&quot;&gt;laptop reliability studies confirm that.&lt;/a&gt; U36SD seemed to have exactly the configuration I needed, packing i5 &lt;span class=&quot;caps&quot;&gt;CPU&lt;/span&gt; and 8 hours of battery time in a small, stylish, portable and light (1.5kg) chassis with 13.3&amp;quot; screen. As an added bonus, it came with dynamically-switched NVidia GeForce card and &lt;span class=&quot;caps&quot;&gt;OEM&lt;/span&gt; Windows 7, for occasional gaming.&lt;/p&gt;
&lt;p&gt;All under $1000 (for us, Europeans, the prices are a bit higher due to &lt;span class=&quot;caps&quot;&gt;VAT&lt;/span&gt;), which is a steal and therefore a laptop I&amp;#8217;m not afraid of losing (or having stolen etc.).&lt;/p&gt;
&lt;h2&gt;Experiment&lt;/h2&gt;
&lt;p&gt;I&amp;#8217;ve heard mixed opinions about recent Ubuntu versions since switching to &lt;a href=&quot;http://unity.ubuntu.com/&quot;&gt;Unity&lt;/a&gt;, some people recommending going with Mint and others being happy with this interface overhaul.&lt;/p&gt;
&lt;p&gt;Because I had some time for fun and experiments, I&amp;#8217;ve decided to install Ubuntu 64bit (!) 12.04 alpha1 (!!) on a new (released in october 2011) laptop (!!!), thus introducing at least three reasons for everything to fail with a bang. But the nerd and hacker inside me wanted to have some fun, even if it meant blowing things up and starting from scratch.&lt;/p&gt;
&lt;p&gt;To everyone&amp;#8217;s surprise, Ubuntu 12.04 64bit LiveCD booted up and had everything working out of the box, including wifi, sound and webcam. Installed like a charm on some freshly-fred disk space and&amp;#8230; that&amp;#8217;s the whole experiment.&lt;/p&gt;
&lt;p&gt;The only tinkering left for me was, based on &lt;a href=&quot;https://help.ubuntu.com/community/Asus_U36SD&quot;&gt;official Ubuntu wiki for U36SD&lt;/a&gt; (albeit written for older versions), adding a script to control &lt;a href=&quot;https://help.ubuntu.com/community/Asus_U36SD#Suspend&quot;&gt;&lt;span class=&quot;caps&quot;&gt;USB&lt;/span&gt; buses on suspend&lt;/a&gt; and installing &lt;a href=&quot;https://github.com/Bumblebee-Project/bbswitch&quot;&gt;bbswitch&lt;/a&gt; to completely disable Nvidia graphics card in Linux (to use only Intel HD3000 and extend battery life to almost 6 hours). Everything else Just Worked&amp;#8482;, often even better and smoother than on my friends&amp;#8217; Macbooks. Ubuntu has come a long way since the early releases, in a direction I&amp;#8217;m really happy with.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; 6 hours of actual work time in Linux, with either WiFi or 3G modem (Android phone).&lt;/p&gt;
&lt;h2&gt;Step Three&lt;/h2&gt;
&lt;p&gt;There&amp;#8217;s no step three. I have an everyday laptop for work that I&amp;#8217;m really happy with after almost a month of usage, not much to add here. Whenever somebody&amp;#8217;s looking for a new laptop with Linux for programming work, I wholeheartedly recommend Asus U36SD + Ubuntu 12.04 combo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This post was in no way endorsed by Asus or its business partners. Although it&amp;#8217;d be cool if it were.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Bitspudlo.com now powered by Spree</title>
        <link href="/blog/2011/07/01/bitspudlo-com-now-powered-by-spree/"/>
        <updated>2011-07-01T00:00:00+02:00</updated>
        <id>/blog/2011/07/01/bitspudlo-com-now-powered-by-spree</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Bitspudlo.com now powered by Spree&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;01 Jul 2011 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h2&gt;Originally at Spree-User google group&lt;/h2&gt;
&lt;p&gt;This is a recap and extension of post I&amp;#8217;ve written on Spree group on 28th may:&lt;/p&gt;
&lt;p&gt;https://groups.google.com/d/topic/spree-user/FWQxXPMyLG0/discussion&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Migrating to Spree, part 1: The Code</title>
        <link href="/blog/2011/05/01/migrating-to-spree-part-1/"/>
        <updated>2011-05-01T00:00:00+02:00</updated>
        <id>/blog/2011/05/01/migrating-to-spree-part-1</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Migrating to Spree, part 1: The Code&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;01 May 2011 &amp;#8211; Warsaw&lt;/p&gt;
&lt;p&gt;(continued from &lt;a href=&quot;/2011/04/24/migrating-to-spree-part-0.html&quot;&gt;previous post&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;The Plan&lt;/h2&gt;
&lt;p&gt;&amp;#8230; was pretty simple. First, export products and categories to &lt;span class=&quot;caps&quot;&gt;JSON&lt;/span&gt; files, using some very simple rake tasks:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:export&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;export categories&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:categories&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:environment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Category&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:conditions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:available&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:methods&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name_pl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name_en&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:description_pl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:description_en&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;export products&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:products&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:environment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:conditions&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:available&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:methods&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:title_pl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title_en&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:description_pl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:description_en&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:full_image_path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Second, check the differences in schema (column names etc.) and, while trying to preserve IDs (pretty crucial for seamless import), import these &lt;span class=&quot;caps&quot;&gt;JSON&lt;/span&gt; files into Spree store.&lt;/p&gt;
&lt;p&gt;The final working import code is (I&amp;#8217;ve decided that english will be the basic language for database content, while Polish Zloty will remain as the base currency) ended up as another rake tasks, this time within the codebase of new, Spree-powered engine &lt;a href=&quot;https://github.com/tomash/bitspudlo.com/blob/master/lib/tasks/import.rake&quot;&gt;lib/tasks/import.rake&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Execution&lt;/h2&gt;
&lt;p&gt;It worked. Of course the import code required some work to achieve the final working state it&amp;#8217;s now in, but basically it was one of the smoothest migrations I ever worked on.&lt;/p&gt;
&lt;h2&gt;Outstanding Issues&lt;/h2&gt;
&lt;p&gt;I still have this itching urge to import orders as well, for all our customers to have a nice order history, but this is quite a task and I&amp;#8217;ve left that in the backlog, &amp;#8220;to be done when I&amp;#8217;ll have both the time and will&amp;#8221;.&lt;/p&gt;
&lt;h2&gt;What&amp;#8217;s Next?&lt;/h2&gt;
&lt;p&gt;Of course migrating data isn&amp;#8217;t the only thing that had to be done in order to have a fully working new Spree-powered Bitspudlo.com.&lt;/p&gt;
&lt;p&gt;But all the other steps are basically documented in &lt;a href=&quot;https://groups.google.com/d/topic/spree-user/FWQxXPMyLG0/discussion&quot;&gt;a post on Spree group I wrote after completing the successful migration&lt;/a&gt; .&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Migrating to Spree, part 0: Introduction</title>
        <link href="/blog/2011/04/24/migrating-to-spree-part-0/"/>
        <updated>2011-04-24T00:00:00+02:00</updated>
        <id>/blog/2011/04/24/migrating-to-spree-part-0</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Migrating to Spree, part 0: Introduction&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;24 Apr 2011 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h2&gt;Nostalgia&lt;/h2&gt;
&lt;p&gt;When I&amp;#8217;ve decided, back in 2007, to learn Rails seriously, I was looking for some &amp;#8220;real&amp;#8221; project to code while learning Rails. Just like &lt;span class=&quot;caps&quot;&gt;DHH&lt;/span&gt;, I believe that &lt;a href=&quot;http://37signals.com/svn/posts/2582-how-do-i-learn-to-program&quot;&gt;trying some technology only makes sense if you do a real project with it&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And so a real project happened, when Krzysztof approached me with an actual plan to implement our common idea and start an e-commerce focused on selling bits from Games Workshop plastic sets. Long story short, one &amp;#8220;Agile Web Development With Rails&amp;#8221; (first edition &amp;#8212; I &lt;strong&gt;do not&lt;/strong&gt; recommend this book to anyone) and a few weeks laters, &lt;a href=&quot;http://bitspudlo.com&quot;&gt;Bitspudlo.com&lt;/a&gt; was born.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;re a lot of &lt;span class=&quot;caps&quot;&gt;SVN&lt;/span&gt; (remember, it was the first half of 2007!) and Git commits documenting the development of this store engine. But I&amp;#8217;ve refused to go with a ready-to-go e-commerce solution. First, I wanted to learn Rails on a real project. Second, back then all open-source e-commerce engines were written in &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt;. In a very bad &lt;span class=&quot;caps&quot;&gt;PHP&lt;/span&gt; (and some of them remain such today).&lt;/p&gt;
&lt;h2&gt;Hard Decisions&lt;/h2&gt;
&lt;p&gt;Flash forward four years and it&amp;#8217;s april 2011. Bitspudlo, started on Rails 1.2.6, updated regularly and now powered by Rails 2.3.8, is the only application I&amp;#8217;ve been working with during the last 7 months that&amp;#8217;s still on Rails 2.&amp;#215;. Moving it to 3.0 would require quite a bit of tiresome work (especially with some of the gems and plugins used) and there are still some features in my backlog that either Krzysztof, I, or both of us would like to have implemented (especially now that our store has grown to a truly international one). In the meantime I&amp;#8217;ve set up a few e-stores based on an awesome Rails-based e-commerce engine called &lt;a href=&quot;http://spreecommerce.com&quot;&gt;Spree&lt;/a&gt;, most notably &lt;a href=&quot;http://topastic.com&quot;&gt;Topastic&lt;/a&gt; and &lt;a href=&quot;http://store.pulp-city.com&quot;&gt;Pulp City Store&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The decision has been made to migrate to Spree. I was ready to move to Spree. The thing is, Spree and its ecosystem of extensions wasn&amp;#8217;t ready yet for us. Two key business requirements, namely multi-linguality (of both the views and database-stored content) and multi-currency, couldn&amp;#8217;t be met unless I wrote all the code by myself. Which is kind of hard, considering the fact I have a full-time job and Bitspudlo.com is just a hobby project.&lt;/p&gt;
&lt;h2&gt;One Step At A Time&lt;/h2&gt;
&lt;p&gt;Being quite fluent with &lt;a href=&quot;https://github.com/svenfuchs/globalize3&quot;&gt;Globalize3&lt;/a&gt; (actually being one of the maintainers of this awesome gem), back in november 2010 I&amp;#8217;ve hacked the simplest working extension for globalizing names of products and categories (in Spree they&amp;#8217;re called &amp;#8220;taxons&amp;#8221;, with a good reason behind that), basically gluing Spree and Globalize3 together. The simplicity of it made me love Ruby, Rails, Globalize and Spree even more. It was more like proof-of-concept, but good enought to consider Spree integrated with Globalize.&lt;/p&gt;
&lt;p&gt;Around the same time (november 2010) when I was playing with making Spree globalizable, two talented programmers, namely &lt;a href=&quot;https://github.com/pronix&quot;&gt;pronix&lt;/a&gt; and &lt;a href=&quot;https://github.com/parallel588&quot;&gt;parallel588&lt;/a&gt; have started a Spree extension for multi-currency support, &lt;a href=&quot;https://github.com/pronix/spree-multi-currency&quot;&gt;spree-multi-currency&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;It was more than enough. There were no more excuses to avoid the migration.&lt;/p&gt;
&lt;p&gt;TO BE &lt;span class=&quot;caps&quot;&gt;CONTINUED&lt;/span&gt;&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>&#39;Globalize is slow&#39; meme must die</title>
        <link href="/blog/2010/11/08/globalize-is-slow-must-die/"/>
        <updated>2010-11-08T00:00:00+01:00</updated>
        <id>/blog/2010/11/08/globalize-is-slow-must-die</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;&amp;#8216;Globalize is slow&amp;#8217; meme must die&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;08 Nov 2010 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h2&gt;Instead of introduction&lt;/h2&gt;
&lt;p&gt;It all started &lt;a href=&quot;http://groups.google.com/group/spree-user/browse_thread/thread/40a0823368074c9&quot;&gt;here, on Spree google group&lt;/a&gt; after I&amp;#8217;ve released skeleton of extension allowing to integrate edge Spree with &lt;a href=&quot;http://github.com/svenfuchs/globalize3&quot;&gt;Globalize3&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Some history of &amp;#8216;Globalize is slow&amp;#8217;&lt;/h2&gt;
&lt;p&gt;Globalize1 kept all the translations in one table and therefore used polymorphic associations (and, I don&amp;#8217;t remember exactly, but possibly every single translated field had its own row). Which of course was slow as hell after the number of translated stuff grew considerably.&lt;/p&gt;
&lt;p&gt;Additionally the problem of N+1 queries (for each product on page there was a query for getting its translated fields, each one slow already by itself) was hard to circumvent due to mixed philosophy of catch-all (single polymorphic table) and atomicity (each field in separate row).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.artweb-design.de/2007/1/31/upcoming-globalize-feature-an-alternative-way-of-storing-model-translations&quot;&gt;There were of course attempts to hack it&lt;/a&gt; but the damage has been done and thus Globalize has become known as a serious performance hog.&lt;/p&gt;
&lt;h2&gt;Globalize done right&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/joshmh/globalize2&quot;&gt;Globalize2&lt;/a&gt; &amp;#8212; and, by extension, &lt;a href=&quot;https://github.com/svenfuchs/globalize3&quot;&gt;Globalize3&lt;/a&gt; which is basically &amp;#8220;2&amp;#8221; but rewritten for Rails3 compatibility allowing for cleaner code and &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; &amp;#8212; used a different approach. Every translated model has it&amp;#8217;s own &amp;#8220;something_translations&amp;#8221; table, consisting of columns with translated values (and, of course, locale for which it&amp;#8217;s used). Which is not a very surprising design decision, provided both were developed mostly by &lt;a href=&quot;http://svenfuchs.com&quot;&gt;Sven Fuchs&lt;/a&gt;, the author of the blog post linked above.&lt;/p&gt;
&lt;p&gt;Now, theoretically the problem of N+1 queries is still here (every single item needs to query for a single row from product_translations), but it&amp;#8217;s hell of a lot easier to prevent it now:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Product&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;translates&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:description&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;named_scope&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:with_translations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:include&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:translations&lt;/span&gt; 
  &lt;span class=&quot;c1&quot;&gt;# or even, for maximum comfort &lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;default_scope&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:include&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:translations&lt;/span&gt; 
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;#8217;ve been using Globalize2 for some time now in &lt;a href=&quot;http://bitspudlo.com&quot;&gt;my store&lt;/a&gt; &lt;br /&gt;
and using the above solution doesn&amp;#8217;t impair performance at all, the &lt;br /&gt;
app is super-fast.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Simple and short, as shown above &amp;#8212; given the current state of Globalize, its &amp;#8220;slowness&amp;#8221; is just a thing of the past.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Diasappointment</title>
        <link href="/blog/2010/09/16/diasappointment/"/>
        <updated>2010-09-16T00:00:00+02:00</updated>
        <id>/blog/2010/09/16/diasappointment</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Diasappointment&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;16 Sep 2010 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h2&gt;The anticipation&lt;/h2&gt;
&lt;p&gt;I was having high hopes since the first day the &lt;a href=&quot;http://www.joindiaspora.com/&quot;&gt;Diaspora Project&lt;/a&gt; has been announced. I don&amp;#8217;t like Facebook&amp;#8217;s attitude towards privacy and I have soft spot for distributed networks in Jabber spirit. That&amp;#8217;s why I was keeping track of their official blog, promoting the name and idea amongst all of my friends and waiting for the first code release. The fact it was going to be built in Ruby made me even more excited &amp;#8212; I wanted to hack on the thing!&lt;/p&gt;
&lt;p&gt;And so, a few hours ago, the developer preview release &lt;a href=&quot;http://www.joindiaspora.com/2010/09/15/developer-release.html&quot;&gt;has been announced&lt;/a&gt; and the code &lt;a href=&quot;http://github.com/diaspora/diaspora&quot;&gt;put on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;WTFs per minute&lt;/h2&gt;
&lt;p&gt;So I&amp;#8217;ve cloned the repo (mind you, it was a few hours and a lot of commits after the announcement) and started going through it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://static0.blip.pl/user_generated/update_pictures/1222775.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And, fuck, I am disappointed.&lt;/p&gt;
&lt;h2&gt;Licensing&lt;/h2&gt;
&lt;p&gt;AGPL. Affero &lt;span class=&quot;caps&quot;&gt;GPL&lt;/span&gt;. To those who haven&amp;#8217;t heard of that before: it&amp;#8217;s the &lt;span class=&quot;caps&quot;&gt;GPL&lt;/span&gt; of &lt;span class=&quot;caps&quot;&gt;GPL&lt;/span&gt;-based licenses. Basically viral exactly like &lt;span class=&quot;caps&quot;&gt;GPL&lt;/span&gt;, but worse: any code using &lt;span class=&quot;caps&quot;&gt;AGPL&lt;/span&gt; library or tool (not only linked, also merely using!) has to be &lt;span class=&quot;caps&quot;&gt;AGPL&lt;/span&gt; licensed too. And also: web application has to have its full source code easily downloadable if the code is &lt;span class=&quot;caps&quot;&gt;AGPL&lt;/span&gt; licensed.&lt;/p&gt;
&lt;p&gt;Seriously, what the fuck?&lt;/p&gt;
&lt;p&gt;This way you, dear Diaspora developers, have just cut off any commercial potential of Diaspora. No company is going to fork it and offer customized (or in any other way &amp;#8220;premium&amp;#8221;) version. Nobody is going to extract any solution (think: protocol implementation) from the code and release it, because basically &lt;span class=&quot;caps&quot;&gt;AGPL&lt;/span&gt; makes a library or tool unusable for anyone.&lt;/p&gt;
&lt;p&gt;As a homework you can try to think where Ruby On Rails would be today, had it been released under &lt;span class=&quot;caps&quot;&gt;AGPL&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;This is even more surprising considering the fact it&amp;#8217;s been written in Ruby on Rails &amp;#8212; an ecosystem where &lt;span class=&quot;caps&quot;&gt;MIT&lt;/span&gt; license is the standard thing. You&amp;#8217;re using a toolset and ecosystem grown on and thanks to stuff released on &lt;span class=&quot;caps&quot;&gt;MIT&lt;/span&gt; license and suddenly shit in this environment with your ridiculous uber-viral and unusable &lt;span class=&quot;caps&quot;&gt;AGPL&lt;/span&gt;?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://static0.blip.pl/user_generated/update_pictures/1166894.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Code quality&lt;/h2&gt;
&lt;p&gt;But hey, it&amp;#8217;s Ruby on Rails project, and considering how good these programmers boasted to be, they for sure have a decent test suite that could be used in writing one&amp;#8217;s own implementation of at least the protocol. A test suite covering all the code that&amp;#8217;s so awesome that in fear of having it forked and not released they had to &lt;span class=&quot;caps&quot;&gt;AGPL&lt;/span&gt; the shit out of it.&lt;/p&gt;
&lt;h3&gt;Libraries, gems and &amp;#8220;gems&amp;#8221;&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;m not going to rant about specifying Bundler version in the Gemfile &amp;#8212; it&amp;#8217;s dumb and redundant, but only since recently and maybe they just play safe.&lt;/p&gt;
&lt;p&gt;But let&amp;#8217;s go further into Gemfile.&lt;/p&gt;
&lt;p&gt;Devise for authentication? Cool! Unfortunately not &lt;a href=&quot;http://github.com/plataformatec/devise&quot;&gt;the original one from Jose Valim&lt;/a&gt; but some &lt;a href=&quot;http://github.com/BadMinus/devise&quot;&gt;BadMinus fork&lt;/a&gt; that&amp;#8217;s already three months behind the upstream.&lt;/p&gt;
&lt;p&gt;And these two entries from Gemfile kind of speak for themselves:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;mongo_mapper&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;0.8.4&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;http://github.com/jnunemaker/mongomapper.git&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;jnunemaker-validatable&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;1.8.4&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;http://github.com/jnunemaker/validatable.git&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Using a released version of given gem while, at the same time, manually giving path to git repo (the official repo from which gem is released on rubygems.org)? Could someone explain that to me? I don&amp;#8217;t consider &amp;#8220;so that you can clone the whole github repo instead of using a gem already installed in your system gems&amp;#8221; a rational answer.&lt;/p&gt;
&lt;h3&gt;Test coverage&lt;/h3&gt;
&lt;p&gt;There are some tests (rspec, to be precise). I haven&amp;#8217;t read them thoroughly, but the test suite seems kind of sparse. A few tests are better than none, anyway. Still kind of weak for a statement &amp;#8220;all commits must be tested&amp;#8221; being placed on the first page of &lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt; file &amp;#8212; how about you, dear Diaspora team, adhere to these rules first?&lt;/p&gt;
&lt;h3&gt;Focusing on what&amp;#8217;s important&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://github.com/diaspora/diaspora/commit/708e9f88a55cc37130f93cc47b820f62fbf48d2d&quot;&gt;This commit says it all&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Data storage&lt;/h2&gt;
&lt;p&gt;Diaspora uses MongoDB as its primary data storage. Now I&amp;#8217;m all hyped about MongoDB and absolutely love it&amp;#8217;s approach to interfacing and storing data, but let&amp;#8217;s get it straight: &lt;a href=&quot;http://blog.mongodb.org/post/381927266/what-about-durability&quot;&gt;MongoDB doesn&amp;#8217;t have any implementation of single-server durability as for now&lt;/a&gt; and countless flamewars have been burning recently on the internet about that. It&amp;#8217;s been &lt;a href=&quot;http://www.mongodb.org/display/DOCS/Durability+and+Repair&quot;&gt;scheduled to be implemented though&lt;/a&gt; (I guess as a result of these flamewars: that was really some bad press which slowed MongoDB adoption), but still not there.&lt;/p&gt;
&lt;p&gt;MongoDB documentation basically recommends using replication as a mean for durability. And this is a sound of thousand DBAs facepalming when hearing about such reliability model.&lt;/p&gt;
&lt;p&gt;Now, I know social network isn&amp;#8217;t a bank, but not having a single-server durability is a show-stopper for me. I&amp;#8217;m not going to deploy Diaspora with two MongoDB servers &amp;#8212; Diaspora was supposed to be distributed as in &amp;#8220;you can run it for yourself and few friends on a inexpensive &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt;&amp;#8221;.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d prefer to have a &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; db as a primary data storage (tested, reliable, bulletproof and elastic technology) and MongoDB (if having to be used) as some sort of frontend-data/caching/denormalization layer (think wall post with all the comments and authors embedded etc.). Currently MongoDB just isn&amp;#8217;t reliable enough for being a primary data storage for a serious service running with single DB server, period.&lt;/p&gt;
&lt;h2&gt;Protocol&lt;/h2&gt;
&lt;p&gt;There is no specification of the Diaspora Protocol &amp;#8212; a basic thing required for any other diaspora-compliant social networks. While, as far as I remember, there were a few &amp;#8212; including Facebook &amp;#8212; wording their interest in being a diaspora-compliant application.&lt;/p&gt;
&lt;p&gt;Now, I understand being Agile and shit, but not specifying the protocol that is supposed to be the killer-feature of Diaspora up-front?&lt;/p&gt;
&lt;p&gt;Oh yes, I&amp;#8217;ve tried to guess the specs from the code. Which made me stumble upon such &amp;#8220;gems&amp;#8221; like &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; built with string concatenation:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_diaspora_xml&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;XML&amp;gt;&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;post&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_xml&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;lt;/post&amp;gt;&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;lt;/XML&amp;gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Seriously, it&amp;#8217;s 2010. Ruby &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt;::Builder (or, at least, &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;ERB&lt;/span&gt; templates) being a de-facto standard in the Ruby world since at least 2006.&lt;/p&gt;
&lt;p&gt;This &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt; is also not &lt;span class=&quot;caps&quot;&gt;XMPP&lt;/span&gt;. Which is even more disappointing.&lt;/p&gt;
&lt;h2&gt;Apologies&lt;/h2&gt;
&lt;p&gt;I now oficially apologise all the people I&amp;#8217;ve been advertising Diaspora to. I guess I got my lesson on being excited with unreleased software.&lt;/p&gt;
&lt;h2&gt;Soothing balm&lt;/h2&gt;
&lt;p&gt;It&amp;#8217;s a rant, but don&amp;#8217;t get me wrong and don&amp;#8217;t throw Diaspora away. I am not, as it&amp;#8217;s still a very promising software.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s not that the Diaspora team hasn&amp;#8217;t released anything: the guys have released a basically working proof-of-concept. All the technical issues mentioned above are solvable and the codebase has the potential for being great. Hell, I&amp;#8217;ll gladly hack on Diaspora and help improve the codebase (I&amp;#8217;m still excited by the idea).&lt;/p&gt;
&lt;p&gt;Under one condition.&lt;/p&gt;
&lt;p&gt;Change the goddamn license. Throw the brainfucked &lt;span class=&quot;caps&quot;&gt;AGPL&lt;/span&gt; in favor of something usable like &lt;span class=&quot;caps&quot;&gt;MIT&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;Edit&lt;/h2&gt;
&lt;p&gt;The disenchantment is pretty wide on the internet, mostly about the batshit insane license choice &amp;#8212; &lt;a href=&quot;http://jarinheit.posterous.com/diaspora-or-how-to-kill-your-facebook-killer&quot;&gt;here&amp;#8217;s one from Jarin Udom&lt;/a&gt;,&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Rails 3 user notes</title>
        <link href="/blog/2010/08/06/rails-3-user-notes/"/>
        <updated>2010-08-06T00:00:00+02:00</updated>
        <id>/blog/2010/08/06/rails-3-user-notes</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Rails 3 user notes&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;06 Aug 2010 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h2&gt;The future is now&lt;/h2&gt;
&lt;p&gt;After some hacking, experimenting and micro-apps with Ruby 1.9 and Rails 3 betas I&amp;#8217;ve decided to use this still-considered-bleeding-edge stack for a new project here at &lt;a href=&quot;http://aenima.pl/&quot;&gt;Aenima&lt;/a&gt;. There&amp;#8217;s a lot of new stuff both on the surface and under the hood when switching from Ruby 1.8 + Rails 2.x, so I&amp;#8217;ve obliged myself to take notes about new, suprising or otherwise worth mentioning (and memorizing) stuff. It&amp;#8217;s not going to be a comprehensive tutorial, &lt;span class=&quot;caps&quot;&gt;HOWTO&lt;/span&gt; or whatever-you-call it, but should have just enough information for competent Rails 2.x programmer who wants to give Rails 3 a try without nasty surprises.&lt;/p&gt;
&lt;h3&gt;Forget system Ruby, It&amp;#8217;s the last call to install &lt;span class=&quot;caps&quot;&gt;RVM&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;Trying to install Ruby 1.9 system-wide, especially on Debian-based systems (Ubuntu) and to live side-by-side with existing Ruby 1.8 is asking for trouble. If you do it, bad dark unicorns will step from oblivion and rip the guts out of your system with their horns.&lt;/p&gt;
&lt;p&gt;So, &lt;a href=&quot;http://rvm.beginrescueend.com/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;RVM&lt;/span&gt;&lt;/a&gt; it is. It&amp;#8217;s an awesome tool by &lt;a href=&quot;http://twitter.com/wayneeseguin&quot;&gt;Wayne E. Seguin&lt;/a&gt;, in case you lived under a stone for the last half year and haven&amp;#8217;t tried it yet. As for the pitfalls, there&amp;#8217;s only one for Ubuntu users: the piece warning about &amp;#8220;no &amp;#8216;&amp;amp;&amp;amp; return&amp;#8217; in .bashrc&amp;#8221; is crucial because it&amp;#8217;s basically about Ubuntu&amp;#8217;s default .bashrc.&lt;/p&gt;
&lt;p&gt;After installing rvm (and restarting terminal, making sure rvm is working etc.) all that&amp;#8217;s left is&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;rvm install ruby-1.9.2-head
rvm use ruby 1.9.2-head
gem install rails --pre&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;#8217;m using Ruby 1.9.2-head here simply out of habit: I know there&amp;#8217;s some rc out with stable on the horizon, but I&amp;#8217;ve never had problems with the trunk version (since at least march) and it will give me all the &amp;#8220;rc&amp;#8221; and &amp;#8220;stable&amp;#8221; versions goodness on updating.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;caps&quot;&gt;RVM&lt;/span&gt;, while solving most serious problems about developing a Rails 3 app under Ruby 1.9, introduces a few new issues (or pitfalls) on its own, so keep reading.&lt;/p&gt;
&lt;h3&gt;There&amp;#8217;s no escape from Bundler&lt;/h3&gt;
&lt;p&gt;Bundler is the default and only way for Rails 3 to work with gems. It might be possible to force Rails 3 into working with gems without Bundler in the middle, but it&amp;#8217;s a dumb (borderline brainfuck) idea and I&amp;#8217;ve never considered it.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;ve never used Bundler before with some Rails 2.3 application, it&amp;#8217;s better to learn this tool on the old stack that to make a full leap. Bundler introduces quite a shift in both philosophy and methodology (workflow), so it deserves some time dedicated just to learning its fundamentals. The good news is that it&amp;#8217;s working like a charm now and I haven&amp;#8217;t ran into single Bundler bug for a few months now (and thanks to &lt;del&gt;Drogomir&lt;/del&gt; &lt;a href=&quot;http://twitter.com/strzalekk&quot;&gt;Strzałek&lt;/a&gt; I&amp;#8217;m using Bundler on a daily basis since january).&lt;/p&gt;
&lt;p&gt;So, port your existing Rails 2.3 app to use Bundler. Switching &lt;a href=&quot;http://bitspudlo.com/&quot;&gt;BitsPudlo&lt;/a&gt; to Bundler took me 30 minutes and I&amp;#8217;m a pretty slow guy with new tools and with git branches there&amp;#8217;s no risk involved.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been using older versions of Bundler (since 0.6 actually) and switching to 1.0 RC also required some learning: the commands and workflow changed a bit, mostly ones related to locking the gemset.&lt;/p&gt;
&lt;h3&gt;&lt;span class=&quot;caps&quot;&gt;RVM&lt;/span&gt; + Bundler + Capistrano needs some love to work together&lt;/h3&gt;
&lt;p&gt;For starters, Capistrano should run bundle install during deploy:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;namespace&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:deploy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Run bundler command for installing gems&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:bundler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:roles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:app&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;cd &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_path&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;; bundle install&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;after&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;deploy:update_code&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;deploy:bundler&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Also, when there is &lt;span class=&quot;caps&quot;&gt;RVM&lt;/span&gt; on the server, rvm use ruby-1.9.2-head should be ran on every shell login (otherwise someone can incidentally screw things). I prefer the former, as every application has its own shell account anyway so there&amp;#8217;s no need for to use system ruby by default.&lt;/p&gt;
&lt;p&gt;But that doesn&amp;#8217;t solve all the Capistrano-&lt;span class=&quot;caps&quot;&gt;RVM&lt;/span&gt; cooperation issues. &lt;span class=&quot;caps&quot;&gt;RVM&lt;/span&gt; has a Capistrano plugin to make it work smoothly, so this should go into deployment recipe as well:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# taken from http://rvm.beginrescueend.com/integration/capistrano/&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rvm_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;                      &lt;span class=&quot;c1&quot;&gt;# we have RVM in home dir, not system-wide install&lt;/span&gt;
&lt;span class=&quot;vg&quot;&gt;$:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unshift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;HOME&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/.rvm/lib&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# Add RVM&amp;#39;s lib directory to the load path.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;rvm/capistrano&amp;quot;&lt;/span&gt;                  &lt;span class=&quot;c1&quot;&gt;# Load RVM&amp;#39;s capistrano plugin.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rvm_ruby_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;ruby-1.9.2-head&amp;#39;&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# Or whatever env you want it to run in.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I found myself in a situation when Bundler complained and threw an error while running bundle install during deploy. Putting this in deployment recipe fixed the problem&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;default_run_options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:pty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3&gt;Mongrel&lt;/h3&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;gem install mongrel --pre&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;will install a version of (1.2 pre) Mongrel that compiles and works nicely with Ruby 1.9.2 and Rails 3.&lt;/p&gt;
&lt;h3&gt;Databases&lt;/h3&gt;
&lt;p&gt;For MySQL, mysql2 is the way to go &amp;#8212; it&amp;#8217;s Ruby 1.9 compatible and we might see some async performance improvements (thanks to Ilya) in that gem.&lt;/p&gt;
&lt;p&gt;For PostgreSQL, last time I tried gem pg had some issues, but that was a long time ago.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://piotrsarnacki.com/&quot; title=&quot;Piotr Sarnacki&quot;&gt;Drogomir&lt;/a&gt; has been running Mongomapper with Ruby 1.9 and Rails 3 with lot of success, so MongoDB is also a viable choice.&lt;/p&gt;
&lt;p&gt;A rule of thumb that applies to every gem, not only db-related ones: check it on &lt;a href=&quot;http://isitruby19.com/&quot;&gt;IsItRuby1.9&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Testing stack&lt;/h3&gt;
&lt;p&gt;All the sane testing tools have versions/forks that work with Ruby 1.9.2 and Rails 3 already. Because of this adding my favourite test stack only required googling which versions and/or forks should be chosen for compatibility.&lt;/p&gt;
&lt;p&gt;So, to get a popular set of RSpec + Cucumber + Factory_girl + Capybara, here&amp;#8217;s what should land in Gemfile:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rspec&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;gt;= 2.0.0.beta.11&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;rspec-rails&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;gt;= 2.0.0.beta.11&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;factory_girl&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;factory_girl_rails&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;capybara&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;database_cleaner&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;cucumber-rails&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;gt;= 0.3.2&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;cucumber&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;gt;= 0.8&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;launchy&amp;#39;&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# So you can do Then show me the page&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;After usual bundle install, running&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;rails generate rspec:install
    rails generate cucumber:install&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;will put all the required stuff to work.&lt;/p&gt;
&lt;h3&gt;Moar&lt;/h3&gt;
&lt;p&gt;&amp;#8230;will be here after further adventures with Rails 3 on Ruby 1.9.2&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Headless Selenium+Firefox+Xvfb stack (on Gentoo CI server)</title>
        <link href="/blog/2010/06/12/headless-selenium-firefox-xvfb-stack/"/>
        <updated>2010-06-12T00:00:00+02:00</updated>
        <id>/blog/2010/06/12/headless-selenium-firefox-xvfb-stack</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Headless Selenium+Firefox+Xvfb stack (on Gentoo CI server)&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;12 Jun 2010 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h2&gt;The background&lt;/h2&gt;
&lt;p&gt;There&amp;#8217;s this app we&amp;#8217;re doing at &lt;a href=&quot;http://aenima.pl&quot;&gt;Aenima&lt;/a&gt; that has a pretty large test suite. It&amp;#8217;s nothing to brag about in the Ruby community, but here&amp;#8217;s the problem: there are a few things covered with Selenium tests (that is, Cucumber tests ran in Selenium environment). Only the Javascript stuff that we cannot otherwise tests, as we&amp;#8217;re not big fans of C{u|e}lerity. These Selenium-driven scenarios run great on our development boxes, but recently we have set up Integrity (actually &lt;a href=&quot;http://twitter.com/strzalekk&quot;&gt;Strzałek&lt;/a&gt; did it) on our internal development server for some Continuous Integration goodness.&lt;/p&gt;
&lt;p&gt;Having Continuous Integration was a must: the test suite grew so large that a complete run (RSpec + Cucumber) takes from 20 to 40 minutes on our laptops, so it was natural that the frequency of running full test suite dropped considerably within the team, which of course increases the risk of regressions.&lt;/p&gt;
&lt;p&gt;Anyway, the dev/CI server is of course headless, no display nor X, so for some time the Cucumber tests were ran with -selenium parameter, but we all knew it was a temporary workaround (I can&amp;#8217;t even call that a &amp;#8220;solution&amp;#8221;). The CI server had to get a running Firefox-Selenium stack.&lt;/p&gt;
&lt;p&gt;It was a natural choice to go with &lt;a href=&quot;ble&quot;&gt;Xvfb&lt;/a&gt;, the only problem remaining was setting it up and building the rest of the stack on top of it. The man responsible for administration of the dev server, &lt;a href=&quot;http://imanel.org/&quot;&gt;Imanel&lt;/a&gt;, has installed Gentoo on it (despite being a Gentoo-fanboy he&amp;#8217;s a great guy). Something I can sympathize with, considering my (and not only mine) experience with Ubuntu Server. But still if something can be done in a simple way on most of the distros, it probably cannot be done simply in Gentoo.&lt;/p&gt;
&lt;h2&gt;Installing Xvfb on Gentoo&lt;/h2&gt;
&lt;p&gt;Xvfb is basically a part of Xorg system and installing it on a display-less server is something like &amp;#8220;installing X without X&amp;#8221;. For that I needed some ebuild and &lt;span class=&quot;caps&quot;&gt;USE&lt;/span&gt;-flag magic. I&amp;#8217;ve copied (with a slight version bump to avoid collision) the latest Xorg ebuild from portage directory that was considered stable on x86, xorg-server-1.7.6.ebuild&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;mkdir -p /usr/local/portage/x11-base/xorg-server/
cp /usr/portage/x11-base/xorg-server/xorg-server-1.7.6.ebuild /usr/local/portage/x11-base/xorg-server/xorg-server-1.7.6.1.ebuild&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And here are two lines the ebuild I had to change (coming from &lt;a href=&quot;http://forums.gentoo.org/viewtopic-p-5859938.html#5859938&quot;&gt;this thread Gentoo Forums&lt;/a&gt;) in unified diff format:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-diff&quot; data-lang=&quot;diff&quot;&gt;&lt;span class=&quot;gd&quot;&gt;--- /usr/portage/x11-base/xorg-server/xorg-server-1.7.6.ebuild  2010-06-04 16:07:04.000000000 +0200&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+++ /usr/local/portage/x11-base/xorg-server/xorg-server-1.7.6.ebuild    2010-06-10 14:13:29.000000000 +0200&lt;/span&gt;
&lt;span class=&quot;gu&quot;&gt;@@ -16,7 +16,8 @@&lt;/span&gt;
 DESCRIPTION=&amp;quot;X.Org X servers&amp;quot;
 KEYWORDS=&amp;quot;~alpha amd64 arm hppa ~ia64 ~mips ppc ppc64 ~sh ~sparc x86 ~x86-fbsd&amp;quot;

&lt;span class=&quot;gd&quot;&gt;-IUSE_SERVERS=&amp;quot;dmx kdrive xorg&amp;quot;&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+# IUSE_SERVERS=&amp;quot;dmx kdrive xorg&amp;quot;&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+IUSE_SERVERS=&amp;quot;dmx kdrive xorg xvfb&amp;quot;&lt;/span&gt;
 IUSE=&amp;quot;${IUSE_SERVERS} tslib hal ipv6 minimal nptl sdl&amp;quot;
 RDEPEND=&amp;quot;hal? ( sys-apps/hal )
        tslib? ( &amp;gt;=x11-libs/tslib-1.0 x11-proto/xcalibrateproto )
&lt;span class=&quot;gu&quot;&gt;@@ -152,7 +153,7 @@&lt;/span&gt;
                $(use_enable kdrive)
                $(use_enable tslib)
                $(use_enable tslib xcalibrate)
&lt;span class=&quot;gd&quot;&gt;-               $(use_enable !minimal xvfb)&lt;/span&gt;
&lt;span class=&quot;gi&quot;&gt;+               $(use_enable xvfb)&lt;/span&gt;
                $(use_enable !minimal xnest)
                $(use_enable !minimal record)
                $(use_enable !minimal xfree86-utils)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now installing Xvfb-exclusive X was as simple as running&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;USE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;minimal xvfb -xorg&amp;quot;&lt;/span&gt; emerge xorg-server&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Big thanks to &lt;a href=&quot;http://imanel.org/&quot;&gt;Imanel&lt;/a&gt; for reviewing the ebuild, building the digest and making it click.&lt;/p&gt;
&lt;h2&gt;Running Cucumber-Selenium-Firefox trio under Xvfb&lt;/h2&gt;
&lt;p&gt;To run Xvfb and have all X-demanding applications run within it, issue these two commands:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;nohup Xvfb -ac -screen scrn 1280x2000x24 :2.0 &lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DISPLAY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;:2.0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And now everything that needs X &amp;#8212; including Firefox &amp;#8212; will run seamlessly. There are some scrolling/visibility issues with Selenium, that&amp;#8217;s why I&amp;#8217;ve allocated a larger vertical size for the Xvfb display.&lt;/p&gt;
&lt;p&gt;And&amp;#8230; that&amp;#8217;s it! Withing the same screen session you can just run your Cucumber tests and see the selenium ones running and passing (preferably!). Xvfb can even let you make some screenshots of Firefox as the Selenium tests are running, but I haven&amp;#8217;t set that up yet. I&amp;#8217;ll probably be lazy and wait for Hubert to crack this nut.&lt;/p&gt;
&lt;p&gt;To make it roll with Integrity, wrap the two lines above in a bash script (not ruby script, as the &amp;#8220;&amp;amp;&amp;#8221; operand won&amp;#8217;t work) and have it ran right before the Cucumber suite itself.&lt;/p&gt;
&lt;p&gt;Credit for the idea, inspiration and relevant bash lines goes to &lt;a href=&quot;http://hubertlepicki.com&quot;&gt;Hubert Łępicki&lt;/a&gt;, to be more specific &amp;#8212; &lt;a href=&quot;http://hubertlepicki.com/2010/01/09/perfect-solution-for-testing-rails-applications-rspec-cucumber-capybara-selenium-2-0&quot;&gt;a blog post about setting great Rails test stack&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Integrating it with multi-project Integrity&lt;/h2&gt;
&lt;p&gt;Every project added to Integrity should have its own instance of Xvfb, running on separate display, to avoid collision.&lt;/p&gt;
&lt;p&gt;&amp;#8230;rest is coming soon.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>The Awesomeness of Unicorn</title>
        <link href="/blog/2010/01/30/the-awesomeness-of-unicorn/"/>
        <updated>2010-01-30T00:00:00+01:00</updated>
        <id>/blog/2010/01/30/the-awesomeness-of-unicorn</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;The Awesomeness of Unicorn&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;30 Jan 2010 &amp;#8211; Warsaw&lt;/p&gt;
&lt;p&gt;This article is a stub. You can&amp;#8217;t help, I&amp;#8217;m going to make it a full-fledged blog post in &lt;em&gt;the future&lt;/em&gt;. As for now &amp;#8212; &lt;a href=&quot;http://unicorn.bogomips.org/&quot;&gt;Unicorn&lt;/a&gt; ;) is Awesome&lt;/p&gt;
&lt;h2&gt;Unicorn&amp;#8217;s killer features&lt;/h2&gt;
&lt;p&gt;&amp;#8230;or simply advantages over other Rails application servers (Passenger, Mongrel etc.). This is a quite personal list of things that really made me go &amp;#8220;wow&amp;#8221; while and after tinkering with Unicorn and migrating three deployments (development, beta, production) of one application from Passenger to Unicorn.&lt;/p&gt;
&lt;p&gt;So, here&amp;#8217;re the things that make Unicorn awesome for me:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;no matter the amount of instances, application code is loaded from disk only once, by &amp;#8220;master&amp;#8221; Unicorn process (the one that just passes requests and manages workers), worker processes get the memory copy using fork()&lt;/li&gt;
	&lt;li&gt;restarts of the application with zero downtime; simplifying things a bit, Unicorn basically serves old version of the application while the new one is loading and jumps to serving new one the moment it becomes available (it&amp;#8217;s a bit more complex under the hood, but that&amp;#8217;s what it looks like for the client)&lt;/li&gt;
	&lt;li&gt;master process manages all the workers by himself, taking care of killing them, spawning new ones or changing the number of workers caused differenly (see below)&lt;/li&gt;
	&lt;li&gt;whole management of Unicorn done via Unix signals&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;  kill -HUP2 `cat /tmp/unicorn.pid` # to restart the application
  kill -QUIT `cat /tmp/unicorn.pid` # graceful termination (workers can finish processing) &lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
  and these are just two examples from the top of my head (ok, from Capistrano scripts I wrote today).&lt;/li&gt;
	&lt;li&gt;incrementing and decrementing amount of workers is also done by simply sending signals (respectively &lt;span class=&quot;caps&quot;&gt;TTIN&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;TTOU&lt;/span&gt;)&lt;/li&gt;
	&lt;li&gt;&amp;#8230;and other stuff that Unicorn has and does because basically &lt;a href=&quot;http://tomayko.com/writings/unicorn-is-unix&quot;&gt;Unicorn is very Unix&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More to come soon!&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Rails Tricks, part 3a: Distance-based search (introduction)</title>
        <link href="/blog/2009/10/18/rails-tricks-part-3a-distance-based-search/"/>
        <updated>2009-10-18T00:00:00+02:00</updated>
        <id>/blog/2009/10/18/rails-tricks-part-3a-distance-based-search</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Rails Tricks, part 3a: Distance-based search (introduction)&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;18 Oct 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h2&gt;They know where you are&lt;/h2&gt;
&lt;p&gt;Location data and maps are currently all over the internet (I don&amp;#8217;t dare say &amp;#8220;everywhere&amp;#8221;). From the obvious Google Maps and it&amp;#8217;s uses (&amp;#8220;club I recommend to get hammered in&amp;#8221;) to classified ad and auction sites (where you don&amp;#8217;t necessarily see the map per se, but can use location-based search). And there&amp;#8217;s going to be more of it, considering the growth of smartphones with built-in &lt;span class=&quot;caps&quot;&gt;GPS&lt;/span&gt; and the following location-using apps.&lt;/p&gt;
&lt;p&gt;It means, simply, that if you haven&amp;#8217;t encountered the need to have location-based search in your webapp, chances are you&amp;#8217;re going to, very soon.&lt;/p&gt;
&lt;h2&gt;I want to become &amp;#8220;them&amp;#8221;!&lt;/h2&gt;
&lt;p&gt;The whole location-based search stuff is non-trivial due to one reason: Earth is not flat, it&amp;#8217;s a sphere (&lt;a href=&quot;http://en.wikipedia.org/wiki/Figure_of_the_Earth&quot;&gt;a spheroid to be precise&lt;/a&gt;), so we don&amp;#8217;t have simple (x,y) coordinates that we could use to calculate distance using trivial pitagorean formula. Instead, location on Earth is determined using &lt;a href=&quot;http://en.wikipedia.org/wiki/Geographic_coordinate_system&quot;&gt;a pair of two numbers: latitude and longitude&lt;/a&gt;, which are basically a pair of angles.&lt;/p&gt;
&lt;p&gt;It means that in order to calculate distance between two points, given their latitude, longitude pairs, &lt;a href=&quot;http://en.wikipedia.org/wiki/Great-circle_distance&quot;&gt;we need to use quite fancy formula&lt;/a&gt; in order to at least pretend to be accurate.&lt;/p&gt;
&lt;p&gt;But we want to do a search based on the results of this formula. And this one&amp;#8217;s pretty complicated. And it&amp;#8217;s definitely not something you&amp;#8217;d like to repeat in every single &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statement when searching for stuff in a-few-kilometer proximity of given (center) point.&lt;/p&gt;
&lt;h2&gt;Stored procedures are the shit&lt;/h2&gt;
&lt;p&gt;Basically if you don&amp;#8217;t want to repeat something in every &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; statement, you put it in DB&amp;#8217;s stored procedures to be called at any time desired using some simple syntax. This of course is a bit against the idea of &amp;#8220;dumb&amp;#8221; databases that &lt;span class=&quot;caps&quot;&gt;DHH&lt;/span&gt; promotes, but we have to make a choice. I choose to look at the horrendous &amp;#8220;great circle distance formula&amp;#8221; only once, to write a function that&amp;#8217;s going to calculate distances using it between any two given points.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re going to use stored procedures also because of the fact that every complete &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;RDBMS&lt;/span&gt; supports them &amp;#8212; yes, even MySQL, got a procedures language called MySPL.&lt;/p&gt;
&lt;h2&gt;Teasers are wrong, I know&lt;/h2&gt;
&lt;p&gt;This post is actually a meta-post, because after this lenghty and scary introduction I&amp;#8217;m going to show how to implement distance-based search in Rails (well, it&amp;#8217;s actually going to be pretty useful for developers using any language and framework) using these database engines in posts about to follow (in the upcoming week):&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;PostgreSQL&lt;/li&gt;
	&lt;li&gt;MySQL&lt;/li&gt;
	&lt;li&gt;MongoDB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The list entries above will consequently change into links leading to article about implementing distance-based search using the given DB. Stay tuned!&lt;/p&gt;
&lt;p&gt;And yes, you read it properly: while first two posts about to follow are going to be about well-known, popular and estabilished players in world of database servers for web application, the third one is going to be about implementing this non-trivial functionality using new kid on the block, a document-oriented database &lt;a href=&quot;http://www.mongodb.org/&quot;&gt;MongoDB&lt;/a&gt; gaining popularity amongst Ruby/Rails devs. I already fell in love with it after reading a lot and using a bit. And that&amp;#8217;s not only me &amp;#8212; the fact that on the upcoming &lt;a href=&quot;http://rupy.eu/&quot;&gt;RuPy&lt;/a&gt; conference in Poland there&amp;#8217;re going to be &lt;a href=&quot;http://rupy.eu/speakers/&quot;&gt;two talks about MongoDB&lt;/a&gt; (with one from Obie Fernandez himself) speaks for itself.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Rails Tricks, part 2: Mislav&#39;s Will_Paginate</title>
        <link href="/blog/2009/10/09/rails-tricks-part-2-mislav-will_paginate/"/>
        <updated>2009-10-09T00:00:00+02:00</updated>
        <id>/blog/2009/10/09/rails-tricks-part-2-mislav-will_paginate</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Rails Tricks, part 2: Mislav&amp;#8217;s Will_Paginate&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;09 Oct 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h2&gt;The industry standard&lt;/h2&gt;
&lt;p&gt;If you ever had a chance to meet &lt;a href=&quot;http://twitter.com/mislav&quot;&gt;Mislav Marohnic&lt;/a&gt; (or see him on a video), for the first few minutes you were probably thinking how &lt;a href=&quot;http://tomash.wfb-pol.org/foty/2009-05-09_euruko2010/mislav-will_parkour.jpg&quot;&gt;this crazy and hyperactive guy&lt;/a&gt; could have written &lt;a href=&quot;http://github.com/mislav/will_paginate&quot;&gt;one of the most popular Rails library&lt;/a&gt;. But after some time with Mislav it becomes obvious that he&amp;#8217;s an insanely smart guy able to create some of the best ruby code I&amp;#8217;ve ever seen.&lt;/p&gt;
&lt;h2&gt;All the pages, linked everywhere&lt;/h2&gt;
&lt;h3&gt;The Problem (&lt;span class=&quot;caps&quot;&gt;AKA&lt;/span&gt; &amp;#8220;design&amp;#8221;)&lt;/h3&gt;
&lt;p&gt;In one project (that&amp;#8217;s not live yet) a designer has shown a pretty original approach to displaying pagination links and client was immediately convinced that&amp;#8217;s the way to go.&lt;/p&gt;
&lt;p&gt;The idea was: we present first and last pages as standard links, but between them &amp;#8212; instead of the standard three-dot &amp;#8212; we put a select with all the pages &amp;#8220;between&amp;#8221;, of course doing a javascript-powered redirect to the chosen page. Like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/2009-10-09/pagination.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;In terms of business requirements, if the page count is equal to or below 10, we show just the links to the pages. If there are more than 10 pages, we put 5 to the left, 5 to the right and all the excess pages are accessed via a select in the middle. The redirect occurs automatically on select. The current page, if it&amp;#8217;s amongst the options in select, is displayed in bold.&lt;/p&gt;
&lt;h3&gt;The Approach&lt;/h3&gt;
&lt;p&gt;From the design it seems we need a constant amount of page links on both &amp;#8220;sides&amp;#8221; of the pagination helper. And (this is an important part of the approach) we need to generate the select &lt;strong&gt;in place of gap&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Dive In&lt;/h3&gt;
&lt;p&gt;That&amp;#8217;s where mislav-will_paginate really shines. It can use custom renderers &amp;#8212; classes (I put them in app/helpers directory) extending WillPaginate::LinkRenderer with a few methods to (re)implement: in this case we&amp;#8217;re going to implement &lt;strong&gt;prepare&lt;/strong&gt; (for assigning our custom gap) and &lt;strong&gt;visible_page_numbers&lt;/strong&gt; (so we always have links on both sides to first and last pages and no links around the gap).&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s make it flexible enough so the number &amp;#8220;5&amp;#8221; (amount of page links to the left and right of select) isn&amp;#8217;t hardcoded, just use well-known outer_window option.&lt;/p&gt;
&lt;p&gt;In our application we had to reimplement also the &lt;strong&gt;to_html&lt;/strong&gt; method to have some additional fancy stuff on the edges, but that&amp;#8217;s not relevant.&lt;/p&gt;
&lt;p&gt;Now I know it&amp;#8217;s not a very preferred way of learning, but let&amp;#8217;s see the code that does the trick:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;FancyRenderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;WillPaginate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LinkRenderer&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;prepare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@gap_marker&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:gap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;visible_page_numbers&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;inner_window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outer_window&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:inner_window&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:outer_window&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_i&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;window_from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inner_window&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;window_to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inner_window&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;# adjust lower or upper limit if other is out of bounds&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window_to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_pages&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;window_from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window_to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_pages&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;window_to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_pages&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window_from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;window_to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window_from&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;window_from&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;window_to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_pages&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window_to&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;total_pages&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;visible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.total_pages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_a&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#start with all of them...&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;left_gap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right_gap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outer_window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;total_pages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outer_window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;visible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left_gap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_a&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left_gap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left_gap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;visible&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right_gap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_a&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right_gap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;last&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right_gap&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;visible&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It&amp;#8217;s pretty obvious from the code (don&amp;#8217;t worry, it took me some time to write it) that mislav-will_paginate rendering uses @gap_marker variable and we need to call will_paginate helper with :gap option. If we don&amp;#8217;t give it&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;will_paginate&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;ss&quot;&gt;:inner_window&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;ss&quot;&gt;:outer_window&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;ss&quot;&gt;:renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;FancyRenderer&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;it looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/2009-10-09/stage_1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So let&amp;#8217;s see if it really displays our custom stuff in place of gap:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;will_paginate&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;ss&quot;&gt;:inner_window&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;ss&quot;&gt;:outer_window&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;ss&quot;&gt;:gap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;hello!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;ss&quot;&gt;:renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;FancyRenderer&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;result:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/2009-10-09/stage_2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s time to write the code that&amp;#8217;ll create the select for remaining &amp;#8220;between&amp;#8221; pages!&lt;/p&gt;
&lt;h3&gt;We&amp;#8217;re not there yet&lt;/h3&gt;
&lt;p&gt;You know what I like most about Rails? That it&amp;#8217;s written in Ruby. And in Ruby you can really do some fancy shit that&amp;#8217;s readable and usable at the same time.&lt;/p&gt;
&lt;p&gt;We&amp;#8217;re going to write a &amp;#8220;gap select&amp;#8221; generator that&amp;#8217;s going to create a required amount of relevant select options with paginated paths as values. But we want to make the code as elasic and reusable as possible (&lt;span class=&quot;caps&quot;&gt;DRY&lt;/span&gt;, motherfucker! Do you follow it?), so calling the given resource path generator within our gap-generating helper is not an option.&lt;/p&gt;
&lt;p&gt;So&amp;#8230; how about something like this, sexy enough?&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;will_paginate&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;ss&quot;&gt;:inner_window&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;ss&quot;&gt;:outer_window&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;ss&quot;&gt;:gap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page_selector_generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stripped_params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;items_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)},&lt;/span&gt; 
    &lt;span class=&quot;ss&quot;&gt;:renderer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;FancyRenderer&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &amp;#8220;stripped_params&amp;#8221; are here of course for the sake of including all the other &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; parameters (see &amp;#8220;links for extra parameters&amp;#8221; section &lt;a href=&quot;/2009/10/04/rails-tricks-part-1-searchlogic.html&quot;&gt;in my post about Searchlogic&lt;/a&gt;), made by cloning params and removing key/value pairs that could interfere with path generator.&lt;/p&gt;
&lt;p&gt;For instance:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;stripped_params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clone&lt;/span&gt; 
  &lt;span class=&quot;n&quot;&gt;stripped_params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;stripped_params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:action&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(You might want to put it in helper.)&lt;/p&gt;
&lt;p&gt;So, we have sexy, &lt;span class=&quot;caps&quot;&gt;DRY&lt;/span&gt; and cool code ready to reuse. Let&amp;#8217;s write the page_selector_generator helper (finally!) to feed it with these stripped_params and path helper block.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ApplicationHelper&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;#accepts a block (one argument: page) with a path-generating helper&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;page_selector_generator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;jump to&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;total_pages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;content_tag&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;page_selector&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;#the second argument is here for giving current page a &amp;quot;selected&amp;quot; attribute&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;options_for_select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And it looks this way:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/2009-10-09/stage_3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So&amp;#8230; &lt;strong&gt;voila&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;(Yeah, I know, the &amp;#8220;5&amp;#8221; left-and-right offset is hardcoded, so I&amp;#8217;ll probably refactor this code soon)&lt;/p&gt;
&lt;h3&gt;Almost there, i.e. proofing the awesome&lt;/h3&gt;
&lt;p&gt;The above code is great with one exception: if you supply some extra parameters, the path in select option&amp;#8217;s value is not generated properly &amp;#8212; the ampersands (&amp;amp;) get escaped and thus the paths from value don&amp;#8217;t yield what would be expected of them.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/images/2009-10-09/stage_4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We have to write our own variant of options_for_select:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ApplicationHelper&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;not_escaped_options_for_select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;selected&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;options_for_select&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;container&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;option_text_and_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;selected_attribute&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39; selected=&amp;quot;selected&amp;quot;&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;option_value_selected?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;selected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;%(&amp;lt;option value=&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;selected_attribute&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;html_escape&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;&amp;lt;/option&amp;gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;options_for_select&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The above code may be ugly (I never really digged html-generating helpers), but it does the trick: the paths are not entity-escaped and we can finally move onto javascript redirects.&lt;/p&gt;
&lt;p&gt;I wanted to end it with &amp;#8220;this remains as an exercise for the reader&amp;#8221;, but I just got reminded how pissed I always was when encountering such crap: it&amp;#8217;s a tech blog article, goddamit. People come here for answers, not for fucking riddles.&lt;/p&gt;
&lt;p&gt;Of course we&amp;#8217;ll write the javascript the unobtrusive way. Here&amp;#8217;s the snippet if you&amp;#8217;re using Prototype:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;page_selector&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;observe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;change&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;http://&amp;#39;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;location&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;page_selector&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I&amp;#8217;ll leave the jQuery version as an exercise for the reader.&lt;/p&gt;
&lt;h2&gt;Searchlogic + Mislav_Will-Paginate = &lt;span class=&quot;caps&quot;&gt;WIN&lt;/span&gt;&lt;/h2&gt;
&lt;h3&gt;Old School&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;If you&amp;#8217;re using Searchlogic 1.6.x&lt;/strong&gt;, you can easily prepare instance variable in a way digestible for will_paginate helper:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;search&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# searchlogic scope preparation &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# remember to also do the pagination, i.e. make use of :page and :per_page parameters&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;models_arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# array of elements for current page&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@models&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;WillPaginate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Collection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;per_page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;models_arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@models&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;total_entries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And you&amp;#8217;re ready to use will_paginage(@models) in your views!&lt;/p&gt;
&lt;h3&gt;Searchlogic 2.x&lt;/h3&gt;
&lt;p&gt;New searchlogic exposes &amp;#8220;all&amp;#8221; method&amp;#8217;s result as named scope (and thus works great in named scope chains), so it&amp;#8217;s even easier to make it work with model methods added by mislav-will_paginate:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;named_scopes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Model&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;whatever&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;named&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scopes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;you&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#named_scope&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;search&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;named_scopes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;vi&quot;&gt;@models&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;paginate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:page&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:per_page&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(thanks to folks, especially gRuby, from &lt;a href=&quot;http://rubyonrails.pl/forum/p13484&quot;&gt;polish RubyOnRails forum&lt;/a&gt;)&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;That&amp;#8217;s all folks, at least for the Part 2 of Rails Tricks series.&lt;/p&gt;
&lt;p&gt;I hope it succeeded in showing that you can do some really fancy stuff with mislav-will_paginate and exploiting the fact we&amp;#8217;re writing Ruby.&lt;/p&gt;
&lt;p&gt;Of course suggestions and comments are welcome (damn I learned a lot from previous&amp;#8217; part comments!).&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Rails Tricks, part 1: Searchlogic</title>
        <link href="/blog/2009/10/04/rails-tricks-part-1-searchlogic/"/>
        <updated>2009-10-04T00:00:00+02:00</updated>
        <id>/blog/2009/10/04/rails-tricks-part-1-searchlogic</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Rails Tricks, part 1: Searchlogic&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;04 Oct 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This is the first post on a series I plan to write about some clever usage of Rails-related tools (gems, plugins or other) that can really enhance programmer&amp;#8217;s and app user&amp;#8217;s experience, make code cleaner, and application neater.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt; In this article&amp;#8217;s code examples I use Searchlogic 1.6 branch. I haven&amp;#8217;t switched to 2.x with its syntax yet, so the code samples would require some re-writing, albeit the general ideas presented in this article remain valid.&lt;/p&gt;
&lt;h2&gt;Why Searchlogic is awesome&lt;/h2&gt;
&lt;p&gt;If you ever had the need to implement some combined searching / filtering / sorting capabilities in your Rails application, chances are you&amp;#8217;ve stumbled upon &lt;a href=&quot;http://www.binarylogic.com/&quot;&gt;Ben Johnson&amp;#8217;s&lt;/a&gt; gem &lt;a href=&quot;http://github.com/binarylogic/searchlogic&quot;&gt;searchlogic&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What Searchlogic does great is not only its neat syntax for easy declaration of things that used to be pain in the ass with ActiveRecord.find conditions (think &amp;#8220;less than X&amp;#8221; and parameter escaping). Searchlogic promotes abstraction of AR.find parameters set as separate entity, a Search Scope &amp;#8212; and enables easy conversions to-fro simple Hash. This way a given Scope can be easily saved (serialized), loaded, copied, modified etc.&lt;/p&gt;
&lt;p&gt;But before we get into that awesomeness, let&amp;#8217;s start by how searchlogic should and should not be used.&lt;/p&gt;
&lt;h2&gt;Search form: you&amp;#8217;re doing it wrong!&lt;/h2&gt;
&lt;p&gt;Searchlogic&amp;#8217;s readme gives an example of simple search/filtering form, submitting parameters that (supposedly) could be fed directly into scope constructor.&lt;/p&gt;
&lt;p&gt;This could work and be a proper usage of searchlogic under one condition: it&amp;#8217;s in admin panel (trusted user with all priviledges) and admin knows exactly how it works and how should the parameters be fed into it.&lt;/p&gt;
&lt;p&gt;But generally it doesn&amp;#8217;t work like users of your site would expect. Empty fields aren&amp;#8217;t omitted in criteria, they evaluate to &amp;#8220;is blank&amp;#8221;-kind of conditions (and that&amp;#8217;s counter-intuitive)*. If prices are stored as integers instead of decimals (a common design decision, see comments), they&amp;#8217;d have to be input that way. &lt;br /&gt;
If there are any associations to be joined, there&amp;#8217;s some tweaking to do. Plus a clever cracker with a tool as simple as firebug could forge extra fields into this form and get records he shouldn&amp;#8217;t be allowed to.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&amp;#8212;I seems to be working as expected in Searchlogic 2.x branch. Well, yet another reason to switch.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The proper way is to manually build a Scope, based on parameters with proper sanitization and conversion before they get passed to the Scope. I usually abstract Scope building to static method of related model and call it from controller&amp;#8217;s private method:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ItemsController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ApplicationController&lt;/span&gt;
  
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;prepare_search&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@items&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;all&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  
  &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;prepare_search&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#searchlogic scopes play well with named scopes!&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@scope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Item&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prepare_search_scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And the Model.prepare_search_scope(params) manually builds Scope by checking on a&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prepare_search_scopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new_search&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conditions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;title_like&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:keyword&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;strip&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:keyword&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:category_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;blank?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conditions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;category_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:category_id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:price_at_least&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conditions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;price_at_least&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:price_at_least&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:price_at_most&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;conditions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;price_at_most&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:price_at_most&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt; 
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_as&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;DESC&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order_by&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:created_at&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Take a look at this method&amp;#8217;s body: it doesn&amp;#8217;t depend on class it&amp;#8217;s used in. It means that if you have a few models where scopes are built in similar way, it&amp;#8217;s a no-brainer to extract this abstraction into module or superclass.&lt;/p&gt;
&lt;h2&gt;Links for extra parameters&lt;/h2&gt;
&lt;p&gt;Usually websites don&amp;#8217;t expose all their searching/filtering capabilities as form. Usually there are some links, especially for changing category, ordering and other hard-to-input stuff. Creating links to the same page (action, controller, etc.) with the same extra parameters with just one (few) added or changed is extremely simple&amp;#8230; just merge these new parameters!&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;link_to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;category 2&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:category_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;It exploits the fact that url_for (used with link_to&amp;#8217;s second parameter) builds path from given hash and &lt;strong&gt;params&lt;/strong&gt; hash is a magic one, containing also the controller, action and other extra stuff that&amp;#8217;s been already input in the address bar.&lt;/p&gt;
&lt;h2&gt;Exploiting Scopes for nice browsing info&lt;/h2&gt;
&lt;p&gt;Many auction sites &amp;#8212; like eBay and polish Allegro &amp;#8212; provide users searching for some stuff with a nice side menu listing categories relevant to search (i.e. containing items that fulfill the search criteria) and amount of items in each of these categories.&lt;/p&gt;
&lt;p&gt;This can be easily achieved using searchlogic by cloning our Scope (preservation of all the manually-built conditions!) and using some &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt;-fu (adding grouping and overwriting &lt;span class=&quot;caps&quot;&gt;SELECT&lt;/span&gt; part of our query to get just the count).&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;categories_scope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clone&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;categories_scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;category_id&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;categories_scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;category_id, count(category_id) AS category_count&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;categories_scope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Of course now we have two Scopes to return, so I personally prefer returning a hash like {:items =&amp;gt; scope, :item_categories =&amp;gt; categories_scope}.&lt;/p&gt;
&lt;p&gt;And yes, of course the above code could use some joins for pulling the relevant categories and thus avoiding N+1 queries problem. Let&amp;#8217;s leave that as an exercise for the reader (as for now, this article needs some tweaking anyway).&lt;/p&gt;
&lt;h2&gt;What more can I do with Scope?&lt;/h2&gt;
&lt;p&gt;Serialize it (like Hash) and store it in database for later use. For instance, notifying user when there&amp;#8217;s some new stuff (just add a created_at condition) fulfilling given criteria defining his interests.&lt;/p&gt;
&lt;h2&gt;That&amp;#8217;s not all, folks&lt;/h2&gt;
&lt;p&gt;Searchlogic (at least 1.6.x branch I&amp;#8217;m using on a daily basis) does also pagination and can play very well with pagination standard in the Rails ecosystem, i.e. &lt;a href=&quot;http://github.com/mislav&quot;&gt;mislav&amp;#8217;s&lt;/a&gt; &lt;a href=&quot;http://github.com/mislav/will_paginate&quot;&gt;will_paginate&lt;/a&gt;. But mislav-will_paginate tricks are going to be a subject of next post in &amp;#8220;Rails Tricks&amp;#8221; series.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Migrating to Rails 2.3 and Globalize2 from Rails 2.1 and Globalize1</title>
        <link href="/blog/2009/06/01/migrating-to-rails-2-3-with-globalize/"/>
        <updated>2009-06-01T00:00:00+02:00</updated>
        <id>/blog/2009/06/01/migrating-to-rails-2-3-with-globalize</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Migrating to Rails 2.3 and Globalize2 from Rails 2.1 and Globalize1&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;01 Jun 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h2&gt;The great migration Exodus&lt;/h2&gt;
&lt;p&gt;Here&amp;#8217;s the deal: my good old pet-project, &lt;a href=&quot;http://bitspudlo.com&quot;&gt;Bitspudlo.com e-store engine&lt;/a&gt; (accidentally I also run this store, but that&amp;#8217;s offtopic) is still running on Rails 2.1 due to Globalize1 being compatible with rails up to this version &amp;#8212; with Globalize for Rails 2.1 being extremely hackish and half-official, &lt;a href=&quot;http://www.globalize-rails.org/&quot;&gt;if you consider Globalize website&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I didn&amp;#8217;t feel well with that. So, since &lt;a href=&quot;http://github.com/joshmh/globalize2&quot;&gt;Globalize2&lt;/a&gt; project started, I&amp;#8217;ve been observing it &lt;a href=&quot;http://www.artweb-design.de/2008/9/19/rails-i18n-revs-up-globalize2-preview-released&quot;&gt;almost since it was announced&lt;/a&gt;. For some time it still didn&amp;#8217;t do the trick for me (despite being written really cleanly and without brutal hacks, thanks to Rails i18n &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; since 2.2), especially in terms of migrating data from Globalize1.&lt;/p&gt;
&lt;p&gt;Last weekend was the day I said &amp;#8220;enough&amp;#8221; after seeing that Globalize2 matured pretty well and being fed up with my pet Rails project not being &amp;#8220;edge&amp;#8221; enough. Seriously, I don&amp;#8217;t feel very well with hackish solutions and Globalize1 sometimes didn&amp;#8217;t work as it should have.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s actually a pretty good &lt;a href=&quot;http://marklunds.com/articles/one/409&quot;&gt;guide on migrating to Rails 2.3 by Peter Marklund&lt;/a&gt;, so that was my starting point. The upside of my migration was that I was starting from 2.1 (alas with code written in the dark ages of 1.2.3 &amp;#8211; 1.2.6), the downside was the huge migration step ahead of me in terms of migrating from Globalize1 to Globalize2.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;So I started with a bang&lt;/strong&gt;: change Rails version in config/environment.rb, remove vendor/plugins/globalize, install &lt;a href=&quot;http://github.com/joshmh/globalize2&quot;&gt;Globalize2 from Github&lt;/a&gt; and get dirty trying to get the app to work (thank git for branching!).&lt;/p&gt;
&lt;h2&gt;Model translations&lt;/h2&gt;
&lt;p&gt;The important things come first: model translations. Globalize1 was designed here in a way that texts in &amp;#8220;default&amp;#8221; language were kept in given model table itself and only translations (deviations) to non-default languages were kept in huge GlobalizeTranslation model with &lt;span class=&quot;caps&quot;&gt;STI&lt;/span&gt; onto ModelTranslation. Now, Globalize2, on the other hand, didn&amp;#8217;t use the original table at all &amp;#8212; all the translatable text fields were kept in model_translations table, regardless of default language. And of course Globalize2 overrided the &lt;strong&gt;field&lt;/strong&gt; and &lt;strong&gt;field=&lt;/strong&gt; methods for translated fields.&lt;/p&gt;
&lt;p&gt;My migrations looked exactly like in Globalize2 readme:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CreateProductTranslationTable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Migration&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;up&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create_translation_table!&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:description&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:text&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;down&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drop_translation_table!&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Fortunately all the data for default language was still available through &lt;strong&gt;attributes&lt;/strong&gt; hash, so this is the migration script I came up with after some fiddling: &lt;a href=&quot;http://gist.github.com/120867&quot;&gt;available as gist on Github&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Feel free to play with this script (hey, it worked for me!), but &lt;strong&gt;remember to backup your data beforehand.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Then I had to sweep through controllers (actually only ApplicationController filters and one action responsible for setting up a different locale) to change from Globalize1 Locale to I18n.locale (and of course using now symbols instead of old string)&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;before_filter&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:set_locale&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set_locale&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;default_locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;pl-PL&amp;#39;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default_locale&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;I18n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_sym&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;(I&amp;#8217;ve ommited the code for autodetecting locale based on browser settings / request header etc.)&lt;/p&gt;
&lt;p&gt;Then I had to run through helpers and logic responsible for displaying prices in different currencies. I&amp;#8217;m not going to paste code here as I feel it&amp;#8217;s pretty hackish and still looking for a way to elegantly refactor it. Fortunately despite its hackishness it was still pretty quickly updated and started to work.&lt;/p&gt;
&lt;h2&gt;Small translations&lt;/h2&gt;
&lt;p&gt;Not much to say here: I got a chance for some pretty nice refactoring of code that (for instance) was sending e-mails with ActionMailer that had titles depending on language. Previously it was extremely fugly, checking for locale in &lt;strong&gt;if&lt;/strong&gt; statement and setting e-mail&amp;#8217;s &lt;strong&gt;@title&lt;/strong&gt; depending on the locale. I made it use new and shiny Rails I18n &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; with some interpolation and that pretty much did the trick. I would fall in love with Rails I18n &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; if I hadn&amp;#8217;t already while working with it at job for client projects.&lt;/p&gt;
&lt;h2&gt;Localizing templates / views&lt;/h2&gt;
&lt;p&gt;Now this got funny.&lt;/p&gt;
&lt;p&gt;Globalize1 had a facility that let developer give the template a .en.html.erb extension and have it rendered for en-language locales with falling back to .html.erb for other locales or when .en. version was not found. Globalize2 focuses on extending Rails I18n &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; and providing nice and clean model translations, but ommited the issue of translating views.&lt;/p&gt;
&lt;p&gt;Theoretically speaking it&amp;#8217;s because Rails actually does exactly that, but with a twist: I was using both en-US and en-GB locales with Globalize1 to switch currencies based on region. And Rails localized-templates solution doesn&amp;#8217;t support fallbacks to generalized locale, so it&amp;#8217;s been looking for .en-US.html.erb template (for instance) and, when not found, falling back to .html.erb completely ignoring .en.html.erb one.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s partially because locale fallbacks are actually something introduced by Globalize2 and Rails doesn&amp;#8217;t know anything about it.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s when I found &lt;a href=&quot;http://github.com/josevalim&quot;&gt;Jose Valim&amp;#8217;s&lt;/a&gt; &lt;a href=&quot;http://github.com/josevalim/localized_templates&quot;&gt;Localized Templates plugin&lt;/a&gt; which proposed a pretty different solution (cleaner one: subdirectories for locales), but still didn&amp;#8217;t have locale fallbacks. Jose turned out to be a very friendly guy and suggested I take a look at his plugin&amp;#8217;s code to modify it, so I did and 15 minutes later I had a &lt;a href=&quot;http://github.com/tomash/localized_templates&quot;&gt;Localized Templates fork using Globalize2 locale fallbacks&lt;/a&gt; that did the trick for me.&lt;/p&gt;
&lt;p&gt;The only thing left was moving the actual localized templates from views/path/template.en.html.erb to views/en/path/template.html.erb, but I wanted to do it anyway to have a good separated file structure.&lt;/p&gt;
&lt;p&gt;If you want to have both fallbacks and the template.locale.html.erb naming scheme, have a look at this plugin: the code is really clean, nice and easy to hack with.&lt;/p&gt;
&lt;h2&gt;Is that all?&lt;/h2&gt;
&lt;p&gt;Some refactoring I did in the meantime (e.g. passing locale in path and relying on session only as fallback) fortunately made all the transition pretty easy anyway. I still have to throw out &lt;a href=&quot;http://activescaffold.com/&quot;&gt;ActiveScaffold&lt;/a&gt; (it doesn&amp;#8217;t play well with Haml as far as I see from backtrace) and replace it with normal, decent &lt;span class=&quot;caps&quot;&gt;CRUD&lt;/span&gt;, but that was something I&amp;#8217;ve been planning nonetheless.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Euruko 2009 reviewed</title>
        <link href="/blog/2009/05/11/euruko-2009-reviewed/"/>
        <updated>2009-05-11T00:00:00+02:00</updated>
        <id>/blog/2009/05/11/euruko-2009-reviewed</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Euruko 2009 reviewed&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;11 May 2009 &amp;#8211; Barcelona / Plane home&lt;/p&gt;
&lt;p&gt;Euruko 2009 in Barcelona has just ended and I&amp;#8217;m going home. It&amp;#8217;s been only a few days, and Euruko 2009 in Barcelona were probably some of my best days this year, but I&amp;#8217;m already starting to miss home. Guess it&amp;#8217;s a good time to summarize and review the last days on the best Ruby conference under the Sun.&lt;/p&gt;
&lt;p&gt;To start with: the initial doubts about spanish Ruby community and how they&amp;#8217;ll cope with organising Euruko turned out to be worthless. The Euruko 2009 team did a great job, hands down. If I had to be on one Ruby-related event this whole year, I wouldn&amp;#8217;t need even 3 seconds to decide.&lt;/p&gt;
&lt;h3&gt;Arrival&lt;/h3&gt;
&lt;p&gt;Together with my girlfriend and my mother (they both always wanted to visit Barcelona) we arrived at the airport on friday evening, having the time and strength only to reach our hotel and go to sleep. It turned out I&amp;#8217;ve booked a room in Campanile Hotel that&amp;#8217;s on the other side of Barcelona to where the Euruko was held &amp;#8212; I heard about Campanile hotel being the hotel of choice for many attendees (and organizers aswell, as most of them were from Madrid), but haven&amp;#8217;t taken into account the possibility of having two Campanile hotels in Barcelona (and of course choosing the &amp;#8220;wrong&amp;#8221; one). Well, unlucky (or: dumb) me. I still had a single fast train from near the hotel to Cornella (near the Euruko venue), so that wasn&amp;#8217;t that of a problem.&lt;/p&gt;
&lt;p&gt;From now on I&amp;#8217;m going to focus on the talks and conference itself. Really, I could probably write a book about all the people I met and all the talks we had during this Euruko, but that&amp;#8217;s not the point.&lt;/p&gt;
&lt;h3&gt;Saturday &amp;#8212; Day One&lt;/h3&gt;
&lt;p&gt;The venue was great, sandwiches in catering were good, weather was wonderful and everyone was in good moods &amp;#8212; it was time to start the Euruko!&lt;/p&gt;
&lt;h4&gt;1) Matz&amp;#8217; Keynote&lt;/h4&gt;
&lt;p&gt;This time Matz gave a review of evolution of computers and their power with software and its complexity, what it meant for programmers and how it related to dynamic languaged like Ruby, Python or Javascript. There were a few funny moments, but I definitely liked Matz&amp;#8217; keynote from the last year more. Fortunately the following Q&amp;amp;A session made attending the keyone really worth it (and Matz is a uber-great guy to talk with, while being our god at the same time).&lt;/p&gt;
&lt;h4&gt;2) Ruby In Systems Testing&lt;/h4&gt;
&lt;p&gt;Great topic, well-thought and prepared presentation, but Stephen wasn&amp;#8217;t at the peak of his performance. Probably that was just an early-speaker stress, as he was cool guy to talk with a few hours later. &amp;#8220;Weight&amp;#8221; of the topic (serious QA and enterprise stuff) and Stephen&amp;#8217;s not-the-best performance marked two talks in a row that were a bit below expectations and some people were actually worried about the following ones.&lt;/p&gt;
&lt;p&gt;That lasted for about 10 minutes, until Javier Ramirez started his&lt;/p&gt;
&lt;h4&gt;3) Having fun with Ruby using Gosu&lt;/h4&gt;
&lt;p&gt;And that was definitely the best talk of the whole Euruko (oops, spoiled the review!). Really, why say anything else? Great from a technical standpoint and Javier is a &lt;strong&gt;simply perfect&lt;/strong&gt; speaker. Just wait for the videos from Euruko to pop up. Half the tweets following this talk were like &amp;#8220;&lt;span class=&quot;caps&quot;&gt;OMG&lt;/span&gt; I&amp;#8217;m so going to hack some game in Gosu &lt;span class=&quot;caps&quot;&gt;ASAP&lt;/span&gt;&amp;#8221; and that speaks for itself.&lt;/p&gt;
&lt;h4&gt;4) Creative Image Manipulation using Ruby&lt;/h4&gt;
&lt;p&gt;I had to take a break, so will have to see this one on the videos.&lt;/p&gt;
&lt;h4&gt;5) Cooking with Chef&lt;/h4&gt;
&lt;p&gt;Good speaker + good topic + good presentation (movie &lt;span class=&quot;caps&quot;&gt;FTW&lt;/span&gt;!) == really good and inspiring talk. Joshua (from 37signals) showed how to use Chef for offloading some chores related to project bootstrapping, deployment and managing installation in general. Will try Chef soon!&lt;/p&gt;
&lt;p&gt;Realizing the possibility of getting audio + video on the talk made me change my talk a bit, to incorporate some new media.&lt;/p&gt;
&lt;h4&gt;6) Software Craftsmanship&lt;/h4&gt;
&lt;p&gt;Didn&amp;#8217;t attent this one &amp;#8212; I was a bit tired and that combined with &amp;#8220;fuck fluff, give me crunch&amp;#8221; attitude made me spend this talk on grass outside, having some great talks. I&amp;#8217;ll gladly watch it on video though.&lt;/p&gt;
&lt;h4&gt;7) Lightning Talks&lt;/h4&gt;
&lt;p&gt;There were a few really worth seeing ones (actually some guys claimed that Lightnings were the best part of Euruko). I really enjoyed Bragi&amp;#8217;s about parsing and evaluation (and Treetop), Dira&amp;#8217;s about vimmish and creating grammars. I actually decided to give one myself about Jekyll, so that my mate Peter could switch to a decent blogging engine, but he didn&amp;#8217;t come to the Lightning Talks finally (you owe me one, man).&lt;/p&gt;
&lt;p&gt;Amongst the things worth highlighting this are definitely lunch at the shopping mall and discussions on the grass outside the building, including Mislav showing some parkour on the venue after being asked about it.&lt;/p&gt;
&lt;p&gt;I missed the saturday party, as the whole excitement tired me (plus it&amp;#8217;d be quite hard to return to my hotel at nigh other way than taxi) and evening with my significant other was a much more tempting perspective.&lt;/p&gt;
&lt;h3&gt;Sunday &amp;#8212; Day Two&lt;/h3&gt;
&lt;p&gt;I missed &amp;#8220;Ruby DataObjects&amp;#8221; talk because of some train confusion (stepped into wrong train, realized that about two stations after forking, rebase took some time and I&amp;#8217;m an hour late) and I miss it. Waiting for the videos!&lt;/p&gt;
&lt;h4&gt;2) Adhearsion&lt;/h4&gt;
&lt;p&gt;That one was funny for me. is a very good speaker and delivered a definitely encouraging talk, but I haven&amp;#8217;t joined the crowd tweeting &amp;#8220;I&amp;#8217;m going to do some Adhearsion&amp;#8221;. Despite project&amp;#8217;s and talk&amp;#8217;s high level, I&amp;#8217;m still put off trying due to my hatred towards calling and answering machines. Paul Klipp wouldn&amp;#8217;t have closed his deals on second call max if he had to do them with some phone-bot ;)&lt;/p&gt;
&lt;h4&gt;3) Crossplatform Mobile Apps in Ruby using Rhodes&lt;/h4&gt;
&lt;p&gt;Wow, this one was so great everyone felt sorry for Adam not having the time to show a live demo of Rhohub, a service his company created to aid developers in development and building of Rhodes applications. Tweeter was getting hot from tweets like &amp;#8220;I have to do some Rhodes app&amp;#8221; during and after this talk. Now if we could only see a live demo&amp;#8230; read further.&lt;/p&gt;
&lt;h4&gt;4) Archaeopteryx&lt;/h4&gt;
&lt;p&gt;I&amp;#8217;m a musical geek, there were some girls in bikini on one slide&amp;#8230; what more can I say? This is a must-hack for me! Oh yeah, and Pablo is a very good speaker. I&amp;#8217;ve been thinking about hacking some midi with Ruby and that was something just for me.&lt;/p&gt;
&lt;h4&gt;5) Quality code with Cucumber by Aslan&lt;/h4&gt;
&lt;p&gt;I really wanted to see Cucumber well-presented, as a fellow developer in Aenima has started using it a few weeks ago and is all hyped (I&amp;#8217;m oldschool, staying with Test::Unit and Shoulda), while I didn&amp;#8217;t have time nor motivation (RuDy!) to investigate. And Aslan delivered. He stretched his talk (to more than 1 hour) and there wasn&amp;#8217;t a simple complaint, it was &lt;strong&gt;that&lt;/strong&gt; good. I&amp;#8217;m definitely going to write Cucumber tests in one of projects to follow.&lt;/p&gt;
&lt;h4&gt;6) my talk on RuDy&lt;/h4&gt;
&lt;p&gt;I think it was better than my last year&amp;#8217;s, from both technical (I think RuDy is a cool project, but hey &amp;#8212; author&amp;#8217;s bias!) and &amp;#8220;speaker&amp;#8221; standpoint (people were laughing sometimes, right?). I&amp;#8217;m not the one to judge, though, so you should check other reviews. If you&amp;#8217;re looking for materials (slides, links, movies even) &lt;a href=&quot;/2009/05/09/rudy-on-euruko-resources-for-talk.html&quot;&gt;they&amp;#8217;re here&lt;/a&gt; .&lt;/p&gt;
&lt;h4&gt;7) Rhodes / Rhohub demo&lt;/h4&gt;
&lt;p&gt;Because there was 1h15m window for my talk (+break) and I&amp;#8217;ve already told the organizers that I&amp;#8217;m going to fit in a 30-minute window (as I was asked to when my talk was accepted), the organizers made a (great!) decision to squeeze in between the Rhodes/Rhohub demo that didn&amp;#8217;t fit with Adam&amp;#8217;s talk on Rhodes. It turned out it was a perfect idea!&lt;/p&gt;
&lt;p&gt;Now, I was so hyped after my RuDy talk that I spent first few minutes in the first row chatting with a programmer from Poland and that interfered with the talk. Accept my apologies, Adam &amp;#8212; I really wasn&amp;#8217;t aware that we were screwing your efforts. After I&amp;#8217;ve realized that we&amp;#8217;re messing up with &amp;#8216;s talk we both shut up and watched the demo &amp;#8212; and damn it was worth it! &amp;quot;I&amp;#8217;m so going to hack some mobile app using Rhodes&amp;quot; was the preminent theme of attendees&amp;#8217; tweets once again.&lt;/p&gt;
&lt;h4&gt;8) Lightning Talks 2&lt;/h4&gt;
&lt;p&gt;Two moment that got my attention: Mislav had a cool topic (Rspactor for automated test creation) but didn&amp;#8217;t fit in the 5-minute window, Paul Klipp showed no slides but managed to give an inspiring talk in less than 3 minutes about selling software and Agile philosophy (wow, he really deserves the AgileActivist title!).&lt;/p&gt;
&lt;h4&gt;Discussion about next year&amp;#8217;s venue.&lt;/h4&gt;
&lt;p&gt;&amp;#8220;There were rumors about Poland/Krakow already being decided as the place for Euruko 2010. These are not true, we are going to decide as the Euruko community. So, are there any other countries/cities besides Poland/Krakow? [silence] Guess not. It&amp;#8217;s Poland then&amp;#8221;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fuck yeah!&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I just hope we&amp;#8217;re going to live up to the expectations (Euruko 2008 and 2009 raised the bar really, really high) and maybe even exceed them. See you people next year in Krakow!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Congratulations once again to Spanish &lt;span class=&quot;caps&quot;&gt;RUG&lt;/span&gt;&lt;/strong&gt; for giving the european Ruby community such a great Euruko. You rock, fellows!&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s all for now, folks. I&amp;#8217;m waiting for the videos.&lt;/p&gt;
&lt;p&gt;For people interested in Ruby beyond what&amp;#8217;s on Github, &lt;a href=&quot;/2009/03/03/rudy-ruby-native-extensions-in-d-programming-language.html&quot;&gt;here&amp;#8217;s how it started&lt;/a&gt;, &lt;a href=&quot;/2009/05/08/rudy-on-euruko-last-thoughts-before-the-takeoff.html&quot;&gt;here are my thoughts about RuDy the day before Euruko&lt;/a&gt; and, of course, &lt;a href=&quot;/2009/05/09/rudy-on-euruko-resources-for-talk.html&quot;&gt;here are the resources from the talk&lt;/a&gt;.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>RuDy on Euruko: resources for talk</title>
        <link href="/blog/2009/05/09/rudy-on-euruko-resources-for-talk/"/>
        <updated>2009-05-09T00:00:00+02:00</updated>
        <id>/blog/2009/05/09/rudy-on-euruko-resources-for-talk</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;RuDy on Euruko: resources for talk&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;09 May 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h3&gt;Perform like a Rock Star, be Metal!&lt;/h3&gt;
&lt;p&gt;The talk itself: &lt;a href=&quot;/files/euruko2009/rudy.odp&quot;&gt;RuDy.odp&lt;/a&gt;, &lt;a href=&quot;/files/euruko2009/rudy.pdf&quot;&gt;RuDy.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://github.com/tomash/rudy/tree/master&quot;&gt;RuDy@github&lt;/a&gt; &amp;#8212; clone and see examples/ directory. The &lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt; has lots and lots of useful info aswell.&lt;/p&gt;
&lt;p&gt;Images of bands courtesy of Google Image Search ;)&lt;/p&gt;
&lt;p&gt;Video fragments come from &lt;a href=&quot;http://www.youtube.com/watch?v=mlbKprH61AE&quot;&gt;Fat Ed&amp;#8217;s Guide to Metal&lt;/a&gt;, a promo video for &lt;a href=&quot;http://www.mtv.co.uk/shows/fur-tv&quot;&gt;Fur TV&lt;/a&gt;.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>RuDy on Euruko: last thoughts before the takeoff</title>
        <link href="/blog/2009/05/08/rudy-on-euruko-last-thoughts-before-the-takeoff/"/>
        <updated>2009-05-08T00:00:00+02:00</updated>
        <id>/blog/2009/05/08/rudy-on-euruko-last-thoughts-before-the-takeoff</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;RuDy on Euruko: last thoughts before the takeoff&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;08 May 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h3&gt;A bit of history&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://github.com/tomash/rudy/commit/d073357f575fd4324323f0182feba984f91e40ca&quot;&gt;Over two months ago&lt;/a&gt; I&amp;#8217;ve put on GitHub repository with first commits for &lt;a href=&quot;http://github.com/tomash/rudy/tree/master&quot;&gt;RuDy&lt;/a&gt;, exactly on the day &lt;a href=&quot;http://github.com/tomash/rudy/commit/7ba235721704a37403615b4dbe049a36f2e34a0f&quot;&gt;when my first very basic Ruby extension written in D worked&lt;/a&gt;. That was a culmination of few previous months gathering some data, emailing with Kirk McDonald (author of &lt;a href=&quot;http://pyd.dsource.org&quot;&gt;PyD&lt;/a&gt;) about challenges to come and features to implement, converting .h files to .d and generally pushing towards this first successful run.&lt;/p&gt;
&lt;p&gt;This first successful (compiling and running) extension was the first milestone of RuDy and a sign that this indeed might work; The day after setting up a github project I&amp;#8217;ve submitted a talk topic on &lt;a href=&quot;http://euruko2009.org&quot;&gt;this year&amp;#8217;s EuRuKo&lt;/a&gt; to tell about and show the RuDy project, and to and advertise it amongst fellow rubyists &amp;#8212; a library without an application using it is a dead library.&lt;/p&gt;
&lt;p&gt;Shortly after the &lt;a href=&quot;/2009/03/03/rudy-ruby-native-extensions-in-d-programming-language.html&quot;&gt;blog post explaining the reasons of starting RuDy&lt;/a&gt; appeared.&lt;/p&gt;
&lt;h3&gt;Head-first&lt;/h3&gt;
&lt;p&gt;Submitting a talk about a pretty innovative and technology-glue project before it was ready to be shown was a kind of stunt I pulled out (partially) for the sake of motivating myself to work on RuDy.&lt;/p&gt;
&lt;p&gt;There were some dangers and possibilites of failing, but Kirk helped me overcome all the obstacles in two ways. First, he did in PyD basically everything (and more) I wanted to do in RuDy, so I knew what was possible anyway and had a lot of working code to look at (and to shamelessly copypaste from). Second, and more important actually, Kirk turned out to be very friendly and helpful guy, ready to help me with problems that were blocking me (mostly due to my small knowledge of D and it&amp;#8217;s nuances) whenever I sent him a desperate e-mail.&lt;/p&gt;
&lt;p&gt;Another obstacle was basically around my studies: this year I&amp;#8217;m supposed to graduate with a Msc. degree from physics and thus &lt;a href=&quot;/physics.html&quot;&gt;my thesis&lt;/a&gt; needed (still needs anyway) a lot of work, not to mention my everyday bill-paying job as Ruby developer. Last two months were pretty busy and what I was afraid of occured: I had only two last weeks when I could really focus on RuDy and prepare it for prime-time and announcement at EuRuKo.&lt;/p&gt;
&lt;h3&gt;Current state&lt;/h3&gt;
&lt;p&gt;But it worked.&lt;/p&gt;
&lt;p&gt;Every single hour of writing D code for RuDy was actually a pleasure and motivator for spending another hours. Everything just worked as expected (there were really a few bugs that made it past compiler &amp;#8212; and they were caught by unit tests) and that was a delightful experience. That was a deja vu &amp;#8212; last time I&amp;#8217;ve been seriously programming in D (simple yet funny physical simulations) made me feel the same. I&amp;#8217;ve been coding furiously for the last two weeks (and the last one was completely crazy in that regard) and even took some days off at work to have more time for RuDy.&lt;/p&gt;
&lt;p&gt;Now I&amp;#8217;m 12 hours before plane from Warsaw takes off and RuDy is nowhere near PyD in terms of features, but complete just enough to show at EuRuKo and inspire fellow developers. Everything I&amp;#8217;ve been working on is fully covered with unit tests, so shall any bug arise, a failing test case will be everything that&amp;#8217;s needed. Test coverage also eases (and lets me postpone) writing a sensible documentation for the whole library, a task left for the times RuDy matures and stabilizes a bit.&lt;/p&gt;
&lt;h3&gt;Future shock&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;m still nervous about showing it on Euruko. I have a lot of confidence in it, but due to time constraints I won&amp;#8217;t be showing &amp;#8220;live&amp;#8221; code compilation and running (OK, maybe I will show Dexter, the test application) and limit myself to code snippets in the talk. Not that I have problems with self esteem, but stumbling upon a runtime failure &amp;#8212; when everything&amp;#8217;s been working and developing so smoothly during the last two weeks &amp;#8212; would probably break me down.&lt;/p&gt;
&lt;p&gt;I also hope it&amp;#8217;s going to attract some enthusiastic developers and I won&amp;#8217;t be the sole developer, tester and user of RuDy. This project is too promising and inspiring (yeah, in my opinion, but a few programmer friends confirmed that) to be left unused and I definitely need someone that would be the end-user of the lib for suggestions about shape and convenience of the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;. I&amp;#8217;ve been shaping RuDy onto library I&amp;#8217;d like to (and I surely will) use myself, but &amp;#8220;parent&amp;#8217;s bias&amp;#8221; is something I want to avoid.&lt;/p&gt;
&lt;p&gt;For sure there&amp;#8217;re going to be questions I can imagine asking after such talk. &amp;#8220;Why bother when there&amp;#8217;s &lt;span class=&quot;caps&quot;&gt;FFI&lt;/span&gt; and inline gem&amp;#8221; &amp;#8212; well, I don&amp;#8217;t personally like how inline and &lt;span class=&quot;caps&quot;&gt;FFI&lt;/span&gt; separate me from the generated code and I haven&amp;#8217;t seen anything bigger than example-apps written using it (I think it may also be pretty hard to do it). I still like how they ease writing small code snippets in C and do the variable to-and-fro conversions. &amp;#8220;What about JRuby, you can&amp;#8217;t link D with that&amp;#8221; &amp;#8212; yes, but D is closer to Java than C and thus it&amp;#8217;d be a lot easier to port code from D to Java (all the class-relation design stays the same). &amp;#8220;What about garbage collectors of D and Ruby, aren&amp;#8217;t they going to conflict with themselves?&amp;#8221; &amp;#8212; that&amp;#8217;s the smartest question I could think about and the honest answer is &amp;#8220;I don&amp;#8217;t know, it needs to be thoroughly tested. Python&amp;#8217;s GC do conflict with D&amp;#8217;s GC and that&amp;#8217;s why PyD has some code to prevent that &amp;#8212; I have some of that code copypasted in RuDy, but commented out until the need arises&amp;#8221;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://github.com/tomash/rudy/tree/master&quot;&gt;RuDy&lt;/a&gt; is a fun project that hopes to become used by Ruby developers feeling frustrated by C (malloc, free, segfault) every time they have to write a native extension. It&amp;#8217;s also my first innovative, full-featured and started Free Software / Open Source project, so enthusiasm won&amp;#8217;t wear off soon. I hope it takes off!&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m taking off in a few hours.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Dear fellow Rubyists: You&#39;re a failure to communicate</title>
        <link href="/blog/2009/05/04/dear-fellow-rubyists-you-re-a-failure-to-communicate/"/>
        <updated>2009-05-04T00:00:00+02:00</updated>
        <id>/blog/2009/05/04/dear-fellow-rubyists-you-re-a-failure-to-communicate</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Dear fellow Rubyists: You&amp;#8217;re a failure to communicate&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;04 May 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h3&gt;Preamble&lt;/h3&gt;
&lt;p&gt;Because of the whole outcome of the situation, here&amp;#8217;s the short abstract of what you can expect: it&amp;#8217;s going to be about recent shitstorm that followed &lt;a href=&quot;http://www.slideshare.net/mattetti/couchdb-perform-like-a-pr0n-star?type=presentation&quot;&gt;Matt&amp;#8217;s &amp;#8216;pr0n star&amp;#8217; talk on GoGaRuCo about CouchDB&lt;/a&gt;. If you&amp;#8217;re tired or offended or otherwise not willing to read about the topic and my bitching about communication standards in Ruby community that&amp;#8217;s to follow, it&amp;#8217;d be best to read something else.&lt;/p&gt;
&lt;h3&gt;The Maturity&lt;/h3&gt;
&lt;p&gt;This is how mature people talk about their differences and discords:&lt;/p&gt;
&lt;ul&gt;
	&lt;li class=&quot;dialogue&quot;&gt;&amp;#8220;Hi, do you have a while to talk about your CouchDB presentation?&amp;#8221;&lt;/li&gt;
	&lt;li&gt;&amp;#8220;Wow, a girl. Sure I do, did you like it?&amp;#8221;&lt;/li&gt;
	&lt;li&gt;&amp;#8220;Actually not quite, I think you pushed the joke too far and too long and I felt disturbed and uncomfortable.&amp;#8221;&lt;/li&gt;
	&lt;li&gt;&amp;#8220;My apologies, I didn&amp;#8217;t quite expect women to show on the conference and my talk with &amp;#8220;pr0n&amp;#8221; in title. I&amp;#8217;ll be more careful next time, maybe it was indeed carried too far. Can I do something for you to make up for the unpleasant talk?&amp;quot;&lt;/li&gt;
	&lt;li&gt;&amp;#8220;Yeah, I have this app on my laptop here trying to use CouchDB for storage. Could you show me how to do it, the PG-rated way?&amp;#8221;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Etc. etc. Well, apparently that could be real only in the times before Teh Interwebz. Spinning the Internet Flame Machine instead of discussing how grown-ups do is a part of bigger phenomenon on how Internet affects the way we communicate, summarized wonderfully by this quote from &lt;a href=&quot;http://en.wikiquote.org/wiki/Californication_(TV_series)&quot;&gt;Californication&lt;/a&gt; :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Just the fact that people seem to be getting dumber and dumber. You know, I mean we have all this amazing technology and yet computers have turned into basically four figure wank machines. (&amp;#8230;) People&amp;#8230; they don&amp;#8217;t write anymore, they blog. Instead of talking, they text (&amp;#8230;)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Apparently geek community should have &amp;#8220;instead of discussing, they flame&amp;#8221; added at the end with a special version for Ruby community s/flame/ghetto-flame. So when two women (&lt;a href=&quot;http://www.ultrasaurus.com/sarahblog/2009/04/gender-and-sex-at-gogaruco/&quot;&gt;1&lt;/a&gt; &lt;a href=&quot;http://www.sarahmei.com/blog/?p=46&quot;&gt;2&lt;/a&gt;) present at GoGaRuCo have worded their discomfort while attending this talk, it was immediately picked up by everyone interested and used to fire one of the biggest flamewars in Ruby/Rails world since &lt;a href=&quot;http://www.zedshaw.com/rants/rails_is_a_ghetto.html&quot;&gt;Zed&amp;#8217;s infamous Ghetto rant&lt;/a&gt;. Where &amp;#8220;everyone interested&amp;#8221; means actually all the attention whores (yeah, I&amp;#8217;m one aswell, as this post proves) willing to jump into any heated ruby/rails related discussion, &lt;a href=&quot;http://www.reddit.com/r/programming/comments/8eg3e/couchdb_perform_like_a_pr0n_star/&quot;&gt;from folks at reddit&lt;/a&gt; to authorities like &lt;span class=&quot;caps&quot;&gt;DHH&lt;/span&gt; himself.&lt;/p&gt;
&lt;p&gt;You see, personally I did like the presentation &amp;#8212; or at least the version of it that made it onto SlideShare (said to be &amp;#8220;lighter&amp;#8221; than the originally shown). &lt;a href=&quot;http://delicious.com/tomash/porn&quot;&gt;I&amp;#8217;m OK with porn&lt;/a&gt; and being a white heterosexual male (and atheist on top of that) there&amp;#8217;re actually not many jokes that could be offending to me. But that&amp;#8217;s just me. I like dirty jokes and making presentation as un-professional as it could get, as long as it has all the necessary crunchy code and technical stuff (I actually don&amp;#8217;t give a fuck about fluff as long as there&amp;#8217;s crunch). That being said, I understand that being a woman surrounded by 200+ men and having a 30+ talk filled with even softcore imagery (great ass in G-string on the first slide, Matt!) and sex references can be disturbing and unnerving.&lt;/p&gt;
&lt;p&gt;You can read great summary of the whole shitstorm, together with really insightful conclusion on &lt;a href=&quot;http://martinfowler.com/bliki/SmutOnRails.html&quot;&gt;Martin Fowler&amp;#8217;s blog&lt;/a&gt; and &lt;strong&gt;that actually sums it all pretty much&lt;/strong&gt;. But there&amp;#8217;s one unsolved thing that no-one pulled out yet.&lt;/p&gt;
&lt;h3&gt;Failure To Communicate&lt;/h3&gt;
&lt;p&gt;I know that Teh Interwebz has its set of rules and actually being a creative part of the Web means being more-or-less an attention whore. That&amp;#8217;s good or at least acceptable. I&amp;#8217;m also aware of the fact that geek community loves flamewars and shit-throwing, reasons of which are perfectly &lt;a href=&quot;http://en.wikipedia.org/wiki/Narcissism_of_small_differences&quot;&gt;summarized by century-old term&lt;/a&gt;, be them about &amp;#8220;the right&amp;#8221; editor, linux distro or single talk about one &lt;a href=&quot;http://gogaruco.com/&quot;&gt;Ruby conference somewhere in San Francisco&lt;/a&gt; most of us wouldn&amp;#8217;t hear about if the flamewar hadn&amp;#8217;t taken place.&lt;/p&gt;
&lt;p&gt;But I hate pulling out the whole &amp;#8220;Ghetto&amp;#8221; metaphor. Actually &lt;a href=&quot;http://www.sarahmei.com/blog/?p=46&quot;&gt;Sarah started on this one&lt;/a&gt; and instead of being politely ignored like a quiet fart amongst polite people (how naive am I to hope for &amp;#8220;politely ignored&amp;#8221; on the Internet?), it gave a bucketful of fuel for the whole flamewar. Even &lt;a href=&quot;http://www.rubyrailways.com/rails-is-still-a-ghetto/&quot;&gt;my mate Peter fell for this&lt;/a&gt; and that&amp;#8217;s when I realized the things have gone too far. It&amp;#8217;s not a way for a good and healthy discussion, it&amp;#8217;s an invitation and encouragement to throw shit at each other.&lt;/p&gt;
&lt;p&gt;And that&amp;#8217;s a failure to communicate.&lt;/p&gt;
&lt;p&gt;One more thing.&lt;/p&gt;
&lt;h3&gt;I am a fucking professional, you cocksucker!&lt;/h3&gt;
&lt;p&gt;What next Zed-coined term are you going to use next? &amp;#8220;Rails community is still bunch of scrawny cocksuckers with carpal tunnel syndrome&amp;#8221;? Yeah, that&amp;#8217;d definitely make your blog post sound like a weighted and professional one. &lt;strong&gt;If you want to talk about professionalism, don&amp;#8217;t &amp;#8220;talk ranty Zed&amp;#8221; about it&lt;/strong&gt; because it&amp;#8217;s simply ridiculous. You don&amp;#8217;t get Borat while giving an etiquette lesson, you don&amp;#8217;t talk South Park to your client, you don&amp;#8217;t dress like &lt;a href=&quot;http://encyclopediadramatica.com/index.php/Pedobear&quot;&gt;Pedobear&lt;/a&gt; for serious discussion about child abuse. &lt;strong&gt;But you use Zed&amp;#8217;s rant language when talking about being professional&lt;/strong&gt;. How fucked is that?&lt;/p&gt;
&lt;p&gt;The saddest thing about that is that Zed&amp;#8217;s rants were supposed to be an act. Instead of being a good laugh at Zed&amp;#8217;s issues with some members of US Rails community, it became a new standard of communication amongst rubyists. It reached the point where Zed himself &lt;a href=&quot;http://zedshaw.com/rants/rails_is_a_ghetto.html&quot;&gt;put off the rant&lt;/a&gt; and probably regrets making it public in the first place. &lt;strong&gt;Sure, go on with that convention&lt;/strong&gt; &amp;#8212; as I stated already, I like dirty language and brutal honesty. &lt;strong&gt;But don&amp;#8217;t talk then about professionalism&lt;/strong&gt;. It&amp;#8217;s unprofessional all the way.&lt;/p&gt;
&lt;p&gt;I know that our heroes, for instance &lt;span class=&quot;caps&quot;&gt;DHH&lt;/span&gt; and Linus Torvalds, like profanity (&lt;a href=&quot;http://www.37signals.com/svn/posts/1214-profanity-works&quot;&gt;stating it openly&lt;/a&gt; or &lt;a href=&quot;http://article.gmane.org/gmane.linux.kernel/706950&quot;&gt;making fun&lt;/a&gt; &lt;a href=&quot;http://lwn.net/Articles/290498/&quot;&gt;of ubuntu names&lt;/a&gt;). But there&amp;#8217;s a difference between &amp;#8220;fuck, that&amp;#8217;s awesome&amp;#8221; or calling the-other-geeks-group &amp;#8220;wanking walruses&amp;#8221; and using Zed-talk when encouraging qualities like professionalism and politeness inside one&amp;#8217;s own community.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s a difference between &amp;#8220;innocently funny&amp;#8221; and &amp;#8220;ridiculously paradoxal&amp;#8221;.&lt;/p&gt;
&lt;h3&gt;I can haz construktiv and polite diskushyn?&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;http://www.imdb.com/title/tt0110912/quotes&quot;&gt;Pretty fuckin&amp;#8217; please with sugar on top.&lt;/a&gt;&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Sadly, PhpBB3 Still Rules</title>
        <link href="/blog/2009/03/29/sadly-phpbb-still-rules/"/>
        <updated>2009-03-29T00:00:00+01:00</updated>
        <id>/blog/2009/03/29/sadly-phpbb-still-rules</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Sadly, PhpBB3 Still Rules&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;29 Mar 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h3&gt;The Setting&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;ve been looking for some decent forum package for &lt;a href=&quot;http://forum.wfb-pol.org&quot;&gt;Border Princes&lt;/a&gt;, the largest Warhammer Fantasy Battle online forum in Poland. It&amp;#8217;s been running on a fork of PhpBB2 called &lt;a href=&quot;http://ptifo.clanmckeen.com&quot;&gt;Categories Hierarchy&lt;/a&gt; for some time now (over two years). For these two, almost three years, it&amp;#8217;s been pretty stable and well-performing. So why bother and not just leave it?&lt;/p&gt;
&lt;h3&gt;The Dilemma&lt;/h3&gt;
&lt;p&gt;In today&amp;#8217;s times of Web2.0, webservices and APIs, &amp;#8220;the cloud&amp;#8221; and other buzzwords, a stand-alone internet forum that cannot communicate with other webapplications is simply not enough and so 2001. I want to build some site(s) that could use PhpBB&amp;#8217;s registration, authorization (the forum has grown a pretty large community) and &amp;#8212; most importantly &amp;#8212; dead-simple information exchange capabilities. While the first two would be pretty easy, the third one bites without any decent webservice.&lt;/p&gt;
&lt;p&gt;Generally speaking, phpBB2 &amp;#8212; even with Ptirhiik&amp;#8217;s decent on work with Categories Hierarchy that have structurized and objectified lots of its spaghetti-code &amp;#8212; sucks balls from a technical standpoint. I&amp;#8217;m not even talking about language (phpbb4, yuck!), it started to embrace such modern and extravagant programming techniques like &lt;span class=&quot;caps&quot;&gt;OOP&lt;/span&gt; only recently. I mean, what the fuck? My own code has seen &lt;span class=&quot;caps&quot;&gt;OOP&lt;/span&gt; since I was 17 (and whenever the language supported it) and that was back in 2001. Authors of phpBB have created the largest and most successful piece of forum software, used by millions of people on a daily basis, and the best they could achieve was structural programming.&lt;/p&gt;
&lt;h3&gt;The Search&lt;/h3&gt;
&lt;p&gt;So I started to look for a successor to PhpBB2+CH, to migrate Border Princes onto a decent and modern forum engine.&lt;/p&gt;
&lt;p&gt;Generally speaking, I was disappointed.&lt;/p&gt;
&lt;p&gt;PunBB &amp;#8212; too small and simple, I need subforums and pretty big authorization capabilities (at least ACL+groups). Invision PB &amp;#8212; paid, not an option (besides being pretty bloated from what I remember from Reaper forums). &lt;span class=&quot;caps&quot;&gt;SMF&lt;/span&gt; &amp;#8212; just not enough (and its usability made a few people actually leave the board what was on phpBB previously). And don&amp;#8217;t even get me started on migration scripts from PhpBB2, let aside PhpBB2+CH (which introduced a lot of changes to database schema).&lt;/p&gt;
&lt;p&gt;It ended up on &lt;a href=&quot;http://phpbb.com&quot;&gt;PhpBB3&lt;/a&gt;. Feature-rich, modern (or that&amp;#8217;s what I thought when making the decision), fast and well-performing. Having a great migration script from not only PhpBB2, but &lt;a href=&quot;http://ptifo.clanmckeen.com/viewtopic.php?t=7802&quot;&gt;also from PhpBB2+CH&lt;/a&gt;, which made the whole migration process a breeze. Running on my small &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; (512 Slice) on &lt;a href=&quot;http://slicehost.com&quot;&gt;SliceHost&lt;/a&gt; (&lt;a href=&quot;/2009/03/04/goodbye-slicehost.html&quot;&gt;I still haven&amp;#8217;t fully switched yet&lt;/a&gt;), it manages to serve 3000+ unique visitors daily (Google Analytics data) without even breaking a sweat (this &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; runs also 3 Rails-powered sites, so it&amp;#8217;s pretty short on &lt;span class=&quot;caps&quot;&gt;RAM&lt;/span&gt;) and visibly snappier than PhpBB2+CH, although it took some MySQL optimization and options tweaking beforehand.&lt;/p&gt;
&lt;h3&gt;The Horror&lt;/h3&gt;
&lt;p&gt;And then, after the forum got up and working, I decided to look at PhpBB3 engine codebase to check it out and maybe do a few modifications and&amp;#8230; yeah, the title pretty much says it all. To put it lightly, the phpbb team managed to reach pretty high in standards of structural programming. Too bad that ~10MB codebase written in structural php with global variables (yeah &amp;#8212; not even a Configuration nor Singleton object) means a crapload of interconnected code. On the good side, the code is pretty readable (as far as structural php code can be), well commented and pretty easy to hack. View part is separared into Smarty-like template files. Still, there are a few things that made me realize I&amp;#8217;ve been living in a beautiful world for the last two years, filled with Ruby, RESTful design, design patterns (not even mentioning &lt;span class=&quot;caps&quot;&gt;OOP&lt;/span&gt;), well-thought APIs, easy-to-add plugins etc. Meanwhile, in the world of forumboards, the best one out there is still PhpBB with lots of flaws:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;(still) &lt;strong&gt;no pretty URLs&lt;/strong&gt;&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;no plugin &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;&lt;/strong&gt; or hooks, still MODs that are all about hacking&lt;/li&gt;
	&lt;li&gt;MODs &lt;strong&gt;aren&amp;#8217;t even in .diff&lt;/strong&gt; (nor any similar) format, just a pack of instructions for human&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;no gravatar&lt;/strong&gt; support, not even through mod&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;no OpenID&lt;/strong&gt; support&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;no webservice&lt;/strong&gt; or any other means of accessing forum data for external apps&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The Excuse&lt;/h3&gt;
&lt;p&gt;I know it&amp;#8217;s easy to bash without doing own. I&amp;#8217;m not going to bash PhpBB3 team, not much than what I wrote above. Writing a forum engine is a pretty big task &amp;#8212; and if it was easy to do such a feature-rich engine with keeping up to the current programming standards, it&amp;#8217;d probably be done already. I know that PhpBB3 team are aware of their code flaws and roadmap for 3.2 includes things like proper &lt;span class=&quot;caps&quot;&gt;MVC&lt;/span&gt; separation (in place of current MC+V), fully OO-code, plugin &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;/hooks, dropping support for php4 and other hope-giving points. So I&amp;#8217;m waiting eagerly. It&amp;#8217;s 2009 already, goddamit! But until you do I have to do something&amp;#8230;&lt;/p&gt;
&lt;h3&gt;The Hacking&lt;/h3&gt;
&lt;p&gt;I need a proper webservice-based access to my forum data, period. I don&amp;#8217;t have time to wait for 3.2, so I did what I was afraid of for the last two years: went back to not only coding php, but actually coding based on someone else&amp;#8217;s php code. I guess getting dirty from time to time won&amp;#8217;t hurt, so what the hell. Here it is: &lt;a href=&quot;http://github.com/tomash/phpbb3_webservices/tree/master&quot;&gt;PhpBB3 Webservices&lt;/a&gt;, my attempt to give some modern touch to PhpBB3. It&amp;#8217;s on github. It doesn&amp;#8217;t require hacking existing PhpBB3 codebase (drop-down in a subdir, has own modified copy of needed phpbb3 files), uses it&amp;#8217;s whole authentication and authorization stack and is generally based on the dead-simple idea of &lt;span class=&quot;caps&quot;&gt;XML&lt;/span&gt;-producing templates.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Programmer is NOT a Poet</title>
        <link href="/blog/2009/03/28/programmer-is-not-a-poet/"/>
        <updated>2009-03-28T00:00:00+01:00</updated>
        <id>/blog/2009/03/28/programmer-is-not-a-poet</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Programmer is &lt;span class=&quot;caps&quot;&gt;NOT&lt;/span&gt; a Poet&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;28 Mar 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;h3&gt;Poetry is Art. Wat?&lt;/h3&gt;
&lt;p&gt;I see a growing tendency in the programmer community to call programming &amp;#8220;an art&amp;#8221;, compare it to poetry (and subsequently programmers to poets and code to poem) etc.. It&amp;#8217;s been even supported by many authorities in programming community, like Dave Thomas, which really makes this notion one big &lt;span class=&quot;caps&quot;&gt;WTF&lt;/span&gt;. &lt;strong&gt;Stop that.&lt;/strong&gt; Despite its obvious masturbatory value (&lt;span class=&quot;caps&quot;&gt;OMG&lt;/span&gt; I&amp;#8217;m a poet), it&amp;#8217;s simply not true. There is one big similarity, but the one just-as-big difference makes this comparison pretty much worthless.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s start with defining two qualities of art. First, the definition of art itself &amp;#8212; or, actually, my own definition (that got me into many arguments actually) for the purpose of this post. Short version: art is &amp;#8220;a craft with a personal twist&amp;#8221;. The long version: art is a craft used in a irreproducible way to express its author by creating something. The &amp;#8220;irreproducible&amp;#8221; part is simply tied with the creative aspect that no computer or other, whatever-skilled human can reproduce, given the same conditions &amp;#8212; because computers are totally non-creative, and humans are actually tied to their own expression and creativity.&lt;/p&gt;
&lt;p&gt;Or because, simply, &lt;strong&gt;there&amp;#8217;s no process in art&lt;/strong&gt;. You can dismantle what we all call &amp;#8220;creating&amp;#8221;, but at some level you finally reach the &amp;#8220;think out something&amp;#8221;, maybe in a loop of &amp;#8220;think out, check, correct or move on&amp;#8221;.&lt;/p&gt;
&lt;p&gt;And yes, that definition &amp;#8212; or understanding &amp;#8212; of art got me into many arguments, because simply defining art as creative expression (with craft thrown is) basically rules out instrumentalists that are called &amp;#8220;artist&amp;#8221; because of simply replaying classical compositions. So yes, using this definition, for an instrumentalist to become an artist would mean writing something new (and pushing the music forward) instead of competing with a &lt;span class=&quot;caps&quot;&gt;MIDI&lt;/span&gt; sequencer.&lt;/p&gt;
&lt;p&gt;The second quality of art is that &lt;strong&gt;while there&amp;#8217;s no defined process&lt;/strong&gt; (as stated above)&lt;strong&gt;, there are also no objective measures of judging a quality of given piece of art&lt;/strong&gt;. It&amp;#8217;s so subjective it&amp;#8217;s actually pointless to judge (maybe only for the sake of recommending finely-crafted art to people with similar taste). You can judge the &amp;#8220;craft&amp;#8221; part, or how well the artist performed from a technical standpoint (that&amp;#8217;s the part computers are capable of doing, like with &lt;span class=&quot;caps&quot;&gt;MIDI&lt;/span&gt; sequencers), but the &amp;#8220;creative&amp;#8221; part will be taken differently by different people. Some people say music is resistant to that, but that&amp;#8217;s not true (given the music satisfies some elementary senses of harmony and rhythm) &amp;#8212; my father wants to leave the car when I put Bury Your Dead latest album and I don&amp;#8217;t want to drive if he&amp;#8217;s going to put his country stuff (and we find a common ground in 70&amp;#8217;s hard rock). And Dali is waaaay better than Picasso.&lt;/p&gt;
&lt;h3&gt;Programming is Engineering (yeah, shocking)&lt;/h3&gt;
&lt;p&gt;Here&amp;#8217;s the surprise. The &lt;strong&gt;no process&lt;/strong&gt; part applies to many fields of science and engineering, where any process &amp;#8212; no matter how well defined &amp;#8212; ends wherever human creativity can (or has to) start on the design level. Architecture? Maths and physics? Any machinery design actually? So, provided you&amp;#8217;re really doing any creative stuff when coding (and you do, unless you&amp;#8217;re a code monkey), there&amp;#8217;s really no difference between your creative programming &lt;strong&gt;lack of process&lt;/strong&gt; and other engineer&amp;#8217;s creative/design phase.&lt;/p&gt;
&lt;p&gt;So why other engineers don&amp;#8217;t call themselves poets?&lt;/p&gt;
&lt;p&gt;The second quality is where we, engineers &amp;#8212; and, specifically, programmers &amp;#8212; are different from artists. Writing software is similar in the first quality &amp;#8212; whatever methodology you apply and put a programmer into, he still at some point reaches the &amp;#8220;think out code&amp;#8221; stage and is on his own. But the second quality, the judge-ability of a given piece of software is actually pretty well defined and measureable, at least to some extent: does the code work as expected and is without bugs. &lt;strong&gt;This is engineering&lt;/strong&gt; &amp;#8212; you create something that actually works in a deterministic, repeatable and measurable way (hey, it&amp;#8217;s even science!). This is not poetry nor art, as their results (i.e. impression) aren&amp;#8217;t repeatable across population and depend on personal taste. Do you like Bury Your Dead? Because I sure do, but I doubt 100% of people reading this post do as well.&lt;/p&gt;
&lt;p&gt;That&amp;#8217;s why you, fellow programmer, are an engineer &amp;#8212; not a poet. If you want to be (what for, to pick up jailbait?), go write some actual poetry. And then claim no-one understands you etc. etc.&lt;/p&gt;
&lt;h3&gt;One Last Myth To Crush&lt;/h3&gt;
&lt;p&gt;I know what you think: Dave Thomas, while comparing programming to writing poetry, used also the example of starting with a blank piece of paper or blank page in a text editor. And then creating something. Like, wow. Tabula rasa, creation from nothing and all the other shit.&lt;/p&gt;
&lt;p&gt;My girlfriend&amp;#8217;s an architect. Guess what she&amp;#8217;s starting with? That&amp;#8217;s right, a blank white sheet of paper. Or blank black workspace in AutoCAD. And she&amp;#8217;s also creating something. But how come she&amp;#8217;s not calling herself a poet?&lt;/p&gt;
&lt;p&gt;Oh, I know. Us, poet-programmers, create some working thing from nothing, while architects create just a design, a set of data for the actual builders to use for building the house.&lt;/p&gt;
&lt;p&gt;BS, yet again. We all just create some sets of instructions in a given domain-specific language. Architects use lines and symbols for their language, we use sets of statemens from programming languages. &lt;strong&gt;Our whole creation is non-existent&lt;/strong&gt; and totally abstract without something that makes a real, working thing out of what we write: bricks and builders for architect&amp;#8217;s project, compiler and computer for programmer&amp;#8217;s code.&lt;/p&gt;
&lt;h3&gt;The End&lt;/h3&gt;
&lt;p&gt;Don&amp;#8217;t worry. You can live without being a poet. You still can pick up chicks at bar, just use some less-cheezy lines than calling yourself a poet (or &amp;#8220;code poet&amp;#8221; &amp;#8212; unless you write in Haiku).&lt;/p&gt;
&lt;p&gt;Just throw away that old dirty scarf.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Ruby Feed Mix</title>
        <link href="/blog/2009/03/13/ruby-feed-mix/"/>
        <updated>2009-03-13T00:00:00+01:00</updated>
        <id>/blog/2009/03/13/ruby-feed-mix</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Ruby Feed Mix&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;13 Mar 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Warning: this post is under development at the moment. Keep coming back until this paragraph disappears.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt; These are, of course, my personal choices and opinions based on personal taste and other subjective criteria. It&amp;#8217;s not supposed to be any sort of attack on any of the blogs.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://rubylearning.com/&quot;&gt;RubyLearning&lt;/a&gt; has just published an impressive &lt;a href=&quot;http://rubylearning.com/blog/2009/03/12/50-ruby-related-blogs-to-read/&quot;&gt;list of 50+ ruby-related blogs&lt;/a&gt; (it&amp;#8217;s 70+ at the moment actually, since people rushed to suggest &amp;#8220;add my blog as well, it has rubies!&amp;#8221;).&lt;/p&gt;
&lt;p&gt;Holy shit. If I was to keep seventy blogs in my &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; Reader, I would spend my whole day switching between the feeds, let alone reading all the new stuff these people post. And since I&amp;#8217;m using iGoogle as my &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; Reader (helps accessing all the stuff while I&amp;#8217;m not using my own laptop), the page with all this stuff would be about 5-pagedown-presses long. Just come on, 70+ blogs / &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; feeds to subscribe? No fraggin&amp;#8217; way.&lt;/p&gt;
&lt;p&gt;I want two things:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;filter out these 70+ blogs: it takes some effort to list them all, it takes a lot of time to filter them out&lt;/li&gt;
	&lt;li&gt;combine all of &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; feeds of these blogs into one fat &amp;#8220;feed-fisting&amp;#8221; &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt;-mixture (because some of the blogs are updated once a month)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first one will come with time and experience and will actually be a no-brainer to execute when I get such a &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt;-mix. And for the second I found a nifty little site &lt;a href=&quot;http://www.rssmix.com/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; Mix&lt;/a&gt; that I&amp;#8217;m going to try out. There&amp;#8217;s no reason to not share the results of such undertaking, right?&lt;/p&gt;
&lt;p&gt;And the results will be shared in the form of feeds links, ready to be pasted straight into a new &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; Mix.&lt;/p&gt;
&lt;p&gt;Before I do it, there&amp;#8217;re definitely some blogs that (for me) don&amp;#8217;t need to be subject to this test, as I read them since a few months now and they &lt;strong&gt;do&lt;/strong&gt; deliver without further proving.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The blogs I can recommend whole-heartedly&lt;/strong&gt; after a few months of regular reading (i.e. I knew them before RubyLearning post):&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
http://feeds2.feedburner.com/codefluency
http://khamsouk.souvanlasy.com/feed/atom.xml
http://feeds.igvita.com/igvita
http://feeds2.feedburner.com/obie
http://feeds2.feedburner.com/petermarklund
http://feeds2.feedburner.com/railscasts
http://rails.co.za/feed/atom.xml
http://feeds2.feedburner.com/Railsonwave-Home
http://feeds2.feedburner.com/RubyInside
http://www.rorsecurity.info/journal/atom.xml
http://feeds2.feedburner.com/RyansScraps
http://zedshaw.com/feed.xml
http://feeds2.feedburner.com/ZenAndTheArtOfRubyProgramming
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;So basically below there are two lists comprising of feeds of all the blogs announced in aforementioned RubyLearning. I&amp;#8217;m going to put them all in my rssmix and remove systematically the ones that don&amp;#8217;t deliver &amp;#8211; be it because of too much fluff posts or simply crappy content.&lt;/p&gt;
&lt;p&gt;In order of appearance on RubyLearning blog post &amp;#8212; ladies and gentlemen, &lt;strong&gt;feeds I like and am subscribed to&lt;/strong&gt;:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;
http://z.about.com/6/g/ruby/b/rss2.xml
http://buddingrubyist.com/feed/
http://feeds2.feedburner.com/SoftiesOnRails
http://www.exampler.com/blog/feed/
http://blog.headius.com/feeds/posts/default
http://www.thechrisoshow.com/feed/atom.xml
http://feeds2.feedburner.com/LoudThinking
http://feeds2.feedburner.com/DrNic
http://feeds2.feedburner.com/Segment7
http://blog.fallingsnow.net/feed/
http://brainspl.at/xml/rss20/feed.xml
http://austinentrepreneur.wordpress.com/feed/
http://feeds2.feedburner.com/rails-envy
http://feedproxy.google.com/buckblog
http://feeds2.feedburner.com/SoylentFoo
http://feeds2.feedburner.com/hasmanythrough
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;And here below I&amp;#8217;m going to drop the ones that were above, but didn&amp;#8217;t like them (and why I did not). &lt;strong&gt;This is a very subjective list &amp;#8211; you may find these blogs great&lt;/strong&gt;, they just didn&amp;#8217;t fit my taste and appetite for a technical, ruby-oriented blog. By the way, if you think I&amp;#8217;m narrow-minded enough to have only ruby-related blogs in my &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt;, go fuck yourself. This blog post is about doing one uber-rss-mix of ruby-related blogs, not about everything I have in my reader.&lt;/p&gt;
&lt;p&gt;In order of appearance on RubyLearning blog post: &lt;strong&gt;feeds that &lt;em&gt;my&lt;/em&gt; reader isn&amp;#8217;t fed with&lt;/strong&gt; (and why):&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;http://feeds.therealadam.com/TheRealAdam (Chomsky is cool, but it was supposed to be Ruby-oriented)&lt;/li&gt;
	&lt;li&gt;http://feeds2.feedburner.com/slash7/rss (ctrl-f &amp;#8220;ruby&amp;#8221; &amp;#8212; &lt;span class=&quot;caps&quot;&gt;WTF&lt;/span&gt;, only one occurence beside sidebar?)&lt;/li&gt;
	&lt;li&gt;http://feeds2.feedburner.com/Chadfowlercom (I&amp;#8217;m reading this one thoroughly now, as I can&amp;#8217;t bear the thought of trashing blog of someone like Chad Fowler &amp;#8212; it just doesn&amp;#8217;t feel right)&lt;/li&gt;
	&lt;li&gt;http://pragdave.blogs.pragprog.com/pragdave/atom.xml (because&amp;#8230; I don&amp;#8217;t know, try it yourself)&lt;/li&gt;
	&lt;li&gt;http://derekneighbors.com/feed/ (Agile is cool, but not ruby enough)&lt;/li&gt;
	&lt;li&gt;http://simplifi.es/home/atom.xml (later, dude &amp;#8211; write some content here)&lt;/li&gt;
	&lt;li&gt;AkitaOnRails (I loved that blog when author wrote in english, I&amp;#8217;ll give it another shot after I learn Portugese)&lt;/li&gt;
	&lt;li&gt;http://feeds2.feedburner.com/nubyonrails (emacs and commercials &amp;#8212; not my favourite)&lt;/li&gt;
	&lt;li&gt;http://feeds2.feedburner.com/wossname (not yet, but I&amp;#8217;ll be reading it from time to time &amp;#8212; has potential)&lt;/li&gt;
	&lt;li&gt;http://feeds2.feedburner.com/iamruinous (fluff)&lt;/li&gt;
	&lt;li&gt;http://feeds2.feedburner.com/JamesOnSoftware (cool blog, empty feed &amp;#8212; dammit!)&lt;/li&gt;
	&lt;li&gt;http://www.fearoffish.co.uk/ (firefox failed to connect)&lt;/li&gt;
	&lt;li&gt;http://feeds2.feedburner.com/jayfields/mjKQ (I have this blog in my feedreader, but not in &amp;#8220;ruby&amp;#8221; tab)&lt;/li&gt;
	&lt;li&gt;http://jicksta.com/feed (cool topics but not my interest; more announcements and fluff than real code)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;I got only to number 32. on the RubyLearning list &amp;#8212; stay tuned for updates.&lt;/h3&gt;
&lt;p&gt;Notes:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;I&amp;#8217;m not even trying company blogs, I prefer people when it comes to writing (honesty and standing behind your statements). Try them on your own risks. Some are pretty cool anyway, so maybe I&amp;#8217;ll put a blog post about them the other day.&lt;/li&gt;
	&lt;li&gt;Zed&amp;#8217;s on the list &amp;#8212; I wasn&amp;#8217;t going to include his blog on the list since he redone his page to a cojones-less version, removed the rants and declared not to write them anymore. But it took a week or two for him to finally write &lt;a href=&quot;http://zedshaw.com/blog/2009-03-02-2.html&quot;&gt;this little gem&lt;/a&gt; that brings back my faith in Zed and his style. I&amp;#8217;m still waiting for the stripper-silhouettes though.&lt;/li&gt;
	&lt;li&gt;Austin of FiveRuns fame stayed on the &amp;#8220;good&amp;#8221; list even despite using Wordpress ;)&lt;/li&gt;
	&lt;li&gt;RailsEnvy stayed on the &amp;#8220;good&amp;#8221; list even despite my dislike for videos and screencasts when it comes to technical content (I have a soft spot for their old Ferret and Rake tutorials)&lt;/li&gt;
	&lt;li&gt;Jamis/Buckblog &amp;#8212; I wonder what he&amp;#8217;s going to write about now, given he left his most notable projects? On the &amp;#8220;good&amp;#8221; list as for now.&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.rubyrailways.com/feed/&quot;&gt;Peter Szinek&amp;#8217;s Blog&lt;/a&gt; wasn&amp;#8217;t even mentioned on the RubyLearning list &amp;#8212; &lt;span class=&quot;caps&quot;&gt;WTF&lt;/span&gt;? It&amp;#8217;s a great blog and fully deserves being noted. Oh, and Peter&amp;#8217;s a great guy too (that alone doesn&amp;#8217;t guarantee landing on the &amp;#8220;good&amp;#8221; list though ;)).&lt;/li&gt;
&lt;/ol&gt;
        </content>
    </entry>
    
    <entry>
        <title>Free the DMD Compiler</title>
        <link href="/blog/2009/03/06/free-the-dmd/"/>
        <updated>2009-03-06T00:00:00+01:00</updated>
        <id>/blog/2009/03/06/free-the-dmd</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Free the &lt;span class=&quot;caps&quot;&gt;DMD&lt;/span&gt; Compiler&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;06 Mar 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;p&gt;If you haven&amp;#8217;t heard this one already, Digital Mars D Compiler (&lt;span class=&quot;caps&quot;&gt;DMD&lt;/span&gt;) by Walter Bright &lt;a href=&quot;http://www.reddit.com/r/programming/comments/82ck4/digitalmars_d_now_open_source/&quot;&gt;has just been released with a full source code&lt;/a&gt;. &lt;strong&gt;That&amp;#8217;s the good news&lt;/strong&gt;, as the closed-source backend of &lt;span class=&quot;caps&quot;&gt;DMD&lt;/span&gt; was pretty much repelling for some of the D programmers out there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The bad news&lt;/strong&gt; is that backend, while being Open Source, is not Free Software. &lt;a href=&quot;http://www.reddit.com/r/programming/comments/82cgp/new_release_of_the_d_programming_language_now/c08227m&quot;&gt;As Walter explained in other thread on Reddit&lt;/a&gt;, some of its bits licensed from Symantec cannot be GPLed as is stated in the license.&lt;/p&gt;
&lt;p&gt;Two things, and their consequences, seriously impair D&amp;#8217;s widespread adoption and attracting a critical mass of developers. They are, namely, &lt;strong&gt;compiler hell&lt;/strong&gt; and &lt;strong&gt;stdlib hell&lt;/strong&gt;, both pretty unique to the language (and thus more dramatic) at the moment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compiler Hell&lt;/strong&gt;. There are three D compilers out there and there&amp;#8217;re issues with each one of them. &lt;span class=&quot;caps&quot;&gt;DMD&lt;/span&gt; is not Free Software (thus is not included in official repositories of Debian and Ubuntu) and &lt;a href=&quot;http://www.digitalmars.com/d/archives/digitalmars/D/Linux_shared_libraries_-_I_m_confused_56913.html&quot; title=&quot;.so&quot;&gt;sucks at creating Linux shared libraries&lt;/a&gt;. &lt;span class=&quot;caps&quot;&gt;GDC&lt;/span&gt;, being free from both aforementioned flaws, &lt;a href=&quot;http://dgcc.sourceforge.net/&quot;&gt;is lagging behind&lt;/a&gt; (version 4.2.4 20080705 (prerelease gdc 0.25 20080312, using dmd 1.024) (Ubuntu 0.25-4.2.4-3.1) on my ubuntu here). And there is the new kid, &lt;a href=&quot;http://www.dsource.org/projects/ldc&quot;&gt;&lt;span class=&quot;caps&quot;&gt;LLVM&lt;/span&gt; D Compiler&lt;/a&gt;, furiously developed by its authors and even &lt;a href=&quot;http://www.incasoftware.de/~kamm/projects/index.php/2009/01/09/ldc-09-released/&quot;&gt;recently announced to be in pretty workable state&lt;/a&gt;, but it&amp;#8217;s still very fresh, untested and requires some development.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Standard Library Hell&lt;/strong&gt; boils down to Phobos vs. Tango, an issue that&amp;#8217;s still (despite some efforts to bridge both libs) a pain in the ass for many D programmers. I&amp;#8217;m not going to elaborate on this one, even despite having a lot to say about the topic (I&amp;#8217;m not in a mood for rants).&lt;/p&gt;
&lt;p&gt;Generally speaking, if you&amp;#8217;re here reading this, you probably already know and dwelled into both hells. So, what&amp;#8217;s the point of this post?&lt;/p&gt;
&lt;p&gt;The point is that, I like &lt;span class=&quot;caps&quot;&gt;DMD&lt;/span&gt; and I&amp;#8217;m full of respect for Walter Bright &amp;#8212; the man knows and has insane amounts of experience about writing compilers, designed this great language he called &amp;#8220;D&amp;#8221; (probably should have called it after a beverage, animal, rare stone or just add another strange character to C) and still has enough modesty to admit that &lt;span class=&quot;caps&quot;&gt;DMD&lt;/span&gt; has flaws and that not his, but the other stdlib&amp;#8217;s (Tango) developers were right when it comes to designing standard library for D. I don&amp;#8217;t want &lt;span class=&quot;caps&quot;&gt;DMD&lt;/span&gt;, probably together with the language the most notable project of man&amp;#8217;s life, to be forgotten or abandoned only because some pieces of code were licensed in a way that impaired its adoption (most ambitious and language-curious programmers are using linux and/or Mac OS X) and prevented code-exchange between D compilers. I think it would even be easier to make &lt;span class=&quot;caps&quot;&gt;DMD&lt;/span&gt; produce working .so files (I need that for RuDy) than to develop the two other compilers to implement (and do it right) all the features of D 2.0 that &lt;span class=&quot;caps&quot;&gt;DMD&lt;/span&gt; already has.&lt;/p&gt;
&lt;p&gt;So, what to do? Simple.&lt;/p&gt;
&lt;h3&gt;Free the &lt;span class=&quot;caps&quot;&gt;DMD&lt;/span&gt; Compiler&lt;/h3&gt;
&lt;p&gt;Let us, D programmers and enthusiasts, do it! How? &amp;#8220;Buy&amp;#8221; the code from Symantec, that is to pay for licensing it in a &lt;span class=&quot;caps&quot;&gt;GPL&lt;/span&gt;-compatible (or, generally, Free Software compatible) way. Generally speaking, it&amp;#8217;s about doing the &lt;a href=&quot;http://en.wikipedia.org/wiki/Blender_(software)#History&quot;&gt;same thing that community did for Blender&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Who&amp;#8217;s in?&lt;/p&gt;
&lt;p&gt;And who knows how much would Symantec charge for relicensing these pieces of backend code?&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Goodbye, SliceHost!</title>
        <link href="/blog/2009/03/04/goodbye-slicehost/"/>
        <updated>2009-03-04T00:00:00+01:00</updated>
        <id>/blog/2009/03/04/goodbye-slicehost</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Goodbye, SliceHost!&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;04 Mar 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;p class=&quot;disclaimer&quot;&gt;Disclaimer: this post has march date, because that was the time I made a decision to move from Slicehost &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; to a dedicated server. But I&amp;#8217;ve finally decided only recently (mid-june), with a decision switch from Kimsufi to &lt;span class=&quot;caps&quot;&gt;OVH&lt;/span&gt;.pl as my new hosting provider. At the time of writing this disclaimer all my services are already moved to the new host. Slicehost is still ubercool though.&lt;/p&gt;
&lt;h3&gt;Dear Slicehost,&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;ve been your client for almost a year now. Throughout these 12 months you&amp;#8217;ve provided me with great hosting service (actually best I&amp;#8217;ve known up to date), with great documentation and tutorials, helpful and smart support and &amp;#8211; what&amp;#8217;s the most important &amp;#8211; steady and reliable hosting I&amp;#8217;ve put a few websites on. I&amp;#8217;ve been recommending you to friends and companies, so I hope your being great to me turned out to be profitable (at least two of them bought a slice after my recommendation).&lt;/p&gt;
&lt;p&gt;You&amp;#8217;ve been rock-stable and thanks to that users of all my sites &amp;#8212; be it clients of &lt;a href=&quot;http://bitspudlo.com&quot;&gt;bitspudlo.com store&lt;/a&gt;, fellow hobbyists from &lt;a href=&quot;http://forum.wfb-pol.org&quot;&gt;Border Princes forum&lt;/a&gt; or fellow rubyists visiting &lt;a href=&quot;http://wrug.eu/&quot;&gt;Warsaw Ruby Users Group site&lt;/a&gt; &amp;#8212; were always delivered. That worked for my business (bitspudlo.com) and personal reputation (other sites), so you probably understand my warm feelings.&lt;/p&gt;
&lt;p&gt;But times change, people change and sites &amp;#8212; it&amp;#8217;s userbases especially &amp;#8212; grow and a small &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; costing 38 bucks a month simply turns out to be not enough, performance-wise. I know I can upgrade to a bigger slice, but that doubles the cost on every step and it&amp;#8217;s not something I&amp;#8217;m ready to dwell into, especially with recent madness on the currency market when it comes to exchange rate of polish zloty and US dollar. There&amp;#8217;s also the matter of transfer limit and disk quota, both pretty low and sometimes even forcing me to pay extra for my sites, and while you tried your best, ping times across half of the globe (Poland, i.e. middle of Europe) cannot go below certain threshold.&lt;/p&gt;
&lt;p&gt;So I&amp;#8217;m moving on. You&amp;#8217;ve been a great hosting, but I&amp;#8217;ve got an option of buying a dedicated server from reliable and reputable company (not AS reputable like you, Slicehost, but close), with machines placed physically in Europe (ping times!) and with all the parameters &lt;a href=&quot;http://www.ovh.pl/produkty/superplan_mini.xml&quot;&gt;one could expect from a dedicated, for not much more than 38$/month you cost me&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll keep on recommending you to others needing a small and reliable &lt;span class=&quot;caps&quot;&gt;VPS&lt;/span&gt; though (especially fellow Rails developers looking for a good hosting for their first Rails/Merb/Sinatra/whatevere project). Goodbye. It&amp;#8217;s been a great time. Good luck, you deserve it.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>Blogging like a hacker using Jekyll</title>
        <link href="/blog/2009/03/04/blogging-like-a-hacker-using-jekyll/"/>
        <updated>2009-03-04T00:00:00+01:00</updated>
        <id>/blog/2009/03/04/blogging-like-a-hacker-using-jekyll</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;Blogging like a hacker using Jekyll&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;04 Mar 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s been a few days since I started this website using Jekyll since the beginning (engine like this was one of the deciding points) and I still cannot get over its awesomeness combined with (or maybe related to) its simplicity. While the idea of generating static html from half-baked partial files using maybe some sort of templating isn&amp;#8217;t new nor original, Jekyll makes it convenient for the site owner while remaining powerful and feature-complete.&lt;/p&gt;
&lt;p&gt;Some of this is related to Jekyll&amp;#8217;s impressive network of forks on GitHub, with which &lt;a href=&quot;http://github.com/mojombo&quot;&gt;mojombo&lt;/a&gt; merges regularly when asked to. I can&amp;#8217;t summarize all these features here, as I don&amp;#8217;t know about all of them yet, but seeing a simple commit log should give the clue.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s one thing that &amp;#8220;mainstream&amp;#8221; (i.e. mojombo&amp;#8217;s) Jekyll still lacks and that is handling well posts&amp;#8217; tags and categories defined in &lt;span class=&quot;caps&quot;&gt;YAML&lt;/span&gt; header instead of post path. I believe somewhere on github there&amp;#8217;s a fork with that fixed and working properly (tagging in static blogging engine &amp;#8211; wow), but I can&amp;#8217;t find it and I&amp;#8217;d also like to stay with vanilla Jekyll.&lt;/p&gt;
&lt;p&gt;But hey, Jekyll is written in Ruby anyway, so maybe I could fix it myself? As if there weren&amp;#8217;t enough forks of this project on github already. Or maybe I could play with Jekyll a bit, adding some completely new features. Or maybe implement some part of it as native extension (&amp;#8220;related posts&amp;#8221; functionality seems to be pretty slow). Or maybe even do it as native extension, but in D, using RuDy?&lt;/p&gt;
&lt;p&gt;Damn, I love opensource and github. Goodnight.&lt;/p&gt;
        </content>
    </entry>
    
    <entry>
        <title>RuDy: Ruby native extensions in D programming language</title>
        <link href="/blog/2009/03/03/rudy-ruby-native-extensions-in-d-programming-language/"/>
        <updated>2009-03-03T00:00:00+01:00</updated>
        <id>/blog/2009/03/03/rudy-ruby-native-extensions-in-d-programming-language</id>
        <author>
					<name>Tomash</name>
					<uri>/</uri>
					<email>tomekrs@o2.pl</email>
				</author>
        <content type="html">
        	
        	&lt;h1&gt;RuDy: Ruby native extensions in D programming language&lt;/h1&gt;
&lt;p class=&quot;meta&quot;&gt;03 Mar 2009 &amp;#8211; Warsaw&lt;/p&gt;
&lt;p&gt;There are two facts about Ruby.&lt;/p&gt;
&lt;p&gt;Well, at least two I want to focus on.&lt;/p&gt;
&lt;p&gt;First: the &amp;#8220;official&amp;#8221; Matz Ruby Interpreter (&lt;span class=&quot;caps&quot;&gt;MRI&lt;/span&gt;) is here to stay and going to remain the mainstream Ruby interpreter. Despite its technical flaws, despite JRuby gaining popularity in some very specific applications (Mike Lee used it pretty creatively with GreaseSpoon in his &amp;#8220;Test By Proxy&amp;#8221; method) and with Rubinius development practically stalled because of recent EngineYard layoffs.&lt;/p&gt;
&lt;p&gt;Second: Ruby 1.9 / 2.0, with all the performance improvements it brings, is (will be) still &amp;#8220;slow&amp;#8221; in &lt;span class=&quot;caps&quot;&gt;CPU&lt;/span&gt;-intensive operations when compared to compiled languages and when performance really matters.&lt;/p&gt;
&lt;p&gt;Arbitrary selection of uncheckable hypotheses (almost axioms) leads to a simple conclusion: &lt;strong&gt;native extensions are here to stay&lt;/strong&gt;, whenever and wherever Ruby&amp;#8217;s performance is simply not enough.&lt;/p&gt;
&lt;p&gt;That would be digestable, except for extensions have to be written in plain old raw C. But I don&amp;#8217;t want to write in C.&lt;/p&gt;
&lt;p&gt;Don&amp;#8217;t get me wrong. I love C for its simplicity (without feature bloat) and being close-to-the-metal, while having some pretty big possibilites. And for all the programs written in it (when you try to say &amp;#8220;Linux&amp;#8221; with a smile and wide &amp;#8220;i&amp;#8221; like in &amp;#8220;Leenux&amp;#8221; it always ends up in a menacing grin). It&amp;#8217;s just that I hate C for its simplicity (feature-poor) and being close-to-the-metal, combined with possiblities of shooting yourself in the foot.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s not as bad as C++. But it&amp;#8217;s still a language I&amp;#8217;d gladly leave behind.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d love to write native extensions in a compiled (to machine code) and fast, yet modern and pro-programmer language. C-family syntax would be a plus because of familiarity and ability to copypaste library-agnostic code (mostly number crunching, pretty common in numerical simulations) with minimal modifications.&lt;/p&gt;
&lt;p&gt;And there is one like that, which I fell in love with after reading some and writing more (whole semester of &amp;#8220;Computer Methods of Simulation&amp;#8221; programming lab). It&amp;#8217;s called &lt;a href=&quot;http://www.digitalmars.com/d&quot;&gt;D Programming Language&lt;/a&gt; and it really deserves more attention that it gets.&lt;/p&gt;
&lt;p&gt;There are many aspects of D I love (and some I don&amp;#8217;t like), most of them outlined in &lt;a href=&quot;http://wrug.eu/2009/1/13/2009-01-meeting-summary&quot;&gt;my talk about D on january &lt;span class=&quot;caps&quot;&gt;WRUG&lt;/span&gt; meeting&lt;/a&gt;. Basically speaking (for needs of this blog post) D, with all its awesomeness and pragmatism, can interface with C code/applications/libraries both ways. So yes, you can &amp;#8211; at least theoretically &amp;#8211; write Ruby native extensions using Ruby&amp;#8217;s C &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;, but in D.&lt;/p&gt;
&lt;p&gt;Although there are a few gotchas.&lt;/p&gt;
&lt;p&gt;Many D and C datatypes are different. Differences can be &amp;#8220;trivial&amp;#8221;, i.e. ones that shoot in the foot only after moving to a different platform, like constant-size numeric types (int in D is always 32 bit, no matter what insane hardware you&amp;#8217;re targetting). They can be because of &amp;#8220;pragmatic&amp;#8221; syntactic sugar (arrays in D are actually structs with integer size and pointer to data. They can be non-trivial, like struct padding (or structs in general), and these ones are fortunately (for the most part) solved by the compiler that passes stuff differently to functions declared as &lt;code&gt;extern (C) int some_func(...)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;These differences pair up with second problem: for interfacing with C functions, D needs to have their declarations. They are usually within .h C header files that D compilers don&amp;#8217;t read &amp;#8211; they want these declarations in .d source files. For small APIs or small subset of &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; functions that you want to use it&amp;#8217;s cool to copypaste these functions into .d file and modify their accepted datatypes slightly (if necessary &amp;#8211; rarely). For bigger APIs this daunting task can be performed using &lt;a href=&quot;http://www.digitalmars.com/d/1.0/htod.html&quot;&gt;htod&lt;/a&gt; (Windows-only, bleargh!) or &lt;a href=&quot;http://www.dsource.org/projects/bcd/&quot;&gt;bcd.gen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And remember about differences in datatypes. Where C function accepts &amp;#8220;a string&amp;#8221;, which in C world means zero-terminated array/pointer of chars, in D you have to pass &lt;code&gt;(d_string ~ \0).ptr&lt;/code&gt;. That&amp;#8217;s fortunately the only really crappy part about C vs D incompatibilities &amp;#8211; rest of them can be circumvented or boiled down to lowest common denominator.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;All these difficulties are still nothing compared to awesomeness (productivity, features, design) of D programming language.&lt;/strong&gt; Believe me not, try it yourself. Hell, it&amp;#8217;s one position below Ruby in &lt;a href=&quot;http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html&quot;&gt;Tiobe Index&lt;/a&gt; (and the language is damn young!).&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s get back to Ruby. So I want to write my native extensions in D. Ruby has a pretty big C &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; which doesn&amp;#8217;t interface with D code out-of-the-box after converting .h to .d with bcd.gen. And getting the Ruby &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; to work in D is just the beginning, as I would also like nicer, D-like (object-oriented, using D&amp;#8217;s metaprogramming and reflection capabilities) &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; for Ruby native extensions. Like Ruby object wrapping (into convenient D classes) or automagic class and method definition, i.e. selected class with its method would be accessible from Ruby after writing single line of code, without &lt;code&gt;rb_define_class&lt;/code&gt; followed by tens of &lt;code&gt;rb_define_method&lt;/code&gt;. And I want my &lt;strong&gt;extconf&lt;/strong&gt; to recognize D extension and prepare proper makefiles, so I can distribute it in a gem to other people who would only see &amp;#8220;building native extensions&amp;#8221; on gem install and not even getting a clue about the thing being written in D.&lt;/p&gt;
&lt;p&gt;It is all possible: D bindings to Ruby &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;, nice D &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; for Ruby extensions, D-aware extconf etc. etc. Hell, &lt;a href=&quot;http://pyd.dsource.org&quot;&gt;pythonists already have that&lt;/a&gt;, so even the hard D part for the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; has been already figured out by someone smart.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d love to have something like &lt;a href=&quot;http://pyd.dsource.org&quot;&gt;PyD&lt;/a&gt;, but for Ruby of course.&lt;/p&gt;
&lt;p&gt;So I started it. And called it &lt;a href=&quot;http://github.com/tomash/rudy/tree/master&quot;&gt;RuDy&lt;/a&gt;, name inspired by &lt;a href=&quot;http://www.digitalmars.com/d/archives/digitalmars/D/Ruby_and_SWIG_58775.html&quot;&gt;a talk between Ray C. Horn and Kirk McDonald&lt;/a&gt; (author of PyD &amp;#8211; the man knows damn lot about D and interfacing with interpreted language). And want to make it something really usable, to let fellow rubyists code even their native extensions in a modern language, so they won&amp;#8217;t have to dwell into cold and unforgiving depths of raw C world, threatened by memory leaks and segfaults.&lt;/p&gt;
&lt;p&gt;As for now it consists only of the &amp;#8220;D bindings to C &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;&amp;#8221; &amp;#8211; and even that of incomplete, but a pretty usable already, set. On the plus side, by &amp;#8220;set&amp;#8221; I mean functions with full test coverage in &lt;em&gt;dexter&lt;/em&gt; application (part of RuDy project &amp;#8211; cover the whole &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; bindings with unit tests), not all the shit bcd.gen threw onto me. So there&amp;#8217;s a pretty big chance that many other functions (I say most should) in this binding work without explicit statements, but it&amp;#8217;s not good enough for me if they&amp;#8217;re not covered with unittests and passing them.&lt;/p&gt;
&lt;p&gt;So, all the fellow Ruby enthusiasts willing to get their hands dirty on some open source code: &lt;strong&gt;RuDy needs you&lt;/strong&gt;! I&amp;#8217;ve developed it into a state of having some (the most important in my opinion) working bindigs to Ruby &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;, and will continue doing that (so you can basically write your extensions in D already), but there&amp;#8217;s a lot of work ahead to make it a great project&lt;/p&gt;
&lt;p&gt;There are developers needed in all three of the fields, all of them pretty much orthogonal (i.e. you can work on your field without looking at others&amp;#8217; development):&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;D bindings to Ruby C &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;&lt;/strong&gt; &amp;#8212; this is basically what I&amp;#8217;ve already started and completed some part of; requires knowledge of some C, willingness to learn D (including differences and similarities of both languages) and basic Ruby (unit tests and basically checking &amp;#8220;if it works&amp;#8221;)&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;D-aware mkmf&lt;/strong&gt; (or other build system) &amp;#8212; requires some Ruby skill (to read and copy/modify mkmf code) and at least basic makefile-fu (to understand extconf code being modified)&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;D object-oriented Ruby &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;&lt;/strong&gt; &amp;#8212; requires willingness to learn (a lot of D, some Python for reading how it&amp;#8217;s done in PyD)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just think about it: an open-source project requiring not very much sophisticated programming skills or knowledge (just the ability and willingness to learn &amp;#8211; but hey, we&amp;#8217;re programmers!), just some work and looking awesome on your resume (Ruby, D, connecting two languages, open source project). In?&lt;/p&gt;
&lt;p&gt;If you want to contact me, do it via one of the contact methods listed on &lt;a href=&quot;/about.html&quot;&gt;about page&lt;/a&gt;.&lt;/p&gt;
        </content>
    </entry>
    
</feed>