<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10titles.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemtitles.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">

  <title><![CDATA[teohm.dev]]></title>
  
  <link href="http://teohm.github.com/" />
  <updated>2013-04-22T22:02:22+08:00</updated>
  <id>http://teohm.github.com/</id>
  <author>
    <name><![CDATA[Huiming Teo (teohm)]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/teohm" /><feedburner:info uri="teohm" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-nc/3.0/" /><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/teohm" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:feedFlare href="http://www.plusmo.com/add?url=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://plusmo.com/res/graphics/fbplusmo.gif">Subscribe with Plusmo</feedburner:feedFlare><feedburner:feedFlare href="http://www.thefreedictionary.com/_/hp/AddRSS.aspx?http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://img.tfd.com/hp/addToTheFreeDictionary.gif">Subscribe with The Free Dictionary</feedburner:feedFlare><feedburner:feedFlare href="http://www.bitty.com/manual/?contenttype=rssfeed&amp;contentvalue=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://www.bitty.com/img/bittychicklet_91x17.gif">Subscribe with Bitty Browser</feedburner:feedFlare><feedburner:feedFlare href="http://www.live.com/?add=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://tkfiles.storage.msn.com/x1piYkpqHC_35nIp1gLE68-wvzLZO8iXl_JMledmJQXP-XTBOLfmQv4zhj4MhcWEJh_GtoBIiAl1Mjh-ndp9k47If7hTaFno0mxW9_i3p_5qQw">Subscribe with Live.com</feedburner:feedFlare><feedburner:feedFlare href="http://mix.excite.eu/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://image.excite.co.uk/mix/addtomix.gif">Subscribe with Excite MIX</feedburner:feedFlare><feedburner:feedFlare href="http://www.webwag.com/wwgthis.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://www.webwag.com/images/wwgthis.gif">Subscribe with Webwag</feedburner:feedFlare><feedburner:feedFlare href="http://www.podcastready.com/oneclick_bookmark.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://www.podcastready.com/images/podcastready_button.gif">Subscribe with Podcast Ready</feedburner:feedFlare><feedburner:feedFlare href="http://www.wikio.com/subscribe?url=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://www.wikio.com/shared/img/add2wikio.gif">Subscribe with Wikio</feedburner:feedFlare><feedburner:feedFlare href="http://www.dailyrotation.com/index.php?feed=http%3A%2F%2Ffeeds.feedburner.com%2Fteohm" src="http://www.dailyrotation.com/rss-dr2.gif">Subscribe with Daily Rotation</feedburner:feedFlare><entry>
    <title type="html"><![CDATA[Chef cookbooks for busy Ruby developers]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/Xnngy6QkvC0/" />
    <updated>2013-04-17T23:06:00+08:00</updated>
    <id>http://teohm.github.com/blog/2013/04/17/chef-cookbooks-for-busy-ruby-developers</id>
    <content type="html">&lt;p&gt;Have you ever &lt;strong&gt;setup a Rails production environment from scratch, by
hand&lt;/strong&gt;? If you had, I share your pain every time when a new project
started.&lt;/p&gt;

&lt;p&gt;The process is often repetitive. To me, it seems to be a waste to do it
manually every time. It also consumes time and attention. It would be
great if I could spend them on tasks that bring more values to clients.&lt;/p&gt;

&lt;p&gt;To minimize such waste, I have written two Chef cookbooks to &lt;strong&gt;automate
the process&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/teohm/rackbox-cookbook"&gt;&lt;strong&gt;rackbox&lt;/strong&gt;&lt;/a&gt;  - to provision &lt;strong&gt;rack-based web server&lt;/strong&gt; (Nginx as front server, Unicorn and Passenger as upstream app servers, &lt;code&gt;rbenv&lt;/code&gt; as ruby version manager).&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/teohm/databox-cookbook"&gt;&lt;strong&gt;databox&lt;/strong&gt;&lt;/a&gt; - to provision &lt;strong&gt;database server&lt;/strong&gt; (supports MySQL and PostgreSQL).&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Getting started&lt;/h2&gt;

&lt;p&gt;In this post, I will show you a &lt;strong&gt;step-by-step guide&lt;/strong&gt; on how to use the
cookbooks together with
&lt;a href="https://github.com/matschaffer/knife-solo"&gt;&lt;code&gt;knife-solo&lt;/code&gt;&lt;/a&gt; to provision a
remote server in 4 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;setup Chef Solo environment&lt;/li&gt;
&lt;li&gt;modify config file&lt;/li&gt;
&lt;li&gt;provision remote server&lt;/li&gt;
&lt;li&gt;tweak Capistrano &lt;code&gt;deploy.rb&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;A working example in also available at
&lt;a href="https://github.com/teohm/kitchen-example"&gt;teohm/kitchen-example&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;1. Setup Chef Solo environment&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install Chef Solo tools on local machine.&lt;/li&gt;
&lt;li&gt;Download Chef cookbooks to local machine.&lt;/li&gt;
&lt;li&gt;Install &lt;code&gt;chef-solo&lt;/code&gt; on remote server.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Install Chef Solo tools&lt;/h3&gt;

&lt;p&gt;Let&amp;#8217;s create a new directory,&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;mkdir chef-kitchen
&lt;/span&gt;&lt;span class='line'&gt;cd chef-kitchen&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;and a &lt;code&gt;Gemfile&lt;/code&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;source "https://rubygems.org"
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;gem "knife-solo", "&amp;gt;= 0.3.0pre3"
&lt;/span&gt;&lt;span class='line'&gt;gem "berkshelf"&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;I recommend &lt;code&gt;knife-solo &amp;gt;= 0.3&lt;/code&gt; as it includes a few &lt;a href="https://github.com/matschaffer/knife-solo/blob/master/CHANGELOG.md#changes-and-new-features"&gt;major fixes and
improvements&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now, install the ruby gems.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;bundle install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Finally, setup a kitchen directory structure with &lt;code&gt;knife-solo&lt;/code&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;bundle exec knife solo init .&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Download Chef cookbooks&lt;/h3&gt;

&lt;p&gt;I use &lt;a href="http://berkshelf.com/"&gt;Berkshelf&lt;/a&gt; to manage cookbooks. So we need a &lt;code&gt;Berksfile&lt;/code&gt;,&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;site :opscode
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;cookbook "runit", "&amp;gt;= 1.1.2"  # HACK: force-use this version
&lt;/span&gt;&lt;span class='line'&gt;cookbook "databox"
&lt;/span&gt;&lt;span class='line'&gt;cookbook "rackbox"&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;(I added a hack here to force &lt;code&gt;berkshelf&lt;/code&gt; to use &lt;code&gt;runit 1.1.2&lt;/code&gt; required
by &lt;code&gt;rackbox&lt;/code&gt;. Still looking for a better solution.)&lt;/p&gt;

&lt;p&gt;We can now download cookbooks with &lt;code&gt;berks install&lt;/code&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;bundle exec berks install --path cookbooks/&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Install &lt;code&gt;chef-solo&lt;/code&gt; on remote server&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;bundle exec knife solo prepare testbox&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;In this example, &lt;code&gt;testbox&lt;/code&gt; is a host I setup in my &lt;code&gt;~/.ssh/config&lt;/code&gt;:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;Host testbox
&lt;/span&gt;&lt;span class='line'&gt;  User ubuntu
&lt;/span&gt;&lt;span class='line'&gt;  Hostname ec2-51-221-13-121.ap-southeast-1.compute.amazonaws.com
&lt;/span&gt;&lt;span class='line'&gt;  IdentityFile ~/.ssh/testbox_ec2.pem&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;2. Customize config file&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Download config example&lt;/li&gt;
&lt;li&gt;Customize config file&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Download config example&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;curl https://raw.github.com/teohm/kitchen-example/master/nodes/host.json.example --output nodes/testbox.json&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Modify config file (JSON)&lt;/h3&gt;

&lt;p&gt;The config file starts with a &lt;code&gt;run_list&lt;/code&gt;. You specify a list of cookbook
recipes here. Chef will run them in the same order in this list.&lt;/p&gt;

&lt;p&gt;It is followed by cookbook attributes. You can modify these attributes.
A full reference of attributes are described in each cookbook&amp;#8217;s README
(see &lt;a href="https://github.com/teohm/appbox-cookbook#attributes"&gt;appbox&lt;/a&gt;,
&lt;a href="https://github.com/teohm/databox-cookbook#attributes"&gt;databox&lt;/a&gt;,
&lt;a href="https://github.com/teohm/rackbox-cookbook#attributes"&gt;rackbox&lt;/a&gt;).&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;span class='line-number'&gt;18&lt;/span&gt;
&lt;span class='line-number'&gt;19&lt;/span&gt;
&lt;span class='line-number'&gt;20&lt;/span&gt;
&lt;span class='line-number'&gt;21&lt;/span&gt;
&lt;span class='line-number'&gt;22&lt;/span&gt;
&lt;span class='line-number'&gt;23&lt;/span&gt;
&lt;span class='line-number'&gt;24&lt;/span&gt;
&lt;span class='line-number'&gt;25&lt;/span&gt;
&lt;span class='line-number'&gt;26&lt;/span&gt;
&lt;span class='line-number'&gt;27&lt;/span&gt;
&lt;span class='line-number'&gt;28&lt;/span&gt;
&lt;span class='line-number'&gt;29&lt;/span&gt;
&lt;span class='line-number'&gt;30&lt;/span&gt;
&lt;span class='line-number'&gt;31&lt;/span&gt;
&lt;span class='line-number'&gt;32&lt;/span&gt;
&lt;span class='line-number'&gt;33&lt;/span&gt;
&lt;span class='line-number'&gt;34&lt;/span&gt;
&lt;span class='line-number'&gt;35&lt;/span&gt;
&lt;span class='line-number'&gt;36&lt;/span&gt;
&lt;span class='line-number'&gt;37&lt;/span&gt;
&lt;span class='line-number'&gt;38&lt;/span&gt;
&lt;span class='line-number'&gt;39&lt;/span&gt;
&lt;span class='line-number'&gt;40&lt;/span&gt;
&lt;span class='line-number'&gt;41&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;{
&lt;/span&gt;&lt;span class='line'&gt;  "run_list": [
&lt;/span&gt;&lt;span class='line'&gt;    "databox",
&lt;/span&gt;&lt;span class='line'&gt;    "rackbox"
&lt;/span&gt;&lt;span class='line'&gt;  ],
&lt;/span&gt;&lt;span class='line'&gt;  "appbox": {
&lt;/span&gt;&lt;span class='line'&gt;    "deploy_keys": ["ssh-rsa 5bnmu23890fghghjk"],
&lt;/span&gt;&lt;span class='line'&gt;    "admin_keys": ["ssh-rsa 456789fghjkvbn567"]
&lt;/span&gt;&lt;span class='line'&gt;  },
&lt;/span&gt;&lt;span class='line'&gt;  "databox": {
&lt;/span&gt;&lt;span class='line'&gt;    "db_root_password": "welcome!",
&lt;/span&gt;&lt;span class='line'&gt;    "databases": {
&lt;/span&gt;&lt;span class='line'&gt;      "mysql": [
&lt;/span&gt;&lt;span class='line'&gt;        { "username": "app1",
&lt;/span&gt;&lt;span class='line'&gt;          "password": "app1",
&lt;/span&gt;&lt;span class='line'&gt;          "database_name": "app1_production" }
&lt;/span&gt;&lt;span class='line'&gt;      ],
&lt;/span&gt;&lt;span class='line'&gt;      "postgresql": [
&lt;/span&gt;&lt;span class='line'&gt;        { "username": "app2",
&lt;/span&gt;&lt;span class='line'&gt;          "password": "app2",
&lt;/span&gt;&lt;span class='line'&gt;          "database_name": "app2_production" }
&lt;/span&gt;&lt;span class='line'&gt;      ]
&lt;/span&gt;&lt;span class='line'&gt;    }
&lt;/span&gt;&lt;span class='line'&gt;  },
&lt;/span&gt;&lt;span class='line'&gt;  "rackbox": {
&lt;/span&gt;&lt;span class='line'&gt;    "ruby": {
&lt;/span&gt;&lt;span class='line'&gt;      "versions": ["1.9.3-p385", "1.9.2-p320"],
&lt;/span&gt;&lt;span class='line'&gt;      "global_version": "1.9.3-p385"
&lt;/span&gt;&lt;span class='line'&gt;    },
&lt;/span&gt;&lt;span class='line'&gt;    "apps": {
&lt;/span&gt;&lt;span class='line'&gt;      "unicorn": [
&lt;/span&gt;&lt;span class='line'&gt;        { "appname": "app1",
&lt;/span&gt;&lt;span class='line'&gt;          "hostname": "app1.test.com" }
&lt;/span&gt;&lt;span class='line'&gt;      ],
&lt;/span&gt;&lt;span class='line'&gt;      "passenger": [
&lt;/span&gt;&lt;span class='line'&gt;        { "appname": "app2",
&lt;/span&gt;&lt;span class='line'&gt;          "hostname": "app2.test.com" }
&lt;/span&gt;&lt;span class='line'&gt;      ]
&lt;/span&gt;&lt;span class='line'&gt;    }
&lt;/span&gt;&lt;span class='line'&gt;  }
&lt;/span&gt;&lt;span class='line'&gt;}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;3. Provision remote server&lt;/h2&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;bundle exec knife solo cook testbox&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;It uploads the kitchen directory and runs &lt;code&gt;chef-solo&lt;/code&gt; on the remote
server. Chef-solo will then takeover and execute the run list to setup
everything.&lt;/p&gt;

&lt;h3&gt;What do we get at this point?&lt;/h3&gt;

&lt;p&gt;Basically, it&amp;#8217;s done!&lt;/p&gt;

&lt;p&gt;We have a &lt;strong&gt;full-stack, rack-based server&lt;/strong&gt; with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3 user accounts (deploy, devops, apps)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rbenv&lt;/code&gt; as ruby version manager&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nginx&lt;/code&gt; as front-server&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unicorn&lt;/code&gt;, &lt;code&gt;passenger-standalone&lt;/code&gt; as upstream app servers, managed by &lt;code&gt;runit&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;postgresql&lt;/code&gt;, &lt;code&gt;mysql&lt;/code&gt; installed and databases created&lt;/li&gt;
&lt;li&gt;all apps will be stored in &lt;code&gt;/home/apps/&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;4. Tweak Capistrano deploy.rb&lt;/h2&gt;

&lt;p&gt;Now, it&amp;#8217;s ready to deploy a Rack-based app to the remote server!&lt;/p&gt;

&lt;p&gt;I have two example Rails apps available on Github:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/teohm/sample-app1"&gt;teohm/sample-app1&lt;/a&gt; runs on unicorn,&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/teohm/sample-app2"&gt;teohm/sample-app2&lt;/a&gt; runs on passenger-standalone.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;There are a few &lt;strong&gt;minor tweaks required in Capistrano &lt;code&gt;deploy.rb&lt;/code&gt;&lt;/strong&gt;, as listed below.&lt;/p&gt;

&lt;p&gt;I will explain the tweaks in details next time. Meanwhile, check out the complete working examples at: &lt;a href="https://github.com/teohm/sample-app1/blob/master/config/deploy.rb"&gt;app1/config/deploy.rb&lt;/a&gt; and &lt;a href="https://github.com/teohm/sample-app2/blob/master/config/deploy.rb"&gt;app2/config/deploy.rb&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Login as &lt;code&gt;deploy&lt;/code&gt; user&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;set :user, "deploy"&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Deploy to &lt;code&gt;/home/apps&lt;/code&gt;&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;set :deploy_to, "/home/apps/#{application}"&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Load &lt;code&gt;rbenv&lt;/code&gt; in Capistrano&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;default_run_options[:shell] = '/bin/bash --login'&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Run bundler with &lt;code&gt;--binstubs&lt;/code&gt;&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;require 'bundler/capistrano'
&lt;/span&gt;&lt;span class='line'&gt;set :bundle_flags, "--deployment --binstubs"
&lt;/span&gt;&lt;span class='line'&gt;set :bundle_without, [:test, :development, :deploy]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Restart app with &lt;code&gt;runit sv&lt;/code&gt;&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;namespace :deploy do
&lt;/span&gt;&lt;span class='line'&gt;  task :start do
&lt;/span&gt;&lt;span class='line'&gt;    run "sudo sv up app1"
&lt;/span&gt;&lt;span class='line'&gt;  end
&lt;/span&gt;&lt;span class='line'&gt;  task :stop do
&lt;/span&gt;&lt;span class='line'&gt;    run "sudo sv down app1"
&lt;/span&gt;&lt;span class='line'&gt;  end
&lt;/span&gt;&lt;span class='line'&gt;  task :restart, :roles =&amp;gt; :app, :except =&amp;gt; { :no_release =&amp;gt; true } do
&lt;/span&gt;&lt;span class='line'&gt;    run "sudo sv restart app1"
&lt;/span&gt;&lt;span class='line'&gt;  end
&lt;/span&gt;&lt;span class='line'&gt;end
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Feedback&lt;/h2&gt;

&lt;p&gt;If you are interested on using the cookbooks, or have an idea/feedback/question about this topic, feel free to drop me (&lt;a href="http://twitter.com/teohm"&gt;@teohm&lt;/a&gt;) a message. Pull requests and issue reports are definitely welcomed!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=Xnngy6QkvC0:xDImkiCMp9c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=Xnngy6QkvC0:xDImkiCMp9c:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=Xnngy6QkvC0:xDImkiCMp9c:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=Xnngy6QkvC0:xDImkiCMp9c:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/Xnngy6QkvC0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2013/04/17/chef-cookbooks-for-busy-ruby-developers/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Reload required files in Rails]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/8Q-5OdS4K6g/" />
    <updated>2013-01-10T12:34:00+08:00</updated>
    <id>http://teohm.github.com/blog/2013/01/10/reload-required-files-in-rails</id>
    <content type="html">&lt;p&gt;When a Rails project grows, I often notice the need to &lt;strong&gt;refactor domain logic into a separate module, isolated from Rails framework&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The isolated module will still stay in the main Rails app codebase, but can be easily packaged as a Ruby gem, tested separately, and used in other related applications.&lt;/p&gt;

&lt;h2&gt;Requirements&lt;/h2&gt;

&lt;p&gt;During the refactoring, we want to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;require&lt;/code&gt; to load the module like a normal gem&lt;/strong&gt;. If possible, no dependency on Rails autoload features such as&lt;code&gt;require_dependency&lt;/code&gt; and &lt;code&gt;autoload_paths&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Edit the module without restarting server during development&lt;/strong&gt;. In other words, we need to find a way to &lt;strong&gt;reload the module on every request&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;Reload &lt;code&gt;require&lt;/code&gt; files&lt;/h2&gt;

&lt;p&gt;After some research, I found a &lt;a href="http://timcardenas.com/automatically-reload-gems-in-rails-327-on-eve"&gt;&lt;strong&gt;working solution&lt;/strong&gt;&lt;/a&gt; by Timothy Cardenas:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;ActionDispatch::Callbacks.to_prepare do
&lt;/span&gt;&lt;span class='line'&gt;  if Object.const_defined?("Module1")
&lt;/span&gt;&lt;span class='line'&gt;    Object.send(:remove_const, "Module1")
&lt;/span&gt;&lt;span class='line'&gt;  end
&lt;/span&gt;&lt;span class='line'&gt;  $".delete_if {|s| s.include?('module1') }
&lt;/span&gt;&lt;span class='line'&gt;  require 'module1'
&lt;/span&gt;&lt;span class='line'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;What it does is, before each request,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Unload the top-level module.&lt;/li&gt;
&lt;li&gt;Un-require all required files from the module.&lt;/li&gt;
&lt;li&gt;Re-require the top-level module.&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;An extra step in Rails 3.2&lt;/h2&gt;

&lt;p&gt;In Rails 3.2, &lt;code&gt;ActionDispatch::Callbacks.to_prepare&lt;/code&gt; has a slightly different behavior. It will run before a request &lt;strong&gt;only if a watchable file is modified&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You need to specify your own &lt;a href="http://api.rubyonrails.org/classes/Rails/Railtie/Configuration.html#method-i-watchable_dirs"&gt;watchable files&lt;/a&gt;:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;# watch all .rb files recursively under modules/module1/ dir
&lt;/span&gt;&lt;span class='line'&gt;config.watchable_dirs['modules/module1'] = [:rb]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Introduce &lt;code&gt;require_reloader&lt;/code&gt; gem&lt;/h2&gt;

&lt;p&gt;Before bundling the solution into a gem, I did a search on RubyGems.org and found Colin Young&amp;#8217;s &lt;a href="https://github.com/colinyoung/gem_reloader"&gt;gem_reloader&lt;/a&gt;. It&amp;#8217;s based on Timy&amp;#8217;s solution as well. I forked it and started playing around.&lt;/p&gt;

&lt;p&gt;In the end, I made some major changes to include Rails 3.2 support, some fixes and new features.&lt;/p&gt;

&lt;p&gt;So I decided to &lt;strong&gt;release it as a new Ruby gem: &lt;a href="https://github.com/teohm/require_reloader"&gt;require_reloader&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class=''&gt;&lt;span class='line'&gt;# config/environments/development.rb
&lt;/span&gt;&lt;span class='line'&gt;YourApp::Application.configure do
&lt;/span&gt;&lt;span class='line'&gt;  ...
&lt;/span&gt;&lt;span class='line'&gt;  RequireReloader.watch :module1,
&lt;/span&gt;&lt;span class='line'&gt;    path: 'modules/module1'
&lt;/span&gt;&lt;span class='line'&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Currently it supports Rails 3, including 3.1 and 3.2.&lt;/p&gt;

&lt;p&gt;If you are working on something similar, looking forward for your feedbacks and pull requests. It is not tested on Rails 2 yet, so pull requests are definitely welcomed!&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=8Q-5OdS4K6g:08sMBF5Bh58:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=8Q-5OdS4K6g:08sMBF5Bh58:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=8Q-5OdS4K6g:08sMBF5Bh58:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=8Q-5OdS4K6g:08sMBF5Bh58:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/8Q-5OdS4K6g" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2013/01/10/reload-required-files-in-rails/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Start Using Ruby % (Percent) Notation]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/rHiCiNjILoA/" />
    <updated>2012-10-15T18:04:00+08:00</updated>
    <id>http://teohm.github.com/blog/2012/10/15/start-using-ruby-percent-notation</id>
    <content type="html">&lt;p&gt;If you seldom use Ruby percent (%) notation in daily work, here&amp;#8217;s a
&lt;strong&gt;quick summary&lt;/strong&gt; of what I picked up recently.&lt;/p&gt;

&lt;h2&gt;Delimiter allows any non-alphanum&lt;/h2&gt;

&lt;p&gt;You can use any &lt;strong&gt;non alpha-numeric character&lt;/strong&gt; as delimiter:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%(any alpha-numeric)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%[char can be]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%%used as%&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%!delimiter\!!&lt;/span&gt; &lt;span class="c1"&gt;# escape &amp;#39;!&amp;#39; literal&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Bracket pairs no need to escape&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;No need to escape bracket pairs&lt;/strong&gt;, even when &lt;strong&gt;nested&lt;/strong&gt;.
You can escape, but will need to escape both open and close bracket.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%( (pa(re(nt)he)sis) )&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; &amp;quot;(pa(re(nt)he)sis)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%[ [square bracket] ]&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; &amp;quot;[square bracket]&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%{ {curly bracket} }&lt;/span&gt;   &lt;span class="c1"&gt;#=&amp;gt; &amp;quot;{curly bracket}&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%&amp;lt; &amp;lt;pointy bracket&amp;gt; &amp;gt;&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; &amp;quot;&amp;lt;pointy bracket&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%&amp;lt; \&amp;lt;this works as well\&amp;gt; &amp;gt;&lt;/span&gt;  &lt;span class="c1"&gt;#=&amp;gt; &amp;quot;&amp;lt;this works as well&amp;gt;&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Modifiers for String, Regex, Array, Symbol, Shell command&lt;/h2&gt;

&lt;p&gt;We often use % notation to &lt;strong&gt;create String and Array&lt;/strong&gt; literals. But it
also supports &lt;strong&gt;Symbol, Regex and shell command&lt;/strong&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%(interpolated string (&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;default&amp;quot;&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;#=&amp;gt; &amp;quot;interpolated string (default)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%Q(interpolated string (&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;default&amp;quot;&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;#=&amp;gt; &amp;quot;interpolated string (default)&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%q(non-interpolated string)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;#=&amp;gt; &amp;quot;non-interpolated string&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sr"&gt;%r(&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;interpolated&amp;quot;&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt; regexp)i&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;#=&amp;gt; /interpolated regexp/i&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%w(non-interpolated\ string  separated\ by\ whitespaces)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;#=&amp;gt; [&amp;#39;non-interpolated string&amp;#39;, &amp;#39;separated by whitespaces&amp;#39;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%W(interpolated\ string &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;separated by whitespaces&amp;quot;&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;#=&amp;gt; [&amp;#39;interpolated string&amp;#39;, &amp;#39;separated by whitespaces&amp;#39;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%s(non-interpolated symbol)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;#=&amp;gt; :&amp;#39;non-interpolated symbol&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="sx"&gt;%x(echo &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;interpolated shell command&amp;quot;&lt;/span&gt; &lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sx"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;#=&amp;gt; &amp;quot;interpolated shell command\n&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Here&amp;#8217;s some &lt;a href="https://github.com/teohm/a-dip-in-ruby/blob/master/spec/percent_notation_spec.rb"&gt;% notation examples written in minitest&lt;/a&gt; in case you interested.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=rHiCiNjILoA:G2c_4kxdqWE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=rHiCiNjILoA:G2c_4kxdqWE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=rHiCiNjILoA:G2c_4kxdqWE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=rHiCiNjILoA:G2c_4kxdqWE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/rHiCiNjILoA" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2012/10/15/start-using-ruby-percent-notation/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Ruby idiom to ensure variable is Array]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/HrDfTnLgHXs/" />
    <updated>2012-10-02T23:27:00+08:00</updated>
    <id>http://teohm.github.com/blog/2012/10/02/ruby-idiom-to-ensure-variable-is-array</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;Stop&lt;/strong&gt; doing this:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;arry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;  &lt;span class="c1"&gt;# handle input == nil&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;arry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;arry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kind_of?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# handle single value object&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;arry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;#process item&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;In Ruby, you should use
&lt;a href="http://www.ruby-doc.org/core-1.9.3/Kernel.html#method-i-Array"&gt;Kernel#Array&lt;/a&gt;
to &lt;strong&gt;convert the variable into an array object&lt;/strong&gt;:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="c1"&gt;# process item&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# Array(nil)     # =&amp;gt; []&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# Array(&amp;quot;foo&amp;quot;)   # =&amp;gt; [&amp;quot;foo&amp;quot;]&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="c1"&gt;# Array([1,2,3]) # =&amp;gt; [1,2,3]&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;a href="https://github.com/teohm/a-dip-in-ruby/blob/master/spec/kernel_array_spec.rb"&gt;More usage examples&lt;/a&gt; written in minitest.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=HrDfTnLgHXs:XCyM3c0eoJc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=HrDfTnLgHXs:XCyM3c0eoJc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=HrDfTnLgHXs:XCyM3c0eoJc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=HrDfTnLgHXs:XCyM3c0eoJc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/HrDfTnLgHXs" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2012/10/02/ruby-idiom-to-ensure-variable-is-array/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Objective-C Collection Operators]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/afmHgIJVFHQ/" />
    <updated>2012-09-24T13:52:00+08:00</updated>
    <id>http://teohm.github.com/blog/2012/09/24/objective-c-collection-operators</id>
    <content type="html">&lt;h2&gt;Calculate average - a shorter way&lt;/h2&gt;

&lt;p&gt;When you have a collection of &lt;code&gt;Transactions&lt;/code&gt; objects and want to
calculate its average amount, instead of looping through the collection
like this:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objective-c'&gt;&lt;span class='line'&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Transaction&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="n"&gt;doubleValue&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;NSNumber&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;avg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NSNumber&lt;/span&gt; &lt;span class="nl"&gt;numberWithDouble:&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;])];&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;you can &lt;strong&gt;reduce the loop to 1 line of code&lt;/strong&gt;, using
&lt;a href="http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/KeyValueCoding/Articles/CollectionOperators.html"&gt;Objective-C key-value coding&lt;/a&gt;:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objective-c'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;NSNumber&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;avg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="nl"&gt;valueForKeyPath:&lt;/span&gt;&lt;span class="s"&gt;@&amp;quot;@avg.amount&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Currently, there is a &lt;strong&gt;fixed set&lt;/strong&gt; of collection operators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple collection operators (&lt;code&gt;@avg&lt;/code&gt;, &lt;code&gt;@count&lt;/code&gt;, &lt;code&gt;@sum&lt;/code&gt;, &lt;code&gt;@max&lt;/code&gt;, &lt;code&gt;@min&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Object operators (&lt;code&gt;@distinctUnionOfObjects&lt;/code&gt;, &lt;code&gt;@unionOfObjects&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Array and set operators (&lt;code&gt;@distinctUnionOfArrays&lt;/code&gt;, &lt;code&gt;@unionOfArrays&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;For details, refer to more
&lt;a href="http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/KeyValueCoding/Articles/CollectionOperators.html"&gt;usage&lt;/a&gt; &lt;a href="https://github.com/teohm/a-dip-in-objective-c/blob/master/ADipInObjectiveCTests/CollectionOperatorTests.m"&gt;examples&lt;/a&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=afmHgIJVFHQ:NMy40CBkKhM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=afmHgIJVFHQ:NMy40CBkKhM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=afmHgIJVFHQ:NMy40CBkKhM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=afmHgIJVFHQ:NMy40CBkKhM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/afmHgIJVFHQ" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2012/09/24/objective-c-collection-operators/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Breaking ARC retain cycle in Objective-C blocks]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/JKl5Vk3Drts/" />
    <updated>2012-09-03T17:50:00+08:00</updated>
    <id>http://teohm.github.com/blog/2012/09/03/breaking-arc-retain-cycle-in-objective-c-blocks</id>
    <content type="html">&lt;p&gt;In a recent client project, we noticed its iOS app often &lt;strong&gt;received low memory
warning&lt;/strong&gt;. The iOS app is developed with ARC-enabled (Automatic Reference Counting).&lt;/p&gt;

&lt;p&gt;When profiled the app using &lt;strong&gt;Instruments &gt; Allocations&lt;/strong&gt;, we found that
a lot of unused ViewController objects were not released from memory.&lt;/p&gt;

&lt;h2&gt;Retain Cycle&lt;/h2&gt;

&lt;p&gt;The codebase uses a lot of &lt;strong&gt;Objective-C blocks&lt;/strong&gt; as shown below, and
&lt;code&gt;self&lt;/code&gt; is often being called within the blocks:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;span class='line-number'&gt;11&lt;/span&gt;
&lt;span class='line-number'&gt;12&lt;/span&gt;
&lt;span class='line-number'&gt;13&lt;/span&gt;
&lt;span class='line-number'&gt;14&lt;/span&gt;
&lt;span class='line-number'&gt;15&lt;/span&gt;
&lt;span class='line-number'&gt;16&lt;/span&gt;
&lt;span class='line-number'&gt;17&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objective-c'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;DetailPageViewController&lt;/span&gt; : &lt;span class="nc"&gt;UIViewController&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;@property&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonatomic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strong&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;UIButton&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;backButton&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="n"&gt;DetailPageViewController&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;@synthesize&lt;/span&gt; &lt;span class="n"&gt;backButton&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;loadView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;doneButton&lt;/span&gt; &lt;span class="nl"&gt;onTouch:&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt; &lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isDone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;YES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;}];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;In this example code, the controller object holds a &lt;strong&gt;strong reference to
&lt;code&gt;doneButton&lt;/code&gt; object&lt;/strong&gt;. But because &lt;code&gt;doneButton onTouch:&lt;/code&gt; block is calling
&lt;code&gt;self&lt;/code&gt;, now the button object &lt;strong&gt;holds a strong reference back to the controller
object&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When object A points strongly to object B, and B points strongly to A, a
&lt;a href="http://cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html"&gt;&lt;strong&gt;retain cycle&lt;/strong&gt;&lt;/a&gt; is created,
and both objects cannot be released from memory.&lt;/p&gt;

&lt;h2&gt;Use Lifetime Qualifiers&lt;/h2&gt;

&lt;p&gt;&lt;a href="http://developer.apple.com/library/mac/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011226-CH1-SW9"&gt;Apple Developer&amp;#8217;s guide on ARC transition&lt;/a&gt; suggested a few ways to &lt;strong&gt;break the retain cycle using different lifetime
qualifiers&lt;/strong&gt;. It is definitely a &lt;strong&gt;must read&lt;/strong&gt; for iOS development.&lt;/p&gt;

&lt;p&gt;If your app is targeted for iOS 5, you can use &lt;code&gt;__weak&lt;/code&gt; lifetime qualifier to break the cycle:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;span class='line-number'&gt;5&lt;/span&gt;
&lt;span class='line-number'&gt;6&lt;/span&gt;
&lt;span class='line-number'&gt;7&lt;/span&gt;
&lt;span class='line-number'&gt;8&lt;/span&gt;
&lt;span class='line-number'&gt;9&lt;/span&gt;
&lt;span class='line-number'&gt;10&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='objective-c'&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;@interface&lt;/span&gt; &lt;span class="nc"&gt;DetailPageViewController&lt;/span&gt; : &lt;span class="nc"&gt;UIViewController&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;loadView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="n"&gt;__weak&lt;/span&gt; &lt;span class="n"&gt;DetailPageViewController&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;doneButton&lt;/span&gt; &lt;span class="nl"&gt;onTouch:&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;id&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="n"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;    &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isDone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;YES&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="p"&gt;}];&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="k"&gt;@end&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Because we are using &lt;code&gt;__weak&lt;/code&gt; qualifier, &lt;code&gt;doneButton onTouch:&lt;/code&gt; block
only has &lt;strong&gt;a weak reference to the controller object&lt;/strong&gt;. Now, the controller
object can be released from memory when its reference count drops to 0.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=JKl5Vk3Drts:vsYGvNmv1i0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=JKl5Vk3Drts:vsYGvNmv1i0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=JKl5Vk3Drts:vsYGvNmv1i0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=JKl5Vk3Drts:vsYGvNmv1i0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/JKl5Vk3Drts" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2012/09/03/breaking-arc-retain-cycle-in-objective-c-blocks/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Mac Tips: Use Caps Lock as Control key]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/U1o_iLq3zmw/" />
    <updated>2012-04-08T10:20:00+08:00</updated>
    <id>http://teohm.github.com/blog/2012/04/08/mac-tips-use-caps-lock-as-control-key</id>
    <content type="html">&lt;p&gt;After using &lt;a href="http://tmux.sourceforge.net/"&gt;tmux&lt;/a&gt;, I start using Control
key a lot often. I decided to move my Control key up to the home row,
by assigning it to &lt;strong&gt;Caps Lock&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For Mac users, open &lt;strong&gt;System Preferences &gt; Keyboard&lt;/strong&gt;, choose &lt;strong&gt;Keyboard&lt;/strong&gt; tab.
Click button &lt;strong&gt;Modifier Keys..&lt;/strong&gt; and change &lt;strong&gt;Caps Lock Key:&lt;/strong&gt; to &lt;strong&gt;^ Control&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://teohm.github.com/images/mac-tips/caps-lock-as-control-key.png" title="A screenshot of Key Modifier Keys dialog" alt="A screenshot of Key Modifier Key dialog"&gt;&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=U1o_iLq3zmw:D-XfY9S4p-s:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=U1o_iLq3zmw:D-XfY9S4p-s:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=U1o_iLq3zmw:D-XfY9S4p-s:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=U1o_iLq3zmw:D-XfY9S4p-s:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/U1o_iLq3zmw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2012/04/08/mac-tips-use-caps-lock-as-control-key/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Mac Tips: Change default application for a file type]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/wDboPaHO9JY/" />
    <updated>2012-04-07T18:46:00+08:00</updated>
    <id>http://teohm.github.com/blog/2012/04/07/mac-tips-change-default-application-for-a-file-type</id>
    <content type="html">&lt;p&gt;To switch the default application for file type,
right-click the file, select &lt;strong&gt;Get Info&lt;/strong&gt; and change the application in
&lt;strong&gt;Open With&lt;/strong&gt; section.&lt;/p&gt;

&lt;p&gt;Remember, remember.. click &lt;strong&gt;Change All&amp;#8230;&lt;/strong&gt; button to &lt;strong&gt;apply the changes to &lt;em&gt;all&lt;/em&gt;
files&lt;/strong&gt;. It seems obvious, but took me a while to figure this out. :)&lt;/p&gt;

&lt;p&gt;&lt;img src="http://teohm.github.com/images/mac-tips/default-application-for-file-type.png" title="A screenshot of Get Info dialog" alt="A screenshot of Get Info dialog"&gt;&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=wDboPaHO9JY:8Y_Xd_f5Wro:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=wDboPaHO9JY:8Y_Xd_f5Wro:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=wDboPaHO9JY:8Y_Xd_f5Wro:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=wDboPaHO9JY:8Y_Xd_f5Wro:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/wDboPaHO9JY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2012/04/07/mac-tips-change-default-application-for-a-file-type/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Mac Tips: Turn on remote login (SSH server)]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/k6xVv4a9L2U/" />
    <updated>2012-04-07T15:12:00+08:00</updated>
    <id>http://teohm.github.com/blog/2012/04/07/mac-tips-turn-on-remote-login-ssh-server</id>
    <content type="html">&lt;p&gt;Enable SSH server on Mac OSX is surprisingly easy. Open &lt;strong&gt;System Preferences &gt;
Sharing&lt;/strong&gt;, and turn on &lt;strong&gt;Remote Login&lt;/strong&gt;. You can futher restrict which user can
login via SSH on the same screen.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://teohm.github.com/images/mac-tips/remote-login.png" title="A screenshot Sharing dialog box." alt="A screenshot Sharing dialog box."&gt;&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=k6xVv4a9L2U:3M_VUnls09Y:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=k6xVv4a9L2U:3M_VUnls09Y:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=k6xVv4a9L2U:3M_VUnls09Y:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=k6xVv4a9L2U:3M_VUnls09Y:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/k6xVv4a9L2U" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2012/04/07/mac-tips-turn-on-remote-login-ssh-server/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Using sshuttle in daily work]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/XuJoiK0JQxo/" />
    <updated>2012-04-01T13:13:00+08:00</updated>
    <id>http://teohm.github.com/blog/2012/04/01/using-sshuttle-in-daily-work</id>
    <content type="html">&lt;p&gt;I was first introduced to &lt;a href="https://github.com/apenwarr/sshuttle"&gt;&lt;strong&gt;sshuttle&lt;/strong&gt;&lt;/a&gt; by Sooyoung (&lt;a href="https://twitter.com/#!/5ooyoung"&gt;@5ooyoung&lt;/a&gt;) in &lt;a href="http://favoritemedium.com/"&gt;Favorite Medium&lt;/a&gt;
as a workaround to The Great Firewall in China.&lt;/p&gt;

&lt;p&gt;Since then, it has become my &lt;strong&gt;light-weight network tunneling tool&lt;/strong&gt; in daily work.&lt;/p&gt;

&lt;h2&gt;Install sshuttle&lt;/h2&gt;

&lt;p&gt;The installation is easy now. You can install it through Mac OSX Homebrew, or &lt;a href="http://packages.ubuntu.com/precise/sshuttle"&gt;Ubuntu apt-get&lt;/a&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;brew install sshuttle
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;I use sshuttle to..&lt;/h2&gt;

&lt;h3&gt;1. Tunnel all traffic&lt;/h3&gt;

&lt;p&gt;This is the first command I learned.
It &lt;strong&gt;forwards all TCP traffic and DNS requests to a remote SSH server&lt;/strong&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sshuttle --dns -vr ssh_server 0/0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Just like &lt;code&gt;ssh&lt;/code&gt;, you can use any server specified in &lt;code&gt;~/.ssh/config&lt;/code&gt;.
The &lt;code&gt;-v&lt;/code&gt; flag means verbose mode.&lt;/p&gt;

&lt;p&gt;Besides TCP and DNS, currently &lt;code&gt;sshuttle&lt;/code&gt; &lt;strong&gt;does not forward other requests
&lt;em&gt;such as&lt;/em&gt; UDP, ICMP ping etc&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;2. Tunnel all traffic, but exclude some&lt;/h3&gt;

&lt;p&gt;You can &lt;strong&gt;exclude certain TCP traffic using &lt;code&gt;-x&lt;/code&gt; option&lt;/strong&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sshuttle --dns -vr ssh_server -x 121.9.204.0/24 -x 61.135.196.21 0/0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;For instance, when I am in China, I don&amp;#8217;t want to tunnel
&lt;a href="http://youku.com"&gt;Youku.com&lt;/a&gt; traffic to a foreign server,
because its movie streaming service is only available within China.&lt;/p&gt;

&lt;p&gt;In this case, I use &lt;code&gt;-x&lt;/code&gt; option to exclude Youku.com IP addresses.&lt;/p&gt;

&lt;h3&gt;3. Tunnel only certain traffic&lt;/h3&gt;

&lt;p&gt;To tunnel only certain TCP traffic, &lt;strong&gt;specify the IP addresses
or &lt;a href="http://www.subnet-calculator.com/cidr.php"&gt;IP ranges&lt;/a&gt; that need tunneling&lt;/strong&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sshuttle -vr ssh_server 121.9.204.0/24 61.135.196.21
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;This command comes in handy, whenever I need to test an app feature (e.g. Netflix movie streaming)
which only available in certain countries, or to bypass ISP faulty caches.&lt;/p&gt;

&lt;h3&gt;4. VPN to office network&lt;/h3&gt;

&lt;p&gt;I seldom do VPN, but all you need is &lt;strong&gt;the remote SSH server with &lt;code&gt;-NH&lt;/code&gt; flags turned on&lt;/strong&gt;.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;sshuttle -NHvr office_ssh_server
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;&lt;code&gt;-N&lt;/code&gt; flag tells sshuttle to figure out by itself the IP subnets to forward,
and &lt;code&gt;-H&lt;/code&gt; flag to scan for hostnames within remote subnets and store them temporarily in &lt;code&gt;/etc/hosts&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;IP addresses.. troublesome?&lt;/h2&gt;

&lt;p&gt;Well, I try not to deal with IP addresses manually. So I wrote a few
&lt;strong&gt;&lt;a href="https://github.com/teohm/dotfiles/blob/master/.bashrc.d/sshuttle_helpers"&gt;sshuttle helpers&lt;/a&gt;
(&lt;code&gt;tnl&lt;/code&gt;, &lt;code&gt;tnlbut&lt;/code&gt;, &lt;code&gt;tnlonly&lt;/code&gt;, &lt;code&gt;vpnto&lt;/code&gt;)&lt;/strong&gt; that allow me to &lt;strong&gt;use domain names instead of IP addresses&lt;/strong&gt;:&lt;/p&gt;

&lt;h3&gt;Tunnel all traffic&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;tnl
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Tunnel all traffic, but exclude some&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;tnlbut youku.com weibo.com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;Tunnel only certain traffic&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;tnlonly netflix.com movies.netflix.com
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h3&gt;VPN to office network&lt;/h3&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;vpnto office_ssh_server
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;The script is available on &lt;a href="https://github.com/teohm/dotfiles/blob/master/.bashrc.d/sshuttle_helpers"&gt;my GitHub repo&lt;/a&gt;.
You can load it into your &lt;code&gt;~/.bashrc&lt;/code&gt;. &lt;strong&gt;To override the default tunneling SSH server&lt;/strong&gt; in the script:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='line'&gt;&lt;span class="nv"&gt;TNL_SERVER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;user@another_server tnl
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;



&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=XuJoiK0JQxo:dD7SdeL2-QU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=XuJoiK0JQxo:dD7SdeL2-QU:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=XuJoiK0JQxo:dD7SdeL2-QU:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=XuJoiK0JQxo:dD7SdeL2-QU:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/XuJoiK0JQxo" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2012/04/01/using-sshuttle-in-daily-work/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[UTF-8 param name issue in Rails multipart form]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/JWrixZldWRE/" />
    <updated>2012-03-27T21:36:00+08:00</updated>
    <id>http://teohm.github.com/blog/2012/03/27/utf-8-param-name-issue-in-rails-multipart-form</id>
    <content type="html">&lt;p&gt;I first stumbled upon this issue when &lt;a href="http://thekindof.me"&gt;Yasith&lt;/a&gt;
(&lt;a href="https://twitter.com/meaningful"&gt;@meaningful&lt;/a&gt;) showed me a strange bug
in a Rails project. Here&amp;#8217;s what happened:&lt;/p&gt;

&lt;h2&gt;Issue&lt;/h2&gt;

&lt;p&gt;When submit a multipart form that contains &lt;strong&gt;Unicode parameter name&lt;/strong&gt; e.g.&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;span class='line-number'&gt;3&lt;/span&gt;
&lt;span class='line-number'&gt;4&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='html'&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;post&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;enctype=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;multipart/form-data&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Iñtërnâtiônàlizætiøn_name&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;         &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Iñtërnâtiônàlizætiøn_value&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;Rails controller returns the param value &lt;code&gt;"Iñtërnâtiônàlizætiøn_value"&lt;/code&gt; as expected.&lt;/p&gt;

&lt;p&gt;But the &lt;strong&gt;param name becomes&lt;/strong&gt;:
&lt;code&gt;"I\xC3\xB1t\xC3\xABrn\xC3\xA2ti\xC3\xB4n\xC3\xA0liz\xC3\xA6ti\xC3\xB8n_name"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It makes life miserable, if you are not expecting this to happen:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Iñtërnâtiônàlizætiøn_name&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; nil&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;I&lt;/span&gt;&lt;span class="se"&gt;\xC3\xB1&lt;/span&gt;&lt;span class="s2"&gt;t&lt;/span&gt;&lt;span class="se"&gt;\xC3\xAB&lt;/span&gt;&lt;span class="s2"&gt;rn&lt;/span&gt;&lt;span class="se"&gt;\xC3\xA2&lt;/span&gt;&lt;span class="s2"&gt;ti&lt;/span&gt;&lt;span class="se"&gt;\xC3\xB4&lt;/span&gt;&lt;span class="s2"&gt;n&lt;/span&gt;&lt;span class="se"&gt;\xC3\xA0&lt;/span&gt;&lt;span class="s2"&gt;liz&lt;/span&gt;&lt;span class="se"&gt;\xC3\xA6&lt;/span&gt;&lt;span class="s2"&gt;ti&lt;/span&gt;&lt;span class="se"&gt;\xC3\xB8&lt;/span&gt;&lt;span class="s2"&gt;n_name&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; &amp;quot;Iñtërnâtiônàlizætiøn_value&amp;quot;&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;What happened?&lt;/h2&gt;

&lt;p&gt;When &lt;a href="https://github.com/rack/rack/blob/master/lib/rack/multipart/parser.rb"&gt;&lt;strong&gt;Rack&lt;/strong&gt;&lt;/a&gt;
returns multipart form data to Rails, it returns:&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;I&lt;/span&gt;&lt;span class="se"&gt;\xC3\xB1&lt;/span&gt;&lt;span class="s2"&gt;t&lt;/span&gt;&lt;span class="se"&gt;\xC3\xAB&lt;/span&gt;&lt;span class="s2"&gt;rn&lt;/span&gt;&lt;span class="se"&gt;\xC3\xA2&lt;/span&gt;&lt;span class="s2"&gt;ti&lt;/span&gt;&lt;span class="se"&gt;\xC3\xB4&lt;/span&gt;&lt;span class="s2"&gt;n&lt;/span&gt;&lt;span class="se"&gt;\xC3\xA0&lt;/span&gt;&lt;span class="s2"&gt;liz&lt;/span&gt;&lt;span class="se"&gt;\xC3\xA6&lt;/span&gt;&lt;span class="s2"&gt;ti&lt;/span&gt;&lt;span class="se"&gt;\xC3\xB8&lt;/span&gt;&lt;span class="s2"&gt;n_name&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="s2"&gt;&amp;quot;I&lt;/span&gt;&lt;span class="se"&gt;\xC3\xB1&lt;/span&gt;&lt;span class="s2"&gt;t&lt;/span&gt;&lt;span class="se"&gt;\xC3\xAB&lt;/span&gt;&lt;span class="s2"&gt;rn&lt;/span&gt;&lt;span class="se"&gt;\xC3\xA2&lt;/span&gt;&lt;span class="s2"&gt;ti&lt;/span&gt;&lt;span class="se"&gt;\xC3\xB4&lt;/span&gt;&lt;span class="s2"&gt;n&lt;/span&gt;&lt;span class="se"&gt;\xC3\xA0&lt;/span&gt;&lt;span class="s2"&gt;liz&lt;/span&gt;&lt;span class="se"&gt;\xC3\xA6&lt;/span&gt;&lt;span class="s2"&gt;ti&lt;/span&gt;&lt;span class="se"&gt;\xC3\xB8&lt;/span&gt;&lt;span class="s2"&gt;n_value&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;p&gt;However, &lt;code&gt;ActionDispatch::Http::Parameters#encode_params&lt;/code&gt; in &lt;a href="https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/parameters.rb"&gt;&lt;strong&gt;Rails&lt;/strong&gt;&lt;/a&gt;
decided to &lt;strong&gt; &lt;em&gt;only&lt;/em&gt; encode parameter values&lt;/strong&gt;, but &lt;em&gt;not&lt;/em&gt; parameter names. &lt;strong&gt;As a result, we get:&lt;/strong&gt;&lt;/p&gt;

&lt;figure class='code'&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;div class="highlight"&gt;&lt;table&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;pre class="line-numbers"&gt;&lt;span class='line-number'&gt;1&lt;/span&gt;
&lt;span class='line-number'&gt;2&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;td class='code'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='line'&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;I&lt;/span&gt;&lt;span class="se"&gt;\xC3\xB1&lt;/span&gt;&lt;span class="s2"&gt;t&lt;/span&gt;&lt;span class="se"&gt;\xC3\xAB&lt;/span&gt;&lt;span class="s2"&gt;rn&lt;/span&gt;&lt;span class="se"&gt;\xC3\xA2&lt;/span&gt;&lt;span class="s2"&gt;ti&lt;/span&gt;&lt;span class="se"&gt;\xC3\xB4&lt;/span&gt;&lt;span class="s2"&gt;n&lt;/span&gt;&lt;span class="se"&gt;\xC3\xA0&lt;/span&gt;&lt;span class="s2"&gt;liz&lt;/span&gt;&lt;span class="se"&gt;\xC3\xA6&lt;/span&gt;&lt;span class="s2"&gt;ti&lt;/span&gt;&lt;span class="se"&gt;\xC3\xB8&lt;/span&gt;&lt;span class="s2"&gt;n_name&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class='line'&gt;  &lt;span class="s2"&gt;&amp;quot;Iñtërnâtiônàlizætiøn_value&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;


&lt;h2&gt;Solutions?&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Don&amp;#8217;t use Unicode param name&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Patch Rails source code. I added a &lt;a href="https://github.com/teohm/rails/compare/multipart_unicode_param_name"&gt;fix in my forked branch&lt;/a&gt;, and &lt;a href="https://github.com/rails/rails/issues/5606"&gt;reported the issue&lt;/a&gt;. Hopefully it will get fixed soon in the coming release.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=JWrixZldWRE:coRG3D1jfFE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=JWrixZldWRE:coRG3D1jfFE:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=JWrixZldWRE:coRG3D1jfFE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=JWrixZldWRE:coRG3D1jfFE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/JWrixZldWRE" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2012/03/27/utf-8-param-name-issue-in-rails-multipart-form/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Working effectively with iTerm2]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/dV1Qd_TqQzY/" />
    <updated>2012-03-22T22:42:00+08:00</updated>
    <id>http://teohm.github.com/blog/2012/03/22/working-effectively-with-iterm2</id>
    <content type="html">&lt;p&gt;I have been using &lt;a href="http://www.iterm2.com"&gt;iTerm&lt;/a&gt; in &lt;a href="http://www.favoritemedium.com"&gt;daily work&lt;/a&gt; for almost a year now.
Along the way, I learned a few handy &lt;strong&gt;settings tweaks and shortcut keys to boost my productivity&lt;/strong&gt; in command-line environment.&lt;/p&gt;

&lt;h2&gt;Install iTerm2&lt;/h2&gt;

&lt;p&gt;If you haven&amp;#8217;t heard of &lt;a href="http://www.iterm2.com"&gt;iTerm&lt;/a&gt;, it&amp;#8217;s a popular &lt;strong&gt;open source alternative to Mac OS X Terminal&lt;/strong&gt;.
Give it a try, download and install it from &lt;a href="http://www.iterm2.com"&gt;http://www.iterm2.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Fine-Tune Settings&lt;/h2&gt;

&lt;p&gt;Launch iTerm, open &lt;strong&gt;iTerm &gt; Preferences&lt;/strong&gt; or just &lt;code&gt;Cmd + ,&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Open tab/pane with current working directory&lt;/h3&gt;

&lt;p&gt;Under &lt;strong&gt;Profiles&lt;/strong&gt; tab, go to &lt;strong&gt;General&lt;/strong&gt; subtab, set &lt;strong&gt;Working Directory&lt;/strong&gt; to &lt;em&gt;&amp;#8220;Reuse previous session&amp;#8217;s directory&amp;#8221;&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;Enable &lt;code&gt;Meta&lt;/code&gt; key&lt;/h3&gt;

&lt;p&gt;To enable Meta key for &lt;a href="http://teohm.github.com/blog/2012/01/04/shortcuts-to-move-faster-in-bash-command-line"&gt;Bash readline editing&lt;/a&gt; e.g. &lt;code&gt;Alt + b&lt;/code&gt; to move to previous word, under &lt;strong&gt;Profiles&lt;/strong&gt; tab, go to &lt;strong&gt;Keys&lt;/strong&gt; subtab, set &lt;strong&gt;Left option key acts as:&lt;/strong&gt; to &lt;em&gt;&amp;#8220;+Esc&amp;#8221;&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;Hotkey to toggle iTerm2&lt;/h3&gt;

&lt;p&gt;Under &lt;strong&gt;Keys&lt;/strong&gt; tab, in &lt;strong&gt;Hotkey&lt;/strong&gt; section, enable &lt;em&gt;&amp;#8220;Show/hide iTerm2 with  a system-wide hotkey&amp;#8221;&lt;/em&gt; and input your hotkey combination, e.g. I use &lt;code&gt;Ctrl + Shift + L&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;Switch pane with mouse cursor&lt;/h3&gt;

&lt;p&gt;Under &lt;strong&gt;Pointer&lt;/strong&gt;, in &lt;strong&gt;Miscellaneous Settings&lt;/strong&gt; section, enable &lt;em&gt;&amp;#8220;Focus follows mouse&amp;#8221;&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;Handy Shortcut Keys&lt;/h2&gt;

&lt;p&gt;Here&amp;#8217;s a set of &lt;strong&gt;shortcut keys I commonly use&lt;/strong&gt;. You can always look for other shortcut keys in the iTerm menu.&lt;/p&gt;

&lt;h3&gt;Tab navigation&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;open new tab &lt;code&gt;Cmd + t&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;next tab &lt;code&gt;Cmd + Shift + ]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;previous tab &lt;code&gt;Cmd + Shift + [&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Pane navigation&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;split pane left-right &lt;code&gt;Cmd + d&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;split pane top-bottom &lt;code&gt;Cmd + Shift + d&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;next pane &lt;code&gt;Cmd + ]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;previous pane &lt;code&gt;Cmd + [&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Search&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;open search bar &lt;code&gt;Cmd + f&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;find next &lt;code&gt;Cmd + g&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Input to all panes&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;input to all panes in current tab &lt;code&gt;Cmd + Alt + i&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Clear screen&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;clear buffer &lt;code&gt;Cmd + k&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;clear lines (Bash command) &lt;code&gt;Ctrl + l&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Zooming / Font Resize&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;toggle maximize window &lt;code&gt;Cmd + Alt + =&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;toggle full screen &lt;code&gt;Cmd + Enter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;make font larger &lt;code&gt;Cmd + +&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;make font smaller &lt;code&gt;Cmd + -&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;iTerm lovers, did I miss anything out?&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=dV1Qd_TqQzY:4KMUCE-lveQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=dV1Qd_TqQzY:4KMUCE-lveQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=dV1Qd_TqQzY:4KMUCE-lveQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=dV1Qd_TqQzY:4KMUCE-lveQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/dV1Qd_TqQzY" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2012/03/22/working-effectively-with-iterm2/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Shortcuts to move faster in Bash command line]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/fIbjbCvOrSw/" />
    <updated>2012-01-04T20:13:00+08:00</updated>
    <id>http://teohm.github.com/blog/2012/01/04/shortcuts-to-move-faster-in-bash-command-line</id>
    <content type="html">&lt;p&gt;Nowadays, I spend more time in Bash shell, typing longer commands. One of my new year resolutions for this year
is to &lt;strong&gt;stop using left/right arrow keys to move around in the command line&lt;/strong&gt;.
I learned &lt;a href="http://pivotallabs.com/users/hunter/blog/articles/1925-terminal-beyond-ctrl-a-and-ctrl-e"&gt;a few shortcuts&lt;/a&gt;
a while ago.&lt;/p&gt;

&lt;p&gt;Last night, I spent some time to read about &lt;strong&gt;&amp;#8220;Command Line Editing&amp;#8221; in &lt;a href="http://www.gnu.org/software/bash/manual/bashref.html#Command-Line-Editing"&gt;the bash manual&lt;/a&gt;&lt;/strong&gt;.
The bash manual is a well-written piece of documentation. I think I should read it more often.&lt;/p&gt;

&lt;p&gt;Well, here&amp;#8217;s the new shortcuts I learned:&lt;/p&gt;

&lt;h2&gt;Basic moves&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Move back one character. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;b&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Move forward one character. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;f&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Delete current character. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;d&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Delete previous character. &lt;code&gt;Backspace&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Undo. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;-&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Moving faster&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Move to the start of line. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;a&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Move to the end of line. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;e&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Move forward a word. &lt;code&gt;Meta&lt;/code&gt; + &lt;code&gt;f&lt;/code&gt; &lt;em&gt;(a word contains alphabets and digits, no symbols)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Move backward a word. &lt;code&gt;Meta&lt;/code&gt; + &lt;code&gt;b&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Clear the screen. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;l&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;strong&gt;What is Meta?&lt;/strong&gt; &lt;code&gt;Meta&lt;/code&gt; is your &lt;code&gt;Alt&lt;/code&gt; key, normally. For &lt;strong&gt;Mac OSX user, you need to
enable it yourself&lt;/strong&gt;. Open &lt;em&gt;Terminal &gt; Preferences &gt; Settings &gt; Keyboard&lt;/em&gt;,
and enable &lt;em&gt;Use option as meta key&lt;/em&gt;. &lt;code&gt;Meta&lt;/code&gt; key, by convention, is used for operations on word.&lt;/p&gt;

&lt;h2&gt;Cut and paste (&amp;#8216;Kill and yank&amp;#8217; for old schoolers)&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cut from cursor to the end of line. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;k&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Cut from cursor to the end of word. &lt;code&gt;Meta&lt;/code&gt; + &lt;code&gt;d&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Cut from cursor to the start of word. &lt;code&gt;Meta&lt;/code&gt; + &lt;code&gt;Backspace&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Cut from cursor to previous whitespace. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;w&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Paste the last cut text. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;y&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Loop through and paste previously cut text. &lt;code&gt;Meta&lt;/code&gt; + &lt;code&gt;y&lt;/code&gt; (use it after &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;y&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Loop through and paste the last argument of previous commands. &lt;code&gt;Meta&lt;/code&gt; + &lt;code&gt;.&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Search the command history&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Search as you type. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;r&lt;/code&gt; and type the search term; Repeat &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;r&lt;/code&gt; to loop through results.&lt;/li&gt;
&lt;li&gt;Search the last remembered search term. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;r&lt;/code&gt; twice.&lt;/li&gt;
&lt;li&gt;End the search at current history entry. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;j&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Cancel the search and restore original line. &lt;code&gt;Ctrl&lt;/code&gt; + &lt;code&gt;g&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Need more?&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A comprehensive &lt;a href="http://www.catonmat.net/blog/bash-emacs-editing-mode-cheat-sheet/"&gt;&lt;strong&gt;bash editing mode cheatsheet&lt;/strong&gt;&lt;/a&gt; by Peteris Krumin (&lt;a href="http://catonmat.net"&gt;catonmat.net&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vim users!&lt;/strong&gt; Do you know you can switch to Vi-style editing mode?
Here: &lt;a href="http://www.catonmat.net/blog/bash-vi-editing-mode-cheat-sheet/"&gt;vi-style cheatsheet&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Bash command line editing is actually handled by &lt;strong&gt;GNU Readline Library&lt;/strong&gt;. So
just dive into &lt;a href="http://www.gnu.org/software/readline/#Documentation"&gt;Readline manual&lt;/a&gt;
for everything else.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=fIbjbCvOrSw:KZZDDAon_3s:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=fIbjbCvOrSw:KZZDDAon_3s:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=fIbjbCvOrSw:KZZDDAon_3s:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=fIbjbCvOrSw:KZZDDAon_3s:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/fIbjbCvOrSw" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2012/01/04/shortcuts-to-move-faster-in-bash-command-line/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Using RABL in Rails JSON Web API]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/6Rb8CPPe8F8/" />
    <updated>2011-05-31T00:00:00+08:00</updated>
    <id>http://teohm.github.com/blog/2011/05/31/using-rabl-in-rails-json-web-api</id>
    <content type="html">&lt;p&gt;Let&amp;#8217;s use an event management app as the example.&lt;/p&gt;

&lt;p&gt;The app has a simple feature: a user can add some events, then invite other users to attend the event. Its data are represented in 3 models: User, Event, and Event Guest.
&lt;img src="http://teohm.github.com/images/2011-05-31-using-rabl-in-rails-json-web-api/models.png" alt="An ER digram that shows the domain models." /&gt;&lt;/p&gt;

&lt;p&gt;Let say, we are going to add a read-only JSON web API for clients to browse data records from the app.&lt;/p&gt;

&lt;h2&gt;Problems&lt;/h2&gt;

&lt;h3&gt;Model is not view&lt;/h3&gt;

&lt;p&gt;When working on a non-trivial web API, you will soon &lt;a href="http://engineering.gomiso.com/2011/05/16/if-youre-using-to_json-youre-doing-it-wrong/"&gt;realize&lt;/a&gt; that, model often cannot be serialized directly in web API.&lt;/p&gt;

&lt;p&gt;Within the same app, one API may need to render a summary view of the model, while another needs a detail view of the same model. You want to serialize a view or view object, not a model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/nesquena/rabl"&gt;&lt;strong&gt;RABL (Ruby API Builder Language) gem&lt;/strong&gt;&lt;/a&gt; is designed for this purpose.&lt;/p&gt;

&lt;h3&gt;Define once, reuse everywhere&lt;/h3&gt;

&lt;p&gt;Let say, we need to render these user attributes: &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;username&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;display_name&lt;/code&gt;, except &lt;code&gt;password&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In RABL, we can define the attribute whitelist in a RABL template.&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;# tryrabl/app/views/users/base.rabl
attributes :id, :username, :email, :display_name&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;To show individual user, we can now reuse the template through RABL &lt;code&gt;extends&lt;/code&gt;.&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;# tryrabl/app/views/users/show.rabl
extends &amp;quot;users/base&amp;quot;
object @user

## JSON output:
# {
#     &amp;quot;user&amp;quot;: {
#         &amp;quot;id&amp;quot;: 8,
#         &amp;quot;username&amp;quot;: &amp;quot;blaise&amp;quot;,
#         &amp;quot;email&amp;quot;: &amp;quot;matteo@wilkinsonhuel.name&amp;quot;,
#         &amp;quot;display_name&amp;quot;: &amp;quot;Ms. Noe Lowe&amp;quot;
#     }
# }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Here&amp;#8217;s another example to show a list of users.&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;# tryrabl/app/views/users/index.rabl
extends &amp;quot;users/base&amp;quot;
collection @users

## JSON output:
# [{
#     &amp;quot;user&amp;quot;: {
#         &amp;quot;id&amp;quot;: 1,
#         &amp;quot;username&amp;quot;: &amp;quot;alanna&amp;quot;,
#         &amp;quot;email&amp;quot;: &amp;quot;rubie@hayes.name&amp;quot;,
#         &amp;quot;display_name&amp;quot;: &amp;quot;Mrs. Gaylord Hoeger&amp;quot;
#     }
# }, {
#     &amp;quot;user&amp;quot;: {
#         &amp;quot;id&amp;quot;: 2,
#         &amp;quot;username&amp;quot;: &amp;quot;jarrell.robel&amp;quot;,
#         &amp;quot;email&amp;quot;: &amp;quot;jarod@eichmann.com&amp;quot;,
#         &amp;quot;display_name&amp;quot;: &amp;quot;Oran Lebsack&amp;quot;
#     }
# }]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;The template can be reused in nested child as well, through RABL &lt;code&gt;child&lt;/code&gt;.&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;attributes :id, :title, :description, :start, :end, :location
child :creator =&amp;gt; :creator do
  extends 'users/base'
end

## JSON output:
# {
#     &amp;quot;event&amp;quot;: {
#         &amp;quot;id&amp;quot;: 7,
#         &amp;quot;title&amp;quot;: &amp;quot;Et earum sed fuga.&amp;quot;,
#         &amp;quot;description&amp;quot;: &amp;quot;Quis sed ..e ad.&amp;quot;,
#         &amp;quot;start&amp;quot;: &amp;quot;2011-05-31T08:31:45Z&amp;quot;,
#         &amp;quot;end&amp;quot;: &amp;quot;2011-06-01T08:31:45Z&amp;quot;,
#         &amp;quot;location&amp;quot;: &amp;quot;Saul Tunnel&amp;quot;,
#         &amp;quot;creator&amp;quot;: {
#             &amp;quot;id&amp;quot;: 1,
#             &amp;quot;username&amp;quot;: &amp;quot;alanna&amp;quot;,
#             &amp;quot;email&amp;quot;: &amp;quot;rubie@hayes.name&amp;quot;,
#             &amp;quot;display_name&amp;quot;: &amp;quot;Mrs. Gaylord Hoeger&amp;quot;
#         }
#     }
# }&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h3&gt;Join table rendered as subclass&lt;/h3&gt;

&lt;p&gt;I notice a recurring pattern in two recent projects. For instance, in this example, from client&amp;#8217;s point of view, Event Guest is basically a User with an additional attribute: RSVP status.&lt;/p&gt;

&lt;p&gt;When query database, usually we need to query the join table: &lt;code&gt;event_guests&lt;/code&gt;.&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;class GuestsController &amp;lt; ApplicationController
  def index
    @guests = EventGuest.where(:event_id =&amp;gt; params[:event_id])
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;But when rendering, the result set needs to be rendered as a list of Users. RABL allows you to do that easily, using its &lt;code&gt;glue&lt;/code&gt; feature (a weird name though :).&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;# tryrabl/app/views/guests/index.rabl
collection @event_guests

# include the additional attribute
attributes :rsvp

# add child attributes to parent model
glue :user do
  extends &amp;quot;users/base&amp;quot;
end

## JSON output:
# [{
#     &amp;quot;event_guest&amp;quot;: {
#         &amp;quot;rsvp&amp;quot;: &amp;quot;PENDING&amp;quot;,
#         &amp;quot;id&amp;quot;: 3,
#         &amp;quot;username&amp;quot;: &amp;quot;myrna_harvey&amp;quot;,
#         &amp;quot;email&amp;quot;: &amp;quot;shad.armstrong@littelpouros.name&amp;quot;,
#         &amp;quot;display_name&amp;quot;: &amp;quot;Savion Balistreri&amp;quot;
#     }
# }, {
#     &amp;quot;event_guest&amp;quot;: {
#         &amp;quot;rsvp&amp;quot;: &amp;quot;PENDING&amp;quot;,
#         &amp;quot;id&amp;quot;: 4,
#         &amp;quot;username&amp;quot;: &amp;quot;adelle.nader&amp;quot;,
#         &amp;quot;email&amp;quot;: &amp;quot;brendon.howe@cormiergrady.info&amp;quot;,
#         &amp;quot;display_name&amp;quot;: &amp;quot;Edgardo Dickens&amp;quot;
#     }
# }]&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;I think I will use RABL for the next Rails web API project.&lt;/p&gt;

&lt;p&gt;The complete Rails example code is available at &lt;a href="https://github.com/teohm/tryrabl"&gt;github.com/teohm/tryrabl&lt;/a&gt;.&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=6Rb8CPPe8F8:NT0otOtYVTY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=6Rb8CPPe8F8:NT0otOtYVTY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=6Rb8CPPe8F8:NT0otOtYVTY:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=6Rb8CPPe8F8:NT0otOtYVTY:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/6Rb8CPPe8F8" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2011/05/31/using-rabl-in-rails-json-web-api/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Learning Git Internals by Example]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/ZEA379947g0/" />
    <updated>2011-05-30T00:00:00+08:00</updated>
    <id>http://teohm.github.com/blog/2011/05/30/learning-git-internals-by-example</id>
    <content type="html">&lt;p&gt;&lt;em&gt;Status: Draft.&lt;/em&gt;&lt;br/&gt;
&lt;em&gt;Plan to revise this post, probably simplify it in future..&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;Movitation&lt;/h2&gt;

&lt;p&gt;After switching to Git from Subversion and Mercurial for a few months, somehow I feel that Git is fundamentally different from Subversion or Mercurial, but couldn&amp;#8217;t really tell the differences. I often see terms like tree, parent etc. in GitHub, which I have no idea what they actually mean.&lt;/p&gt;

&lt;p&gt;So I decided to spent some time to learn Git.&lt;/p&gt;

&lt;p&gt;I will try to summarize and publish important stuffs I learned about Git along the way.. but here is the first entry, about Git internals, which helped me to answer how Git is different other source control tools.&lt;/p&gt;

&lt;h2&gt;Objects, References, The Index&lt;/h2&gt;

&lt;p&gt;To understand the core of Git internals, there are 3 things to we should know: &lt;strong&gt;objects, references, the index&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I find this model is elegant. It fits well in a small diagram, as well as in my head.&lt;/p&gt;

&lt;p&gt;&lt;img src="http://teohm.github.com/images/2011-05-30-learning-git-internals-by-example/big-picture.png" alt="A picture illustrates files in .git directory mentioned in this article." /&gt;&lt;/p&gt;

&lt;h3&gt;Objects&lt;/h3&gt;

&lt;p&gt;All files that you commited into a Git repository, including the commit info are stored as &lt;strong&gt;objects&lt;/strong&gt; in &lt;code&gt;.git/objects/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;An object is identified by a 40-character-long string &amp;#8211; SHA1 hash of the object&amp;#8217;s content.&lt;/p&gt;

&lt;p&gt;There are &lt;strong&gt;4 types&lt;/strong&gt; of objects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;blob&lt;/em&gt; - stores file content.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;tree&lt;/em&gt; - stores direcotry layouts and filenames.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;commit&lt;/em&gt; - stores commit info and forms the Git commit graph.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;tag&lt;/em&gt; - stores annotated tag.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;The example will illustrate how these objects relate to each others.&lt;/p&gt;

&lt;h3&gt;References&lt;/h3&gt;

&lt;p&gt;A &lt;em&gt;branch&lt;/em&gt;, &lt;em&gt;remote branch&lt;/em&gt; or a &lt;em&gt;tag&lt;/em&gt; (also called &lt;em&gt;lightweight tag&lt;/em&gt;) in Git, is just a &lt;strong&gt;pointer to an object&lt;/strong&gt;, usually a commit object.&lt;/p&gt;

&lt;p&gt;They are stored as plain text files in &lt;code&gt;.git/refs/&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;Symbolic References&lt;/h4&gt;

&lt;p&gt;Git has a special kind of reference, called &lt;em&gt;symbolic reference&lt;/em&gt;. It doesn&amp;#8217;t point to an object directly. Instead, it &lt;strong&gt;points to another reference&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For instance, &lt;code&gt;.git/HEAD&lt;/code&gt; is a symbolic reference. It points to the current branch you are working on.&lt;/p&gt;

&lt;h3&gt;The Index&lt;/h3&gt;

&lt;p&gt;The index is a staging area, stored as a binary file in &lt;code&gt;.git/index&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;git add&lt;/code&gt; a file, Git adds the file info to the index. When &lt;code&gt;git commit&lt;/code&gt;, Git only commits what&amp;#8217;s listed in the index.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2&gt;Examples&lt;/h2&gt;

&lt;p&gt;Let&amp;#8217;s walkthrough a simple example, to create a Git repository, commit some files and see what happened behind the scene in &lt;code&gt;.git&lt;/code&gt; directory.&lt;/p&gt;

&lt;h3&gt;Initialize New Repository&lt;/h3&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;$ git init canai&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;img src="http://teohm.github.com/images/2011-05-30-learning-git-internals-by-example/init.png" alt="illustration" /&gt;&lt;/p&gt;

&lt;p&gt;What happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Empty &lt;code&gt;.git/objects/&lt;/code&gt; and &lt;code&gt;.git/refs/&lt;/code&gt; created.&lt;/li&gt;
&lt;li&gt;No index file yet.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HEAD&lt;/code&gt; symbolic reference created.

&lt;pre&gt;&lt;code&gt;$ cat .git/HEAD 
ref: refs/heads/master
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Add New File&lt;/h3&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;$ echo &amp;quot;A roti canai project.&amp;quot; &amp;gt;&amp;gt; README
$ git add README&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;img src="http://teohm.github.com/images/2011-05-30-learning-git-internals-by-example/new-file.png" alt="illustration" /&gt;&lt;/p&gt;

&lt;p&gt;What happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Index file created.&lt;br/&gt;
It has a SHA1 hash that points to a blob object.

&lt;pre&gt;&lt;code&gt;$ git ls-files --stage
100644 5f89c6f016cad2d419e865df380595e39b1256db 0 README
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Blob object created.&lt;br/&gt;
The content of README file is stored in this blob.

&lt;pre&gt;&lt;code&gt;# .git/objects/5f/89c6f016cad2d419e865df380595e39b1256db
$ git cat-file blob 5f89c6
A roti canai project.
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;First Commit&lt;/h3&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;$ git commit -m'first commit'
[master (root-commit) d9976cf] first commit
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 README&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;img src="http://teohm.github.com/images/2011-05-30-learning-git-internals-by-example/first-commit.png" alt="illustration" /&gt;&lt;/p&gt;

&lt;p&gt;What happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Branch &amp;#8216;master&amp;#8217; reference created.&lt;br/&gt;
It points to the lastest commit object in &amp;#8216;master&amp;#8217; branch.

&lt;pre&gt;&lt;code&gt;$ cat .git/refs/heads/master 
d9976cfe0430557885d162927dd70186d0f521e8
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;First commit object created.&lt;br/&gt;
It points to the root tree object.

&lt;pre&gt;&lt;code&gt;# .git/objects/d9/976cfe0430557885d162927dd70186d0f521e8
$ git cat-file commit d9976cf
tree 0ff699bbafc5d17d0637bf058c924ab405b5dcfe
author Huiming Teo &amp;lt;huiming@favoritemedium.com&amp;gt; 1306739524 +0800
committer Huiming Teo &amp;lt;huiming@favoritemedium.com&amp;gt; 1306739524 +0800

first commit
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Tree object created.&lt;br/&gt;
This tree represents the &amp;#8216;canai&amp;#8217; directory.

&lt;pre&gt;&lt;code&gt;# .git/objects/0f/f699bbafc5d17d0637bf058c924ab405b5dcfe
$ git ls-tree 0ff699
100644 blob 5f89c6f016cad2d419e865df380595e39b1256db  README
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Add Modified File&lt;/h3&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;$ echo &amp;quot;Welcome everyone.&amp;quot; &amp;gt;&amp;gt; README
$ git add README&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;img src="http://teohm.github.com/images/2011-05-30-learning-git-internals-by-example/modified-file.png" alt="illustration" /&gt;&lt;/p&gt;

&lt;p&gt;What happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Index file updated.&lt;br/&gt;
Notice it points to a new blob?

&lt;pre&gt;&lt;code&gt;$ git ls-files --stage
100644 1192db4c15e019da7fc053225d09dea14bc3ac07 0 README
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Blob object created.&lt;br/&gt;
The entire README content is stored as a new blob.

&lt;pre&gt;&lt;code&gt;# .git/objects/11/92db4c15e019da7fc053225d09dea14bc3ac07
$ git cat-file blob 1192db
A roti canai project.
Welcome everyone.
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Add File into Subdirectory&lt;/h3&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;$ mkdir doc
$ echo &amp;quot;[[TBD]] manual toc&amp;quot; &amp;gt;&amp;gt; doc/manual.txt
$ git add doc&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;img src="http://teohm.github.com/images/2011-05-30-learning-git-internals-by-example/subdir.png" alt="illustration" /&gt;&lt;/p&gt;

&lt;p&gt;What happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Index file updated.

&lt;pre&gt;&lt;code&gt;$ git ls-files --stage
100644 1192db4c15e019da7fc053225d09dea14bc3ac07 0 README
100644 ea283e4fb22719fad512405d41dffa050cd16f9a 0 doc/manual.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Blob object created.

&lt;pre&gt;&lt;code&gt;# .git/objects/ea/283e4fb22719fad512405d41dffa050cd16f9a
$ git cat-file blob ea283
[[TBD]] manual toc
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Second Commit&lt;/h3&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;$ git commit -m'second commit'
[master 556eaf3] second commit
 2 files changed, 2 insertions(+), 0 deletions(-)
 create mode 100644 doc/manual.txt&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;img src="http://teohm.github.com/images/2011-05-30-learning-git-internals-by-example/second-commit.png" alt="illustration" /&gt;&lt;/p&gt;

&lt;p&gt;What happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Branch &amp;#8216;master&amp;#8217; reference updated.&lt;br/&gt;
It points to a lastest commit in this branch.

&lt;pre&gt;&lt;code&gt;$ cat .git/refs/heads/master 
556eaf374886d4c07a1906b9fdcaba195292b96
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Second commit object created.
Notice its &amp;#8216;parent&amp;#8217; points to the first commit object. This forms a commit graph.

&lt;pre&gt;&lt;code&gt;$ git cat-file commit 556e
tree 7729a8b15b747bce541a9752a8f10d57daf221b6
parent d9976cfe0430557885d162927dd70186d0f521e8
author Huiming Teo &amp;lt;huiming@favoritemedium.com&amp;gt; 1306743598 +0800
committer Huiming Teo &amp;lt;huiming@favoritemedium.com&amp;gt; 1306743598 +0800

second commit
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;New root tree object created.

&lt;pre&gt;&lt;code&gt;$ git ls-tree 7729
100644 blob 1192db4c15e019da7fc053225d09dea14bc3ac07  README
040000 tree 6ff17d485bf857514f299f0bde0e2a5c932bd055  doc
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;New subdir tree object created.

&lt;pre&gt;&lt;code&gt;$ git ls-tree 6ff1
100644 blob ea283e4fb22719fad512405d41dffa050cd16f9a  manual.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Add Annotated Tag&lt;/h3&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;$ git tag -a -m'this is annotated tag' v0.1 d9976&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;img src="http://teohm.github.com/images/2011-05-30-learning-git-internals-by-example/annotated-tag.png" alt="illustration" /&gt;&lt;/p&gt;

&lt;p&gt;What happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tag reference created.&lt;br/&gt;
It points to a tag object.

&lt;pre&gt;&lt;code&gt;$ cat .git/refs/tags/v0.1 
c758f4820f02acf20bb3f6d7f6098f25ee6ed730
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;Tag object created.

&lt;pre&gt;&lt;code&gt;$ git cat-file tag c758
object d9976cfe0430557885d162927dd70186d0f521e8
type commit
tag v0.1
tagger Huiming Teo &amp;lt;huiming@favoritemedium.com&amp;gt; 1306744918 +0800

this is annotated tag
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Add new (lightweight) tag&lt;/h3&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='bash'&gt;$ git tag root-commit d9976&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;&lt;img src="http://teohm.github.com/images/2011-05-30-learning-git-internals-by-example/new-tag.png" alt="illustration" /&gt;&lt;/p&gt;

&lt;p&gt;What happened:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tag reference created.&lt;br/&gt;
It points to a commit object.

&lt;pre&gt;&lt;code&gt;$ cat .git/refs/tags/root-commit 
d9976cfe0430557885d162927dd70186d0f521e8
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;More Readings&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;Chapter 7: Internals and Plumbing&amp;#8221; in &lt;a href="http://book.git-scm.com/index.html"&gt;The Git Community Book&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&amp;#8220;Chapter 9: Git Internals&amp;#8221; in &lt;a href="http://progit.org/book/ch9-0.html"&gt;Pro Git&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;What&amp;#8217;s Next?&lt;/h2&gt;

&lt;p&gt;Looking for a minimal git workflow suitable for a distributed team, long-running project..&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=ZEA379947g0:yOPRyxxPGpc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=ZEA379947g0:yOPRyxxPGpc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=ZEA379947g0:yOPRyxxPGpc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=ZEA379947g0:yOPRyxxPGpc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/ZEA379947g0" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2011/05/30/learning-git-internals-by-example/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[Using JQuery Validation in Rails Remote Form]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/68yizOjtKMg/" />
    <updated>2011-05-25T00:00:00+08:00</updated>
    <id>http://teohm.github.com/blog/2011/05/25/using-jquery-validation-in-rails-remote-form</id>
    <content type="html">&lt;p&gt;In a recent project, I was trying to use &lt;a href="http://bassistance.de/jquery-plugins/jquery-plugin-validation/"&gt;JQuery Validation&lt;/a&gt; in an &lt;a href="https://github.com/rails/jquery-ujs/blob/bb620a29199214b5c7a3a015372fda28b69c69a1/src/rails.js"&gt;earlier version&lt;/a&gt; of Rails 3 remote form (&lt;a href="https://github.com/rails/jquery-ujs"&gt;jquery-ujs&lt;/a&gt;). They didn&amp;#8217;t work out well in IE.&lt;/p&gt;

&lt;p&gt;After experimenting with the &lt;a href="https://github.com/rails/jquery-ujs/blob/dad6982dc592686677e6845e681233c40d2ead27/src/rails.js"&gt;latest jquery-ujs&lt;/a&gt; and making an embarrassing mistake, it turns out that the issue is resolved in the latest version.&lt;/p&gt;

&lt;p&gt;(&lt;em&gt;Mistake&lt;/em&gt;: You may notice I removed a previous post about this topic, where I mistakenly concluded the latest jquery-ujs is not working with JQuery Validation. Thanks to JangoSteve for &lt;a href="https://github.com/rails/jquery-ujs/issues/165#comment_1228899"&gt;pointing it out&lt;/a&gt;. The post was misleading, so I believe it&amp;#8217;s best to remove it to avoid confusion. :-)&lt;/p&gt;

&lt;h2&gt;Get the latest &lt;code&gt;jquery-ujs&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;There are 2 reasons to use the latest jquery-ujs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;it has a patch that fixes the issue (see &lt;a href="https://github.com/rails/jquery-ujs/issues/118"&gt;issue #118&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;it exposes an internal function that we may need &amp;#8211; &lt;code&gt;$.rails.handleRemote()&lt;/code&gt; (see &lt;a href="http://www.alfajango.com/blog/rails-jquery-ujs-now-interactive/"&gt;more details&lt;/a&gt;)&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;Working example&lt;/h2&gt;

&lt;p&gt;The example is tested with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JQuery 1.6.1&lt;/li&gt;
&lt;li&gt;JQuery Vaidation 1.8.1&lt;/li&gt;
&lt;li&gt;Latest Rails UJS (commit: &lt;a href="https://github.com/rails/jquery-ujs/blob/dad6982dc592686677e6845e681233c40d2ead27/src/rails.js"&gt;dad6982dc592686677e6&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;When using &lt;code&gt;submitHandler&lt;/code&gt; in JQuery Validation&lt;/h3&gt;

&lt;p&gt;If you are using JQuery Validation&amp;#8217;s &lt;code&gt;submitHandler(form)&lt;/code&gt; function, you need to
call &lt;code&gt;$.rails.handleRemote( $(form) )&lt;/code&gt; function manually, so that it submits the form via XHR.&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='javascript'&gt;$('#submit_form').validate({

  submitHandler: function(form) {
    // .. do something before submit ..
    $.rails.handleRemote( $(form) );  // submit via xhr
    //form.submit();                  // don't use, it submits the form directly
  }

});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;



&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=68yizOjtKMg:iHP5lIDjmh0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=68yizOjtKMg:iHP5lIDjmh0:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=68yizOjtKMg:iHP5lIDjmh0:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=68yizOjtKMg:iHP5lIDjmh0:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/68yizOjtKMg" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2011/05/25/using-jquery-validation-in-rails-remote-form/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[ActiveRecord Mass Assignment]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/4XHLJnPK25M/" />
    <updated>2011-05-09T00:00:00+08:00</updated>
    <id>http://teohm.github.com/blog/2011/05/09/activerecord-mass-assignment</id>
    <content type="html">&lt;p&gt;Even you haven&amp;#8217;t heard of
&lt;a href="http://guides.rubyonrails.org/security.html#mass-assignment"&gt;mass assignment&lt;/a&gt;,
it already exists in your first Rails generated scaffold code.&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;def create
  @comment = Comment.new(params[:comment])
  ..
end

def update
  ..
  @comment.update_attributes(params[:comment])
  ..
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Why knowing mass assignment is important?&lt;/h2&gt;

&lt;p&gt;By default, mass assignment opens up an undesirable &lt;strong&gt;security hole&lt;/strong&gt;,
by allowing web clients to update any attributes they passing in,
including attributes like &lt;code&gt;created_at&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For details, you can read:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://guides.rubyonrails.org/security.html#mass-assignment"&gt;Ruby On Rails Security Guide - Mass Assignment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://railspikes.com/2008/9/22/is-your-rails-application-safe-from-mass-assignment"&gt;Rail Spikes: Is your Rails application safe?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Mass assignment methods&lt;/h2&gt;

&lt;p&gt;There are a few &lt;strong&gt;ActiveRecord methods&lt;/strong&gt; that accept mass assignment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html#method-c-new"&gt;&lt;code&gt;new&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html#method-c-create"&gt;&lt;code&gt;create&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html#method-i-attributes-3D"&gt;&lt;code&gt;attributes=&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://apidock.com/rails/ActiveRecord/Base/update_attributes"&gt;&lt;code&gt;update_attributes&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Using any of these methods, means you are now responsible for the safety
of the web application.&lt;/p&gt;

&lt;h2&gt;Minimal protection&lt;/h2&gt;

&lt;p&gt;To use mass assignment safely, we want to specify exactly which attributes
allowed to be updated.&lt;/p&gt;

&lt;h3&gt;1. Define &lt;code&gt;attr_accessible&lt;/code&gt; on every model&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;attr_accessible&lt;/code&gt; defines a white-list of attributes
that can be updated during mass assignment.&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;class Comment &amp;lt; ActiveRecord::Base
  attr_accessible :title, :content
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h3&gt;2. Enforce &lt;code&gt;attr_accessible&lt;/code&gt; usage&lt;/h3&gt;

&lt;p&gt;You may set the white-list default to empty. This forces you
to define the whitelist explicitly on a model, before
mass assignment can be used.&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;# config/initializer/enforce_attr_accessible.rb

ActiveRecord::Base.send(:attr_accessible, nil)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;



&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=4XHLJnPK25M:vEvy4nrbYAk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=4XHLJnPK25M:vEvy4nrbYAk:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=4XHLJnPK25M:vEvy4nrbYAk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=4XHLJnPK25M:vEvy4nrbYAk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/4XHLJnPK25M" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2011/05/09/activerecord-mass-assignment/</feedburner:origLink></entry>
  
  <entry>
    <title type="html"><![CDATA[ActiveRecord Model Equality]]></title>
    <link href="http://feedproxy.google.com/~r/teohm/~3/NFXbh5-ODBs/" />
    <updated>2011-05-05T00:00:00+08:00</updated>
    <id>http://teohm.github.com/blog/2011/05/05/activerecord-model-equality</id>
    <content type="html">&lt;p&gt;In daily web app development, we often need to check if two model objects are equal.
When I first started using Rails, this is what I wrote:&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;if user.id == current_user.id
  # do something
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Use obj1 == obj2 instead&lt;/h2&gt;

&lt;p&gt;Of course, that reflects my ignorance on learning the new tool.&lt;/p&gt;

&lt;p&gt;So, here&amp;#8217;s a proper way to compare if
&lt;a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html#method-i-3D-3D"&gt;two model objects are equal&lt;/a&gt;:&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;test &amp;quot;2 records with same #id equal to each others.&amp;quot; do
  c1 = Comment.create
  c2 = Comment.find(c1.id)

  assert c1 == c2
  assert c2 == c1
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;What about new record?&lt;/h2&gt;

&lt;p&gt;Basically, a new model object only equals to itself:&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;test &amp;quot;New record does not equal to another new record.&amp;quot; do
  new_record = Comment.new
  another_new = Comment.new

  assert new_record == new_record
  assert another_new == another_new
  assert new_record != another_new
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Learning to use &lt;code&gt;==&lt;/code&gt; operator for checking model equality
is useful. Because now, we can start using other methods
that depend on &lt;code&gt;==&lt;/code&gt; operator. For instance, &lt;code&gt;Array#include?&lt;/code&gt;.&lt;/p&gt;

&lt;div&gt;
  &lt;pre&gt;&lt;code class='ruby'&gt;test &amp;quot;When applied in Array&amp;quot; do
  c1 = Comment.create
  c2 = Comment.find(c1.id)

  assert [c1].include? c2
  assert [c2].include? c1
  assert [c1, c2] == [c1, c2]
end&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Rails learning tests&lt;/h2&gt;

&lt;p&gt;You may notice the code examples are written as tests.
This is my first &lt;a href="https://github.com/teohm/lt_rails"&gt;Rails learning test&lt;/a&gt;.
So the plan is to write more tests as a way to learn Rails. I will
post them here occationally if interesting enough to share.&lt;/p&gt;

&lt;p&gt;Source code: &lt;a href="https://github.com/teohm/lt_rails/blob/master/test/unit/model_equality_test.rb"&gt;model_equality_test.rb&lt;/a&gt;&lt;/p&gt;
&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/teohm?a=NFXbh5-ODBs:uFHRVCu6CQM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=NFXbh5-ODBs:uFHRVCu6CQM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/teohm?a=NFXbh5-ODBs:uFHRVCu6CQM:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/teohm?i=NFXbh5-ODBs:uFHRVCu6CQM:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/teohm/~4/NFXbh5-ODBs" height="1" width="1"/&gt;</content>
  <feedburner:origLink>http://teohm.github.com/blog/2011/05/05/activerecord-model-equality/</feedburner:origLink></entry>
  
</feed>
