<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><description>Kamal Fariz Mahyuddin on Ruby, Rails, Apple and being a Dad</description><title>bitfluent</title><generator>Tumblr (3.0; @bitfluent)</generator><link>http://blog.bitfluent.com/</link><geo:lat>3.121319</geo:lat><geo:long>101.412048</geo:long><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/bitfluent" type="application/rss+xml" /><item><title>On the Beauty of Rubinius' Design (I Wish I Had Rails.new)</title><description>&lt;p&gt;In &lt;a href="http://rubini.us/"&gt;Rubinius&lt;/a&gt;, you can spawn off a brand new complete &lt;a href="http://en.wikipedia.org/wiki/Virtual_machine"&gt;VM&lt;/a&gt; by simply calling &lt;code&gt;Rubinius.new&lt;/code&gt;. It’ll behave exactly as though it was invoked directly from an rbx binary sitting in your &lt;code&gt;$PATH&lt;/code&gt;, complete with STDIN/STDOUT (which you can override). I believe this is one of the basis of how Rubinius’ multi-VM architecture works.&lt;/p&gt;

&lt;p&gt;Anyway, I bring this up because I really, really wish Rails was architected in a similar fashion. I am building a &lt;a href="http://en.wikipedia.org/wiki/Content_management_system"&gt;CMS&lt;/a&gt; on top of Rails and would love to get my hands on a &lt;code&gt;Rails.new&lt;/code&gt; if there ever was one. Here’s why.&lt;/p&gt;

&lt;p&gt;In a CMS setting, very little of what Rails offers out of the box is usable. You don’t have access to Rails routes so from the very beginning, you don’t have Rails automatically invoking the right controller, the right action and rendering the right view. This doesn’t make sense anyway - you don’t expect your CMS users to start writing controller code in your web editor, do you? (Unless you are &lt;a href="http://heroku.com/"&gt;Heroku&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;On a slight tangent, the assumption when writing a CMS is that when you ship, you would have written every conceivable controller and model there is (views don’t fall into this because users are generally familiar with the concept of customizable templates). One strategy to extend your “frozen code base” is via the use of widgets and third-party apps (like Facebook) so that you can create seemingly new pages served by custom controllers.&lt;/p&gt;

&lt;p&gt;So how do you design a CMS? I’ve been prototyping something for the past week and came up for a breather to check out how other people have solved it. I am delightfully surprised to find out that &lt;a href="http://radiantcms.org/"&gt;Radiant&lt;/a&gt; does it very close to what I have. In particular, Radiant has one single controller that accepts all requests (lets ignore the entire admin portion for the time being). Based on the path array (provided by the globbed route), it decides what to do / where to dispatch. It takes care of locating the page that corresponds to the URL (it uses a &lt;code&gt;Page&lt;/code&gt; model), rendering it and returning the result to the user. It is interesting to note that Radiant directly manipulates the &lt;code&gt;request&lt;/code&gt; and &lt;code&gt;response&lt;/code&gt; objects, something that Rails developers almost never had to reach for in a regular app. On the other hand, I am exploring the use of serializing the templates to disk and simply calling &lt;code&gt;render :template&lt;/code&gt; on it.&lt;/p&gt;

&lt;p&gt;Wait a minute. &lt;strong&gt;Holy cow, we just built (a simplified) Rails on top of Rails!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What I’d love to see here instead is a &lt;code&gt;Rails.new&lt;/code&gt; method just like Rubinius. Boom, a full blown MVC at your fingertips. Configure it right and there you have your very own CMS with minimal work. Or maybe there is. Lazyweb?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=lh8Z0y"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=lh8Z0y" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=eDsO2I"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=eDsO2I" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=BNDSTI"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=BNDSTI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/302847972" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/302847972/36867302</link><guid isPermaLink="false">http://blog.bitfluent.com/post/36867302</guid><pubDate>Mon, 02 Jun 2008 17:13:00 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/36867302</feedburner:origLink></item><item><title>An update in a really long while</title><description>&lt;p&gt;Woah, one month with no updates.&lt;/p&gt;

&lt;p&gt;I started contracting for a startup in Seattle, WA since beginning of April and have been neglecting to update stuff. It’s pretty nice here plus I get to access things that people here take for granted like attending &lt;a href="http://www.rubyholic.com/groups/show/1"&gt;Seattle.rb hack nights&lt;/a&gt;, &lt;a href="http://www.pandora.com"&gt;Pandora&lt;/a&gt;, &lt;a href="http://www.hulu.com"&gt;Hulu&lt;/a&gt; and this weekend, &lt;a href="http://barcamp.org/BarCampPortland"&gt;Barcamp Portland&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;See you guys in a bit.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=YabzQ6"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=YabzQ6" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=YdBrjH"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=YdBrjH" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=ncJ3RH"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=ncJ3RH" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/281646580" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/281646580/33455744</link><guid isPermaLink="false">http://blog.bitfluent.com/post/33455744</guid><pubDate>Fri, 02 May 2008 03:53:52 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/33455744</feedburner:origLink></item><item><title>http://dev.rubyonrails.org/ticket/11491</title><description>&lt;a href="http://dev.rubyonrails.org/ticket/11491"&gt;http://dev.rubyonrails.org/ticket/11491&lt;/a&gt;: &lt;p&gt;Finally, &lt;code&gt;render :partial =&gt; some_collection&lt;/code&gt; will pick the right template based on each object in the collection. I can now retire my workaround:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&lt;% some_collection.each do |item| %&gt;
  &lt;%= render :partial =&gt; item %&gt;
&lt;% end %&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Best part is that the &lt;code&gt;partial_counter&lt;/code&gt; is maintained across the different partials.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=JcezqA"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=JcezqA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=4XNg2LF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=4XNg2LF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=pdXMn4F"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=pdXMn4F" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/261718308" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/261718308/30422191</link><guid isPermaLink="false">http://blog.bitfluent.com/post/30422191</guid><pubDate>Tue, 01 Apr 2008 12:03:51 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/30422191</feedburner:origLink></item><item><title>Updating Counter Cache in Migrations</title><description>&lt;p&gt;I’m nearly complete with an app I’ve been working on, so I thought I’d dedicate some time for optimization. One of the first things I did to my models was to add &lt;a href="http://api.rubyonrails.com/classes/ActiveRecord/Associations/ClassMethods.html#M001105"&gt;counter cache&lt;/a&gt;s so that performing counts on my association were fast.&lt;/p&gt;

&lt;p&gt;First try,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class AddCommentCounterCacheOnTopics &lt; ActiveRecord::Migration
  def self.up
    add_column :topics, :comments_count, :integer, :default =&gt; 0
  end

  def self.down
    remove_column :topics, :comments_count
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Very standard. However, it initializes the column to 0, effectively “losing” all my comments (they’re there in the DB, but Rails adds an additional optimization whereby it won’t fetch the association if the counter cache is 0). Looks like I need to update the &lt;code&gt;comments_count&lt;/code&gt; column to whatever it was at the time of migration.&lt;/p&gt;

&lt;p&gt;Second try,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class AddCommentCounterCacheOnTopics &lt; ActiveRecord::Migration
  def self.up
    add_column :topics, :comments_count, :integer, :default =&gt; 0

    Topic.find(:all).each do |t|
      t.comments_count = t.comments.count
      t.save!
    end
  end

  def self.down
    remove_column :topics, :comments_count
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Two things to note: First, I’m using the &lt;code&gt;#count&lt;/code&gt; method in &lt;code&gt;t.comments.count&lt;/code&gt; because calling &lt;code&gt;#size&lt;/code&gt; will use the value in &lt;code&gt;t.comment_count&lt;/code&gt; which is 0. &lt;code&gt;#count&lt;/code&gt; on the other hand will perform a SQL &lt;code&gt;count()&lt;/code&gt;. Second, &lt;strong&gt;this won’t work!&lt;/strong&gt; Why? Because counter cache columns are set to &lt;code&gt;attr_readonly&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To work around this, a little hack. Final result,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class AddCommentCounterCacheOnTopics &lt; ActiveRecord::Migration
  def self.up
    add_column :topics, :comments_count, :integer, :default =&gt; 0

    def Topic.readonly_attributes; nil end # A little evil hack

    Topic.find(:all).each do |t|
      t.comments_count = t.comments.count
      t.save!
    end
  end

  def self.down
    remove_column :topics, :comments_count
  end
end
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=Yl38wI"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=Yl38wI" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=TsDv8nF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=TsDv8nF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=pRWDi8F"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=pRWDi8F" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/260327186" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/260327186/30194408</link><guid isPermaLink="false">http://blog.bitfluent.com/post/30194408</guid><pubDate>Sun, 30 Mar 2008 01:34:00 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/30194408</feedburner:origLink></item><item><title>Excellent panel on scaling customer support. Definitely...</title><description>&lt;object type="application/x-shockwave-flash" data="http://blip.tv/scripts/flash/showplayer.swf?enablejs=true&amp;feedurl=http%3A%2F%2Fgetsatisfaction%2Eblip%2Etv%2Frss&amp;file=http%3A%2F%2Fblip%2Etv%2Frss%2Fflash%2F683327&amp;showplayerpath=http%3A%2F%2Fblip%2Etv%2Fscripts%2Fflash%2Fshowplayer%2Eswf" width="400" height="255" allowfullscreen="true" id="showplayer"&gt;&lt;param name="movie" value="http://blip.tv/scripts/flash/showplayer.swf?enablejs=true&amp;feedurl=http%3A%2F%2Fgetsatisfaction%2Eblip%2Etv%2Frss&amp;file=http%3A%2F%2Fblip%2Etv%2Frss%2Fflash%2F683327&amp;showplayerpath=http%3A%2F%2Fblip%2Etv%2Fscripts%2Fflash%2Fshowplayer%2Eswf" /&gt;&lt;param name="quality" value="best" /&gt;&lt;embed src="http://blip.tv/scripts/flash/showplayer.swf?enablejs=true&amp;feedurl=http%3A%2F%2Fgetsatisfaction%2Eblip%2Etv%2Frss&amp;file=http%3A%2F%2Fblip%2Etv%2Frss%2Fflash%2F683327&amp;showplayerpath=http%3A%2F%2Fblip%2Etv%2Fscripts%2Fflash%2Fshowplayer%2Eswf" quality="best" width="400" height="255" name="showplayer" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br/&gt;&lt;br/&gt;Excellent panel on scaling customer support. Definitely something to take into account whenever you think of launching a new product out there. Are you too caught up in the idea and the development, forgetting the most important ingredient of your success: the users?
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=5zhWQP"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=5zhWQP" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=8nSrd1F"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=8nSrd1F" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=S9HFasF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=S9HFasF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/256832715" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/256832715/29670819</link><guid isPermaLink="false">http://blog.bitfluent.com/post/29670819</guid><pubDate>Mon, 24 Mar 2008 11:56:00 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/29670819</feedburner:origLink></item><item><title>My First Podcast Mention!</title><description>&lt;p&gt;It’s the first time I’ve ever gotten mentioned in a podcast! It’s on &lt;a href="http://railsenvy.com/2008/3/19/rails-envy-podcast-episode-023-03-19-2008"&gt;Episode 023&lt;/a&gt; of the Rails Envy Podcast for my blog post on &lt;a href="http://blog.bitfluent.com/post/28517435"&gt;using the Fire Eagle gem with Rails&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Download the episode and fast forward to 11:24 :)&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=y3mUDK"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=y3mUDK" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=VvHcjfF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=VvHcjfF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=yUMVKyF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=yUMVKyF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/254940240" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/254940240/29384602</link><guid isPermaLink="false">http://blog.bitfluent.com/post/29384602</guid><pubDate>Thu, 20 Mar 2008 22:03:55 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/29384602</feedburner:origLink></item><item><title>Google Gears for Safari Soon?</title><description>&lt;div id="shcp_9030"&gt;&lt;blockquote style="margin-left: 0; padding-left: 1em; border-left: 1em #eee solid; "&gt; &lt;span class="content comments_count_1 withoutphoto"&gt;&lt;span class="text"&gt; &lt;blockquote class="comment_body comment_body1"&gt;Adds support for offline storage for Web applications in SQL databases&lt;a href="http://r6.sharedcopy.com/3ckdhv12#shcp1"&gt; &lt;sup&gt;link »&lt;/sup&gt;&lt;/a&gt;
&lt;/blockquote&gt; &lt;/span&gt;&lt;/span&gt; - from &lt;a href="http://r6.sharedcopy.com/3ckdhv12"&gt;About the Safari 3.1 Update&lt;/a&gt; via &lt;a href="http://sharedcopy.com"&gt;sharedcopy.com&lt;/a&gt;
&lt;/blockquote&gt;&lt;/div&gt;

&lt;p&gt;&lt;style&gt;#shcp_9030 blockquote blockquote { margin-left: 1.5em; font-size: 0.95em; font-style: italic; }; #shcp_9030 .html_gist { display: none; }&lt;/style&gt;&lt;script&gt;  var json_9030 = {   host: 'sharedcopy.com',   width: '376px',   height: '250px',   bgcolor: '#ffffff',   background: '#ffffff url(http://docs.info.apple.com.sharedcopy.com/images/loading.gif) no-repeat center center; ',   src: 'http://docs.info.apple.com.sharedcopy.com/embeds/copy/kamal/6ca363f08816f8b04723229310fc3262/376.250/BBBBBB.ffffff.CC0000/shcp1.html' };&lt;/script&gt;&lt;script src="http://sharedcopy.com/static/embed/script.js"&gt;&lt;/script&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=yxp8Bn"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=yxp8Bn" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=xVljPjF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=xVljPjF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=pF4qBYF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=pF4qBYF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/253674321" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/253674321/29190056</link><guid isPermaLink="false">http://blog.bitfluent.com/post/29190056</guid><pubDate>Tue, 18 Mar 2008 22:40:20 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/29190056</feedburner:origLink></item><item><title>Jaws drop How it recovered from the guy kicking it and later...</title><description>&lt;object width="400" height="336"&gt;&lt;param name="movie" value="http://www.youtube.com/v/W1czBcnX1Ww&amp;ap=%2526fmt%3D18"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/W1czBcnX1Ww&amp;ap=%2526fmt%3D18" type="application/x-shockwave-flash" width="400" height="336" wmode="transparent"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br/&gt;&lt;br/&gt;&lt;em&gt;Jaws drop&lt;/em&gt; How it recovered from the guy kicking it and later slipping on ice was freaking amazing! via &lt;a href="http://www.37signals.com/svn/posts/912-incredible-big-dog-robot-from-boston-dynamics"&gt;SvN&lt;/a&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=Mz1Poc"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=Mz1Poc" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=Voj572F"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=Voj572F" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=QM4iIHF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=QM4iIHF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/253347259" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/253347259/29134793</link><guid isPermaLink="false">http://blog.bitfluent.com/post/29134793</guid><pubDate>Tue, 18 Mar 2008 09:07:49 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/29134793</feedburner:origLink></item><item><title>#ruby-lang</title><description>ddfreyne: Somebody decided that the best way to let all tests pass... is to comment out the tests that fail&lt;br /&gt;&#xD;
ddfreyne: ...&lt;br /&gt;&#xD;
kamal_fariz: i'd go one further and mock rspec's expectation matcher to return true&lt;br /&gt;&#xD;
ddfreyne: heh
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=twD88H"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=twD88H" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=5qQveEF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=5qQveEF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=82z35BF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=82z35BF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/252883193" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/252883193/29066950</link><guid isPermaLink="false">http://blog.bitfluent.com/post/29066950</guid><pubDate>Mon, 17 Mar 2008 17:07:00 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/29066950</feedburner:origLink></item><item><title>via Paragon Adrift</title><description>&lt;object width="400" height="336"&gt;&lt;param name="movie" value="http://www.youtube.com/v/V6eFn45xOCY&amp;ap=%2526fmt%3D18"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/V6eFn45xOCY&amp;ap=%2526fmt%3D18" type="application/x-shockwave-flash" width="400" height="336" wmode="transparent"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br/&gt;&lt;br/&gt;via &lt;a href="http://maraby.org/"&gt;Paragon Adrift&lt;/a&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=M19z3o"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=M19z3o" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=VpqHYIF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=VpqHYIF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=fsOWv6F"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=fsOWv6F" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/251156493" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/251156493/28805926</link><guid isPermaLink="false">http://blog.bitfluent.com/post/28805926</guid><pubDate>Fri, 14 Mar 2008 11:29:57 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/28805926</feedburner:origLink></item><item><title>Interfacing a Rails App to Fire Eagle Pt 1: Exploration via IRB</title><description>&lt;p&gt;Here are my notes as I explore interfacing a Rails app to &lt;a href="http://fireeagle.yahoo.net"&gt;Fire Eagle&lt;/a&gt;. Tokens have been masked to protect the innocent :)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a &lt;a href="https://fireeagle.yahoo.net/developer/create"&gt;new application&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get the fireeagle gem.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;MacBook-Pro:src kamal$ git clone git://github.com/kamal/fireeagle.git fireeagle
Initialized empty Git repository in /Users/kamal/src/fireeagle/.git/
remote: Generating pack...
remote: Done counting 377 objects.
remote: Deltifying 377 objects...
remote:  100% (377/377) done
remote: Total 377 (delta 192), reused 0 (delta 0)
Receiving objects: 100% (377/377), 75.91 KiB | 9 KiB/s, done.
Resolving deltas: 100% (192/192), done.
MacBook-Pro:src kamal$ cd fireeagle
MacBook-Pro:fireeagle(master) kamal$ rake install_gem
(in /Users/kamal/src/fireeagle)
sudo gem install --local pkg/*.gem
Successfully installed fireeagle-0.6.1
1 gem installed
Installing ri documentation for fireeagle-0.6.1...
Installing RDoc documentation for fireeagle-0.6.1...
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fire up irb and instantiate a client with the Consumer Key and Secret provided by Step 1.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;MacBook-Pro:~ kamal$ irb
&gt;&gt; require 'fireeagle'
=&gt; true
&gt;&gt; client = FireEagle::Client.new(
  :consumer_key    =&gt; 'AAAAAAAAAAAA',
  :consumer_secret =&gt; 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB')
=&gt; #&lt;FireEagle::Client:0x1bef504 ...&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generate a Request Token and associate it with the user because we’ll need to locate who authenticated our app.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&gt;&gt; client.get_request_token
=&gt; #&lt;OAuth::Token:0x1bddb24 @secret="emfPurZAbYlRqNL7fSxhXOkxCJRZ2T1r", @token="mGxmGcGPNyjr"&gt;
&gt;&gt; current_user.update_attributes!(
  :request_token        =&gt; client.request_token.token,
  :request_token_secret =&gt; client.request_token.secret)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Redirect the user to the &lt;a href="https://fireeagle.yahoo.net/oauth/authorize?oauth_token=mGxmGcGPNyjr"&gt;Authorization URL&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&gt;&gt; client.authorization_url
=&gt; "https://fireeagle.yahoo.net/oauth/authorize?oauth_token=mGxmGcGPNyjr"
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After the user grants us permission, Fire Eagle will redirect the user’s browser to our Callback URL (defined in Step 1) with the same &lt;code&gt;oauth_token&lt;/code&gt; params.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&lt;a href="http://yourapp.example.com/your_call_back_path?oauth_token=mGxmGcGPNyjr"&gt;http://yourapp.example.com/your_call_back_path?oauth_token=mGxmGcGPNyjr&lt;/a&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Find the User by the &lt;code&gt;oauth_token&lt;/code&gt; and instantiate a new client (&lt;code&gt;client2&lt;/code&gt; in our IRB session) with the request token and secret.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&gt;&gt; user = User.find_by_request_token(params[:oauth_token])
&gt;&gt; client2 = FireEagle::Client.new(
  :consumer_key         =&gt; 'AAAAAAAAAAAA',
  :consumer_secret      =&gt; 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB',
  :request_token        =&gt; user.request_token,
  :request_token_secret =&gt; user.request_token_secret)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Convert the Request Token to a long-lived Access Token and save it. Optionally, you can nil out the Request Token because you are not going to need them anymore.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&gt;&gt; client2.convert_to_access_token
=&gt; #&lt;OAuth::Token:0x23c4824 @token="CCCCCCCCCCCC", @secret="DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"&gt;
&gt;&gt; user.update_attributes!(
  :access_token         =&gt; client2.access_token.token,
  :access_token_secret  =&gt; client2.access_token.secret
  :request_token        =&gt; nil
  :request_token_secret =&gt; nil)
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Go to town!&lt;/strong&gt; From here on out, you can directly instantiate a client using the user’s Access Token to read or update their location.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&gt;&gt; client3 = FireEagle::Client.new(
  :consumer_key        =&gt; 'AAAAAAAAAAAA',
  :consumer_secret     =&gt; 'BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB',
  :access_token        =&gt; user.access_token,
  :access_token_secret =&gt; user.access_token_secret)
&gt;&gt; client3.update(:q =&gt; 'petaling jaya')
=&gt; #&lt;FireEagle::Response:0x2549a8c ...&gt;
&gt;&gt; client.user.best_guess.name
=&gt; "Petaling Jaya, Malaysia"
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A lot of the stuff above can be extracted into a Rails plugin. First dibs on &lt;code&gt;acts_as_hatchling&lt;/code&gt;!&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=kvRggY"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=kvRggY" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=onm98qF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=onm98qF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=FXnpSIF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=FXnpSIF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/249294262" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/249294262/28517435</link><guid isPermaLink="false">http://blog.bitfluent.com/post/28517435</guid><pubDate>Tue, 11 Mar 2008 12:57:29 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/28517435</feedburner:origLink></item><item><title>"Flying is simply hours of boredom punctuated by moments of stark terror"</title><description>“Flying is simply hours of boredom punctuated by moments of stark terror”&lt;br/&gt;&lt;br/&gt; - &lt;em&gt;&lt;a href="http://www.916-starfighter.de/SR-71_Waever.htm"&gt;916 Starfighter&lt;/a&gt; - Amazingly detailed recollection of a test flight gone bad&lt;/em&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=DQRSxd"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=DQRSxd" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=D3THI5F"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=D3THI5F" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=58ByJbF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=58ByJbF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/249221740" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/249221740/28504767</link><guid isPermaLink="false">http://blog.bitfluent.com/post/28504767</guid><pubDate>Tue, 11 Mar 2008 09:38:13 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/28504767</feedburner:origLink></item><item><title>On Providing Alternate Labels to ActiveRecord Attributes</title><description>&lt;p&gt;I cooked up a simple enhancement to &lt;code&gt;ActiveRecord::Errors#full_messages&lt;/code&gt; to allow me to pass a mapping of attribute to label. Here’s the snippet:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;module ActiveRecord
  class Errors
    def full_messages_with_attr_mapping(mappings)
      mappings.symbolize_keys!
      full_messages = []

      @errors.each_key do |attr|
        @errors[attr].each do |msg|
          next if msg.nil?

          if attr == "base"
            full_messages &lt;&lt; msg
          else
            full_messages &lt;&lt; (mappings[attr.to_sym] || @base.class.human_attribute_name(attr)) + " " + msg
          end
        end
      end
      full_messages
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://pastie.org/163203"&gt;Pastie Link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me walk through the scenario where I found this snippet useful.&lt;/p&gt;

&lt;p&gt;Suppose I had a &lt;code&gt;User&lt;/code&gt; model with the field &lt;code&gt;ic&lt;/code&gt; to store the &lt;a href="http://en.wikipedia.org/wiki/MyKad"&gt;Malaysian National Registration Identification Card&lt;/a&gt; number. If I hit validation errors, I’ll get an ugly error message when I use &lt;code&gt;@user.errors.full_messages.each { ... }&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Ic is not valid.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With the snippet above, I’ll call it with &lt;code&gt;@user.errors.full_messages_with_attr_mapping(:ic =&gt; 'I/C Number').each { ... }&lt;/code&gt; and get&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;I/C Number is not valid.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Much nicer.&lt;/p&gt;

&lt;p&gt;However, I don’t like this solution much because I can’t &lt;code&gt;alias_method_chain&lt;/code&gt; this to &lt;code&gt;full_messages&lt;/code&gt; (because of the explicit mapping params). The downside of this is &lt;code&gt;@user.errors.each_full { ... }&lt;/code&gt; will not do what I want as it uses &lt;code&gt;full_messages&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ideally, I want something that looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class User &lt; ActiveRecord::Base
  attr_label :ic =&gt; 'I/C Number', :hp =&gt; 'H/P Number'
  validates_mykad_of :ic
  ...
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or, we can add a new key to specify the preferred label, much like how &lt;code&gt;validates_*&lt;/code&gt; lets you override the error message.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class User &lt; ActiveRecord::Base
  validates_mykad_of :ic, :message =&gt; 'is not valid', :label =&gt; 'I/C Number'
  ...
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or something like that.&lt;/p&gt;

&lt;p&gt;I prefer Option 1 as it opens up more than just validation error messages. Other places it’ll be useful is in forms&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&lt;% form_for :user do |f| %&gt;
  &lt;%= f.label :ic %&gt;
&lt;% end %&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Is there a better way? Are there plugins that allow one to do this already?&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=fomuG3"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=fomuG3" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=nfDmhfF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=nfDmhfF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=HE16hgF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=HE16hgF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/247797432" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/247797432/28274635</link><guid isPermaLink="false">http://blog.bitfluent.com/post/28274635</guid><pubDate>Sat, 08 Mar 2008 15:20:13 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/28274635</feedburner:origLink></item><item><title>Subtraction: I Wants These Fonts</title><description>&lt;a href="http://www.subtraction.com/archives/2008/0201_i_wants_thes.php"&gt;Subtraction: I Wants These Fonts&lt;/a&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=GhHA40"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=GhHA40" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=gkgS0fF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=gkgS0fF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=iWelUSF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=iWelUSF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/247278292" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/247278292/28194031</link><guid isPermaLink="false">http://blog.bitfluent.com/post/28194031</guid><pubDate>Fri, 07 Mar 2008 17:21:13 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/28194031</feedburner:origLink></item><item><title>Git Utilities You Can't Live Without</title><description>&lt;p&gt;I found some new git toys to add to my toolbox. Let me share them with you:&lt;/p&gt;

&lt;h2&gt;1. git-completion.bash&lt;/h2&gt;

&lt;p&gt;The &lt;a href="http://kernel.org/pub/software/scm/git/git-1.5.4.3.tar.bz2"&gt;git tarball&lt;/a&gt; contains a sweet &lt;a href="http://www.caliban.org/bash/#completion"&gt;bash completion&lt;/a&gt; routine for git. Stick a copy from &lt;code&gt;git-1.5.4.3/contrib/completion/git-completion.bash&lt;/code&gt; to &lt;code&gt;/opt/local/etc/bash_completion.d/git-completion&lt;/code&gt; and tab away!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DEMO&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;MacBook-Pro:webrat kamal$ git &lt;tab&gt;&lt;tab&gt;
add                 cherry              diff                instaweb            rebase              show-ref
am                  cherry-pick         fast-export         log                 relink              st
annotate            ci                  fetch               lost-found          remote              stash
apply               citool              filter-branch       ls-files            repack              status
archive             clean               format-patch        ls-remote           request-pull        submodule
bisect              clone               fsck                ls-tree             reset               svnimport
blame               co                  gc                  merge               revert              tag
br                  commit              get-tar-commit-id   mergetool           rm                  up
branch              config              grep                mv                  send-email          var
bundle              convert-objects     gui                 name-rev            shortlog            verify-pack
checkout            count-objects       imap-send           pull                show                whatchanged
checkout-index      describe            init                push                show-branch
MacBook-Pro:webrat kamal$ git br&lt;tab&gt;
br       branch
MacBook-Pro:webrat kamal$ git branch &lt;tab&gt;&lt;tab&gt;
HEAD            master          onchange        origin/HEAD     origin/master
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://pastie.org/161597.txt"&gt;Pastie link&lt;/a&gt; if you can’t see it in full.&lt;/p&gt;

&lt;p&gt;I like that last bit the most. It found my available branches. It can do a whole lot more. From the inline README:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- local and remote branch names
- local and remote tag names
- .git/remotes file names
- git 'subcommands'
- tree paths within 'ref:path/to/file' expressions
- common --long-options
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;2. Git-aware PS1&lt;/h2&gt;

&lt;p&gt;Once you have the git-completion file, you can set your PS1 to display the current branch you are in.&lt;/p&gt;

&lt;p&gt;For stock-looking Leopard PS1, stick this in your &lt;code&gt;~/.bash_profile&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PS1='\h:\W$(__git_ps1 "(%s)") \u\$ '
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;DEMO&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;MacBook-Pro:src kamal$ cd webrat/
MacBook-Pro:webrat(master) kamal$ git co onchange
Switched to branch "onchange"
MacBook-Pro:webrat(onchange) kamal$
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It’ll only display the branch if it senses you are in a git repo. &lt;strong&gt;Freaking sweet or what??&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;3. git.rake&lt;/h2&gt;

&lt;p&gt;I &lt;a href="http://pastie.org/161606"&gt;stole this Rake task&lt;/a&gt; from the &lt;a href="http://rubini.us/"&gt;Rubinius&lt;/a&gt; project. Stick it in your &lt;code&gt;lib/tasks&lt;/code&gt; directory. Rake now has new git powers.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;MacBook-Pro:webrat(master) kamal$ rake -T git
(in /Users/kamal/src/webrat)
rake git:push    # Push all changes to the repository
rake git:status  # Show the current status of the checkout
rake git:topic   # Create a new topic branch
rake git:update  # Pull new commits from the repository
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now everytime you want to work on something, create a git topic branch by issuing &lt;code&gt;rake git:topic&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;MacBook-Pro:webrat(master) kamal$ rake git:topic
(in /Users/kamal/src/webrat)
Topic name (default quick): feature_x
git checkout -b feature_x
Switched to a new branch "feature_x"
MacBook-Pro:webrat(feature_x) kamal$
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Edit, edit, edit. Commit. Time to push upstream with &lt;code&gt;rake git:push&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;MacBook-Pro:webrat(feature_x) kamal$ rake git:push
(in /Users/kamal/src/webrat)
Switched to branch "master"
* Switching back to master...
* Pulling in new commits...
git fetch
git rebase origin
Current branch master is up to date.
* Porting changes into feature_x...
Switched to branch "feature_x"
git rebase master
Current branch feature_x is up to date.
* Merging topic 'feature_x' back into master...
Switched to branch "master"
git merge feature_x
Updating e25c574..0eb83d5
Fast forward
 doc/README_FOR_APP |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
* Pushing changes...
git push
Counting objects: 7, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 414 bytes, done.
Total 4 (delta 1), reused 0 (delta 0)
refs/heads/master: e25c57 -&gt; 0eb83d
To git@github.com:kamal/webrat.git
   e25c574..0eb83d5  master -&gt; master
* Switching back to feature_x...
Switched to branch "feature_x"
MacBook-Pro:webrat(feature_x) kamal$
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Dude, &lt;em&gt;seriously.&lt;/em&gt; All that switching around, fetching, rebasing, merging? I bet only Linus Torvalds remembers the whole sequence off the top of his head.&lt;/p&gt;

&lt;p&gt;Hope you enjoyed that. Also, I’ve got &lt;a href="http://github.com/"&gt;5 GitHub invites&lt;/a&gt; if anyone wants ‘em.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=68KVUD"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=68KVUD" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=IQW4pxF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=IQW4pxF" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=fhmb7WF"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=fhmb7WF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/245890817" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/245890817/27983389</link><guid isPermaLink="false">http://blog.bitfluent.com/post/27983389</guid><pubDate>Wed, 05 Mar 2008 11:59:00 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/27983389</feedburner:origLink></item><item><title>Agile Disciple  There's a Tarantula in my Story!</title><description>&lt;a href="http://agiledisciple.com/2008/2/27/there-s-a-tarantula-in-my-story"&gt;Agile Disciple  There's a Tarantula in my Story!&lt;/a&gt;: I’m adding this plugin and story stat!
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=5Zt8Ru"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=5Zt8Ru" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=rfJXpZE"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=rfJXpZE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=sFNQZgE"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=sFNQZgE" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/242467525" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/242467525/27477362</link><guid isPermaLink="false">http://blog.bitfluent.com/post/27477362</guid><pubDate>Thu, 28 Feb 2008 10:52:11 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/27477362</feedburner:origLink></item><item><title>Resurrecting MissingDrawer plugin for TextMate Cool to see the...</title><description>&lt;img src="http://media.tumblr.com/zQnRMn6Hf5vc8jttdLQLes4e_500.png"/&gt;&lt;br/&gt;&lt;br/&gt;&lt;a href="http://jannisleidel.com/2008/02/missingdrawer/"&gt;Resurrecting MissingDrawer plugin for TextMate&lt;/a&gt; Cool to see the TextMate plugin I’ve been using has been updated.
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=iLfP9V"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=iLfP9V" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=fY02GQE"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=fY02GQE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=llQpCPE"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=llQpCPE" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/241217440" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/241217440/27282498</link><guid isPermaLink="false">http://blog.bitfluent.com/post/27282498</guid><pubDate>Tue, 26 Feb 2008 09:41:58 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/27282498</feedburner:origLink></item><item><title>"I think Ruby is pretty particularly cool. But no, not really - we’re not doing rocket science,..."</title><description>“I think Ruby is pretty particularly cool. But no, not really - we’re not doing rocket science, we’re just trying to get people laid.”&lt;br/&gt;&lt;br/&gt; - &lt;em&gt;Siqi Chen, &lt;a href="http://highscalability.com/friends-sale-architecture-300-million-page-view-month-facebook-ror-app"&gt;Friends for Sale Architecture - A 300 Million Page View/Month Facebook RoR App&lt;/a&gt;&lt;/em&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=ntgurX"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=ntgurX" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=4n7pUbE"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=4n7pUbE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=Y7N8p7E"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=Y7N8p7E" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/238658662" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/238658662/26885088</link><guid isPermaLink="false">http://blog.bitfluent.com/post/26885088</guid><pubDate>Thu, 21 Feb 2008 16:00:00 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/26885088</feedburner:origLink></item><item><title>Malaysia.rb February 2008 Meetup</title><description>&lt;p&gt;Ruby Implementation Night is the theme of the &lt;a href="http://groups.google.com/group/malaysia-rb"&gt;Malaysia.rb&lt;/a&gt; February 2008 Meetup. There will be talks on &lt;a href="http://rubini.us"&gt;Rubinius&lt;/a&gt;, &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt;, &lt;a href="http://eigenclass.org/hiki.rb?Changes+in+Ruby+1.9"&gt;Ruby 1.9&lt;/a&gt; and smatterings of other stuff.&lt;/p&gt;

&lt;p&gt;Also, &lt;strong&gt;FREE&lt;/strong&gt; &lt;a href="http://www.peepcode.com"&gt;PeepCode&lt;/a&gt; T-Shirts and Episode Coupons giveaway!&lt;/p&gt;

&lt;h3&gt;When:&lt;/h3&gt;

&lt;p&gt;Thursday, February 21st 2008, 7:30PM&lt;/p&gt;

&lt;h3&gt;Agenda:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;7:30 - 8:00pm   Socializing
8:00 - 8:15pm   Opening by the Organizer
8:15 - 8:45pm   "Getting Started with Rubinius" - Kamal Fariz
8:45 - 9:15pm   Open Lightning Talks (geared towards JRuby, Ruby 1.9 or whatever you fancy) - Volunteers??
9:15 - 9:30pm   PeepCode T-Shirt and Episode Coupon Lucky Draw and Close
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Cost:&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Free.&lt;/strong&gt; No registration required, just come right in, buy a drink, have a seat, and join the crowd. Invite your friends.&lt;/p&gt;

&lt;h3&gt;Contact:&lt;/h3&gt;

&lt;p&gt;&lt;a href="mailto:kamal.fariz@gmail.com"&gt;kamal.fariz@gmail.com&lt;/a&gt;&lt;br/&gt;
+60123099143&lt;/p&gt;

&lt;h3&gt;Where:&lt;/h3&gt;

&lt;p&gt;Near UNITAR Kelana Jaya&lt;br/&gt;&lt;a href="http://maps.google.com/maps?f=q&amp;hl=en&amp;geocode=&amp;q=unitar&amp;sll=3.150629,101.532555&amp;sspn=0.119639,0.160675&amp;ie=UTF8&amp;ll=3.105485,101.599073&amp;spn=0.014955,0.020084&amp;z=16"&gt;Location&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Directions:&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to new Giant Supermarket, Kelana Jaya&lt;/li&gt;
&lt;li&gt;Go to UNITAR, and then go to the lane behind it.&lt;/li&gt;
&lt;li&gt;Go to the Restoran Utara - we all meet there - venue is in adjacent shoplot.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: Meetup location changed to Kelana Jaya. See directions.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=VfNO0G"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=VfNO0G" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=gt07kVE"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=gt07kVE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=bau23gE"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=bau23gE" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/237476688" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/237476688/26705170</link><guid isPermaLink="false">http://blog.bitfluent.com/post/26705170</guid><pubDate>Tue, 19 Feb 2008 18:10:00 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/26705170</feedburner:origLink></item><item><title>The best investment advice you'll never get</title><description>&lt;a href="http://www.sanfran.com/content_areas/home/view_printable.php?story_id=1507"&gt;The best investment advice you'll never get&lt;/a&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/bitfluent?a=zIw72l"&gt;&lt;img src="http://feeds.feedburner.com/~a/bitfluent?i=zIw72l" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=V2HWApE"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=V2HWApE" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/bitfluent?a=e7w6oIE"&gt;&lt;img src="http://feeds.feedburner.com/~f/bitfluent?i=e7w6oIE" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/bitfluent/~4/237347193" height="1" width="1"/&gt;</description><link>http://feeds.feedburner.com/~r/bitfluent/~3/237347193/26682722</link><guid isPermaLink="false">http://blog.bitfluent.com/post/26682722</guid><pubDate>Tue, 19 Feb 2008 12:14:33 +0800</pubDate><feedburner:origLink>http://blog.bitfluent.com/post/26682722</feedburner:origLink></item></channel></rss>
