<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>http://arjanvandergaag.nl/</id>
  <title>arjanvandergaag.nl atom feed</title>
  <updated>2012-02-02T12:30:00Z</updated>
  <link rel="alternate" href="http://arjanvandergaag.nl/"/>
  <link rel="self" href="http://arjanvandergaag.nl/feed/"/>
  <author>
    <name>Arjan van der Gaag</name>
    <uri>http://arjanvandergaag.nl</uri>
  </author>
  <entry>
    <id>tag:arjanvandergaag.nl,2012-02-02:/blog/bol-gem.html</id>
    <title type="html">A Ruby gem for the bol.com developer API</title>
    <published>2012-02-02T12:30:00Z</published>
    <updated>2012-02-02T12:30:00Z</updated>
    <link rel="alternate" href="/"/>
    <content type="html">&lt;p class="leader"&gt;It has bugged me for a long time that I could not access product information
from &lt;a href="http://bol.com"&gt;bol.com&lt;/a&gt; the same way I could from Amazon.com. When bol.com released
their public &lt;span class="caps"&gt;API&lt;/span&gt; some time ago, I &lt;em&gt;still&lt;/em&gt; couldn’t. Not easily. So I wrote a
Ruby library for &lt;a href="http://developers.bol.com"&gt;the Bol.com &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The bol.com &lt;span class="caps"&gt;API&lt;/span&gt; allows you to fetch detailed information for common products,
such as books, DVDs and toys, search for products by keyword, or list
bestsellers. The &lt;span class="caps"&gt;API&lt;/span&gt; is not too complex: it’s just a handful of endpoints, a
couple of available query parameters and a request signature. &lt;/p&gt;

&lt;p&gt;I built a wrapper around this &lt;span class="caps"&gt;API&lt;/span&gt; that exposes the available operations and
handles the difficult parts of request signing and &lt;span class="caps"&gt;XML&lt;/span&gt; parsing. All you, as the
developer, have to do is provide the access credentials. All operations give
you nice, clean Ruby objects back, such as a &lt;code&gt;Bol::Product&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;

&lt;p&gt;You need to &lt;a href="https://developers.bol.com/inloggen/?action=register"&gt;sign up for a developer account&lt;/a&gt; first. When your account
has been approved, you can request an &lt;span class="caps"&gt;API&lt;/span&gt; key. The key has two parts – one
public, one secret – that will be used by bol.com to make sure you really are
who you say you are when you make a request.&lt;/p&gt;

&lt;p&gt;Once you have both your access key and its secret, you can get started by
installing the Ruby gem:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ gem install bol
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="an-example-application"&gt;An example application&lt;/h2&gt;

&lt;p&gt;Let’s create a very simple Sinatra application to search the bol.com store (see
&lt;a href="https://gist.github.com/1724664"&gt;the completed app in one file&lt;/a&gt;). Create an application file &lt;code&gt;app.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;sinatra&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;

get &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  erb &lt;span class="sy"&gt;:search&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Add a simple form view:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-html"&gt;&lt;span class="ta"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="an"&gt;method&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;action&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;/search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="ta"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Query: &lt;span class="ta"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="an"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;name&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;q&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
  &lt;span class="ta"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="an"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="ta"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Run the app to confirm everything works:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ruby -rubygems app.rb
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you browse to &lt;code&gt;http://localhost:4567&lt;/code&gt; you can see the search page, but it
doesn’t do anything yet. Let’s add a search action:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;post &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;/search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  &lt;span class="iv"&gt;@products&lt;/span&gt; = []
  erb &lt;span class="sy"&gt;:results&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And a view to display results:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-rhtml"&gt;&lt;span class="ta"&gt;&amp;lt;ol&amp;gt;&lt;/span&gt;
&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="iv"&gt;@products&lt;/span&gt;.each &lt;span class="r"&gt;do&lt;/span&gt; |product| &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="ta"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; product.title &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="ta"&gt;&amp;lt;/ol&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="implementing-search"&gt;Implementing search&lt;/h2&gt;

&lt;p&gt;We’ve added a &lt;code&gt;/search&lt;/code&gt; route that will somehow set an array of products, and
then render them to an ordered list on the page. Simple enough. Now to actually
search some products:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;post &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;/search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  &lt;span class="iv"&gt;@products&lt;/span&gt; = &lt;span class="co"&gt;Bol&lt;/span&gt;.search params[&lt;span class="sy"&gt;:q&lt;/span&gt;]      
  erb &lt;span class="sy"&gt;:results&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Searching the bol.com website is as easy as &lt;code&gt;Bol.search(params[:q])&lt;/code&gt;. Restart
the app, and try it out. You will get an error, complaining that the gem is not
properly configured. We need to provide our access key and its secret, so they
can be used to sign our requests:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;span class="co"&gt;Bol&lt;/span&gt;.configure &lt;span class="r"&gt;do&lt;/span&gt; |c|
  c.access_key = &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;123456789&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
  c.secret     = &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;abcdefghi&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you restart the application, you should be able to search bol.com by
keyword and get a list of titles back. &lt;/p&gt;

&lt;h2 id="showing-product-details"&gt;Showing product details&lt;/h2&gt;

&lt;p&gt;Let’s go one step further and add some product details. We’ll create a new
route for that:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;get &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;/product/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  &lt;span class="iv"&gt;@product&lt;/span&gt; = &lt;span class="co"&gt;Bol&lt;/span&gt;::&lt;span class="co"&gt;Product&lt;/span&gt;.find params[&lt;span class="sy"&gt;:id&lt;/span&gt;]
  erb &lt;span class="sy"&gt;:product&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can use &lt;code&gt;Product#find&lt;/code&gt; to find a particular product on bol.com by its
internal &lt;span class="caps"&gt;ID.&lt;/span&gt; We’ll create a link to the detail page in our search results:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-rhtml"&gt;&lt;span class="ta"&gt;&amp;lt;ol&amp;gt;&lt;/span&gt;
&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="iv"&gt;@products&lt;/span&gt;.each &lt;span class="r"&gt;do&lt;/span&gt; |product| &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="ta"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
    &lt;span class="ta"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="an"&gt;href&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;/product/&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; product.id &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; product.title &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="ta"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class="ta"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="ta"&gt;&amp;lt;/ol&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We also need a view for our new action:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-rhtml"&gt;&lt;span class="ta"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="iv"&gt;@product&lt;/span&gt;.title &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="ta"&gt;&amp;lt;dl&amp;gt;&lt;/span&gt;
  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="iv"&gt;@product&lt;/span&gt;.attributes.each_pair &lt;span class="r"&gt;do&lt;/span&gt; |k, v| &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="ta"&gt;&amp;lt;dt&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; k &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/dt&amp;gt;&lt;/span&gt;
  &lt;span class="ta"&gt;&amp;lt;dd&amp;gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;pre&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; v &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/pre&amp;gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/dd&amp;gt;&lt;/span&gt;
  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="ta"&gt;&amp;lt;/dl&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Restart the app, perform a search and click on a result. You should see all
available product details. Note that there are several sizes of cover image
available, and that the &lt;code&gt;author&lt;/code&gt; attribute is an &lt;code&gt;Array&lt;/code&gt; – there can be more
than one, after all.&lt;/p&gt;

&lt;h2 id="scoping-search-results-to-categories"&gt;Scoping search results to categories&lt;/h2&gt;

&lt;p&gt;Now we want to limit our search results to a particular category of products.
Bol.com products are extensively categorized and we can look up those
categories and search in them. Let’s add a drop-down list of categories to
search to our search form:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;get &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  &lt;span class="iv"&gt;@categories&lt;/span&gt; = &lt;span class="co"&gt;Bol&lt;/span&gt;.categories
  erb &lt;span class="sy"&gt;:search&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;

post &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;/search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;
  &lt;span class="iv"&gt;@products&lt;/span&gt; = &lt;span class="co"&gt;Bol&lt;/span&gt;::&lt;span class="co"&gt;Scope&lt;/span&gt;.new(params[&lt;span class="sy"&gt;:category_id&lt;/span&gt;])
    .search params[&lt;span class="sy"&gt;:q&lt;/span&gt;]      
  erb &lt;span class="sy"&gt;:results&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And in the view:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-rhtml"&gt;&lt;span class="ta"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="an"&gt;method&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;action&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;/search&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="ta"&gt;&amp;lt;select&lt;/span&gt; &lt;span class="an"&gt;name&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;category_id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="iv"&gt;@categories&lt;/span&gt;.each &lt;span class="r"&gt;do&lt;/span&gt; |category| &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class="ta"&gt;&amp;lt;option&lt;/span&gt; &lt;span class="an"&gt;value&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; category.id &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; category.name &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt; (&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; category.count &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;)
    &lt;span class="ta"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
    &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="ta"&gt;&amp;lt;/select&amp;gt;&lt;/span&gt;
  &lt;span class="ta"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="an"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;name&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;q&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="ta"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="an"&gt;type&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="ta"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once we’ve reloaded the application, we can choose a category to search in and
get results limited to that category. Categories are nested, so you can get
subcategories using &lt;code&gt;Bol::Scope.new(some_id).categories&lt;/code&gt;. And there are also
&lt;em&gt;refinements&lt;/em&gt;, such as groupings by price or brand and other attributes, but
they work similarly to categories.&lt;/p&gt;

&lt;h2 id="referral-links"&gt;Referral links&lt;/h2&gt;

&lt;p&gt;Then only referral links remain. It is a good idea to link to
products on bol.com, so you can get a kickback on any sales
resulting from the traffic you send over. This is not strictly a
feature of the developer &lt;span class="caps"&gt;API&lt;/span&gt;, but it is so commonly used, I just
threw it in here. You can simply ask a product for its referral
&lt;span class="caps"&gt;URL&lt;/span&gt;, given a specific referral &lt;span class="caps"&gt;ID&lt;/span&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;product = &lt;span class="co"&gt;Bol&lt;/span&gt;.find(params[&lt;span class="sy"&gt;:id&lt;/span&gt;])
product.referral_link(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;my-site-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)
&lt;span class="c"&gt;# =&amp;gt; "http://..."&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="other-features"&gt;Other features&lt;/h2&gt;

&lt;p&gt;This example application showcases the basics of the bol gem, but it includes
some more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ordering and limiting of number of results&lt;/li&gt;
  &lt;li&gt;Automatic pagination&lt;/li&gt;
  &lt;li&gt;Joining and subtracting categories and refinements to create complex scopes&lt;/li&gt;
  &lt;li&gt;List popular or bestselling products&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;See the project &lt;a href="https://github.com/avdgaag/bol"&gt;README&lt;/a&gt; file for more information.&lt;/p&gt;

&lt;h2 id="example-application-and-source-code"&gt;Example application and source code&lt;/h2&gt;

&lt;p&gt;That’s all you need to know to get started. You can see the entire &lt;a href="https://gist.github.com/1724664"&gt;example
application&lt;/a&gt; in &lt;a href="https://gist.github.com/1724664"&gt;this gist&lt;/a&gt;. You can find &lt;a href="https://github.com/avdgaag/bol"&gt;the source for this Ruby gem
on Github&lt;/a&gt;, where I also keep the &lt;span class="caps"&gt;API&lt;/span&gt; documentation and track issues. The
gem is still in beta stage, so it can be field-tested before getting an actual
stamp-of-approval by releasing a version &lt;span class="caps"&gt;1.0.&lt;/span&gt; Try it out and do let me know if
you make anything awesome with it!&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:arjanvandergaag.nl,2012-01-19:/blog/shell-scripting.html</id>
    <title type="html">Shell scripting to the rescue</title>
    <published>2012-01-19T19:00:00Z</published>
    <updated>2012-01-19T19:00:00Z</updated>
    <link rel="alternate" href="/"/>
    <content type="html">&lt;p class="leader"&gt;I love &lt;a href="http://ruby-lang.org"&gt;Ruby&lt;/a&gt; and tend to use it for everything I &lt;em&gt;can&lt;/em&gt; use it for. But
I’ve &lt;a href="http://www.amazon.co.uk/gp/product/0596003307/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=arjanvandergaag-21&amp;amp;linkCode=as2&amp;amp;camp=1634&amp;amp;creative=19450&amp;amp;creativeASIN=0596003307"&gt;reading up on Unix&lt;/a&gt; recently, and I decided to test my newfound
knowledge by using standard unix programs to solve a problem. Those who do not
know Unix are doomed to re-implement it badly (or so I have been told).&lt;/p&gt;

&lt;p&gt;I needed to copy a lot of images from a remote server to my local machine.
Since images were constantly being added to the remote server, I wanted to have
a repeatable script to download only those images that were listed in a &lt;span class="caps"&gt;YAML&lt;/span&gt;
file from another application. So I needed to read the &lt;span class="caps"&gt;YAML&lt;/span&gt; file, find the
files listed inside it, and collect those in an archive for easy downloading.&lt;/p&gt;

&lt;h2 id="reading-input"&gt;01. Reading input&lt;/h2&gt;

&lt;p&gt;My input file was in &lt;span class="caps"&gt;YAML&lt;/span&gt;, so the first step is reading that. But since the
file is several thousand lines long, we pipe it into head to just print the
first few lines:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cat images.yml | head
---
- http://host.tld/images/image1.jpg
- http://host.tld/images/image2.jpg
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first problem was the first line of three dashes, which I needed to get rid
of. Using &lt;code&gt;sed&lt;/code&gt; you can actually issue &lt;code&gt;ex&lt;/code&gt; commands like in Vim, so this was
easy:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cat images.yml | sed '1d' | head
- http://host.tld/images/image1.jpg
- http://host.tld/images/image2.jpg
- http://flickr.com/images/image3.jpg
...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This deletes line one, but there’s a saying along the lines of: “if you &lt;code&gt;cat&lt;/code&gt; a
file and immediately pipe it into something else, something’s wrong”. So, I
rewrote it like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sed 'd' images.yml | head
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="parsing-yaml"&gt;02. “Parsing” &lt;span class="caps"&gt;YAML&lt;/span&gt;
&lt;/h2&gt;

&lt;p&gt;Then, I needed to get rid of the &lt;span class="caps"&gt;YAML&lt;/span&gt; array element indicators – the dashes
starting each line. I could have used &lt;code&gt;sed&lt;/code&gt; for that, but I chose &lt;code&gt;cut&lt;/code&gt;, which
extracts fields from a line, splitting the line on a given delimited into
columns. I wanted the second column with a space as delimiter:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sed 'd' images.yml | cut -d' ' -f 2 | head
http://host.tld/images/image1.jpg
http://host.tld/images/image2.jpg
http://flickr.com/images/image3.jpg
…
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This was starting to look useful. &lt;/p&gt;

&lt;h2 id="getting-just-the-image-path"&gt;03. Getting just the image path&lt;/h2&gt;

&lt;p&gt;There was a problem with the images: all images contained the full &lt;span class="caps"&gt;URL&lt;/span&gt;, and I
wanted to get just the path. &lt;code&gt;sed&lt;/code&gt; to the rescue, again:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sed 'd' images.yml | \
  cut -d' ' -f 2 | \
  sed 's|http://host.tld/||' |\
  head
images/image1.jpg
images/image2.jpg
http://flickr.com/images/image3.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This time, I used a replacement pattern as we would in Vim, only replacing the
standard &lt;code&gt;/&lt;/code&gt; separator with a &lt;code&gt;|&lt;/code&gt; to not have to escape every &lt;code&gt;/&lt;/code&gt; in the search
string.&lt;/p&gt;

&lt;h2 id="getting-rid-of-externally-hosted-images"&gt;04. Getting rid of externally hosted images&lt;/h2&gt;

&lt;p&gt;This left the problem of externally hosted images. I just gave up on those.
Getting rid of those sounded like a task for &lt;code&gt;grep&lt;/code&gt;, which can be used to
&lt;em&gt;exclude&lt;/em&gt; lines matching a pattern:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sed 'd' images.yml | \
  cut -d' ' -f 2 | \
  sed 's|http://host.tld/||' |\
  grep -v "flickr" |\
  head
images/image1.jpg
images/image2.jpg
http://amazon.com/images/image4.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gives a new problem: there are several different external hosts in the
file. I only wanted our own. I decided to rewrite the command and use &lt;code&gt;grep&lt;/code&gt; to
filter out all lines that &lt;em&gt;do&lt;/em&gt; contain our own host, and &lt;em&gt;then&lt;/em&gt; remove the
domain:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sed 'd' images.yml | \
  cut -d' ' -f 2 | \
  grep "http://host.tld" |\
  sed 's|http://host.tld/||' |\
  head
images/image1.jpg
images/image2.jpg
images/image5.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="combining-files-into-an-archive"&gt;05. Combining files into an archive&lt;/h2&gt;

&lt;p&gt;The next task was to zip up all those files into one big archive for easy
downloading from the server to my local machine.&lt;/p&gt;

&lt;p&gt;The first idea was to just dump the whole lot into &lt;code&gt;zip&lt;/code&gt;, like so:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sed 'd' images.yml | \
  cut -d' ' -f 2 | \
  grep "http://host.tld" |\
  sed 's|http://host.tld/||' |\
  zip dump.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Alas, that doesn’t work. I started investigating possible solutions, such as
using &lt;code&gt;xargs&lt;/code&gt; – which mashes a bunch of lines into a single line and feed them
as arguments to another program, with some intelligence about the number of
arguments a program accepts. After some fiddling, I got frustrated that &lt;code&gt;zip&lt;/code&gt;
just didn’t read filenames from standard input, so I &lt;em&gt;finally&lt;/em&gt; decided to open
the &lt;code&gt;zip&lt;/code&gt; manual with &lt;code&gt;man zip&lt;/code&gt;. Searching the manual for &lt;code&gt;stdin&lt;/code&gt;, I found out
&lt;code&gt;zip&lt;/code&gt; indeed does not read input filenames from standard input by default, but
On Mac &lt;span class="caps"&gt;OS&lt;/span&gt; X, there’s the &lt;code&gt;--names-stdin&lt;/code&gt; option, while on most other systems
there’s &lt;code&gt;-@&lt;/code&gt;. There you go, it pays to &lt;abbr title="Read The Fucking Manual"&gt;RTFM&lt;/abbr&gt;.&lt;/p&gt;

&lt;p&gt;So, the entire command now looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sed 'd' images.yml | \
  cut -d' ' -f 2 | \
  grep "http://host.tld" |\
  sed 's|http://host.tld/||' |\
  zip dump.zip -@
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This does what I wanted it to do quite nicely, but I figured I could do
slightly better.&lt;/p&gt;

&lt;h2 id="duplicates-and-thumbnails"&gt;06. Duplicates and thumbnails&lt;/h2&gt;

&lt;p&gt;One problem was a lot of duplicate images; another was lots of different sizes
of the same image – with the original one the only I care about.&lt;/p&gt;

&lt;p&gt;Solving duplicates is easy enough using the &lt;code&gt;uniq&lt;/code&gt; program:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sed 'd' images.yml | \
  cut -d' ' -f 2 | \
  grep "http://host.tld" |\
  sed 's|http://host.tld/||' |\
  uniq |\
  zip dump.zip -@
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, I want to only use the original image, not the generated thumbnails. I
happened to know that generated thumbnails have filenames like
&lt;code&gt;original-filename-150x75.jpg&lt;/code&gt;. Removing the dimensions at the end of the
filename would give me the regular file. My list could very well contain that
original file already, but &lt;code&gt;uniq&lt;/code&gt; would sort that out. So, there’s one more
&lt;code&gt;sed&lt;/code&gt; to add:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sed 'd' images.yml | \
  cut -d' ' -f 2 | \
  grep "http://host.tld" |\
  sed 's|http://host.tld/||' |\
  sed 's/-\d+x\d+\.jpg/.jpg/' |\
  uniq |\
  zip -9 dump.zip -@
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That gave me a dump archive file containing all my images. As I was happy with
the result, I tacked on a &lt;code&gt;-9&lt;/code&gt; to enable maximum compression for the archive,
shaving a couple of percentage points of the end result file size.&lt;/p&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;This post might seem long, but the process of developing this command chain was
actually rather quick. Feedback is almost instant and there’s a rich collection
of tools to get the job done. I’m pretty sure developing a Ruby script doing
the same thing would have involved more manual tweaking and looking up
documentation.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:arjanvandergaag.nl,2012-01-13:/blog/generating-fancy-routes-with-rails.html</id>
    <title type="html">Generating fancy URLs with Rails</title>
    <published>2012-01-13T19:00:00Z</published>
    <updated>2012-01-13T19:00:00Z</updated>
    <link rel="alternate" href="/"/>
    <content type="html">&lt;p class="leader"&gt;There’s a problem with Rails resourceful routes. It is very easy to generate standard resourceful routes; it is equally easy to match incoming fancy URLs. But DRYly generating fancy URLs is a lot harder than suspected.&lt;/p&gt;

&lt;p&gt;Matching fancy &lt;em&gt;incoming&lt;/em&gt; routes is easy enough:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;get &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;/posts/:year/:month/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;posts#show&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our application will now correctly match URLs like &lt;code&gt;/posts/2011/3/1-hello-world&lt;/code&gt;, but see what happens when we try to generate a polymorphic route:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;link_to(post.title, post)
&lt;span class="c"&gt;# =&amp;gt; &amp;lt;a href="/posts/1"&amp;gt;hello, world&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is &lt;em&gt;not&lt;/em&gt; what we want. Of course, we could set &lt;code&gt;:year&lt;/code&gt; and &lt;code&gt;:month&lt;/code&gt; parameters manually, but that’s not very &lt;span class="caps"&gt;DRY.&lt;/span&gt; We could also try to override the &lt;code&gt;post_url&lt;/code&gt; and &lt;code&gt;post_path&lt;/code&gt; methods, but  this does not cover all use cases.&lt;/p&gt;

&lt;h2 id="hypothetical-solution"&gt;Hypothetical solution&lt;/h2&gt;

&lt;p&gt;Ideally, we would like to return a hash of parameters for the &lt;code&gt;to_param&lt;/code&gt; method:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Post&lt;/span&gt;
  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;to_param&lt;/span&gt;
    { &lt;span class="ke"&gt;year&lt;/span&gt;: created_at.year,
      &lt;span class="ke"&gt;month&lt;/span&gt;: created_at.month,
      &lt;span class="ke"&gt;id&lt;/span&gt;: id }
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Rails would then have to interpolate these params into the generated &lt;span class="caps"&gt;URL.&lt;/span&gt; Alas, this doesn’t work.&lt;/p&gt;

&lt;h2 id="actual-hacky-solution"&gt;Actual, hacky solution&lt;/h2&gt;

&lt;p&gt;We can hack around it, tough, by overriding &lt;code&gt;url_for&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;url_for&lt;/span&gt;(options = {})
    obj = options[&lt;span class="sy"&gt;:_positional_args&lt;/span&gt;][&lt;span class="i"&gt;0&lt;/span&gt;]
    &lt;span class="r"&gt;if&lt;/span&gt; obj === &lt;span class="co"&gt;Post&lt;/span&gt;
      options[&lt;span class="sy"&gt;:_positional_keys&lt;/span&gt;] = [
        obj.year,
        obj.month,
        obj
      ]
    &lt;span class="r"&gt;end&lt;/span&gt;
    &lt;span class="r"&gt;super&lt;/span&gt;(options)
  &lt;span class="r"&gt;end&lt;/span&gt;
  helper_method &lt;span class="sy"&gt;:url_for&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This works fine for the most part – despite being a terrible hack. The &lt;code&gt;helper_method :url_for&lt;/code&gt; line does, however, override &lt;code&gt;ActionView&lt;/code&gt;’s normal behaviour of generating only paths instead of full URLs. To get around this, we can create a new helper method that uses the controller method:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;span class="r"&gt;module&lt;/span&gt; &lt;span class="cl"&gt;ApplicationHelper&lt;/span&gt;
  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;url_for&lt;/span&gt;(options = {})
    &lt;span class="r"&gt;return&lt;/span&gt; &lt;span class="r"&gt;super&lt;/span&gt; &lt;span class="r"&gt;unless&lt;/span&gt; options.is_a? &lt;span class="co"&gt;Hash&lt;/span&gt;
    controller.url_for(
      options.reverse_merge(&lt;span class="ke"&gt;only_path&lt;/span&gt;: &lt;span class="pc"&gt;true&lt;/span&gt;)
    )
  &lt;span class="r"&gt;end&lt;/span&gt;
&lt;span class="r"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now all URLs are properly generated:&lt;/p&gt;

&lt;pre&gt;&lt;code class="language-ruby"&gt;link_to post.title, post
&lt;span class="c"&gt;# =&amp;gt; &amp;lt;a href="/2011/2/1-hello,world"&amp;gt;Hello, world&amp;lt;/a&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="a-note-of-warning"&gt;A note of warning&lt;/h2&gt;

&lt;p&gt;The code in these examples is extremely simplified. Being a hack, you need to add some proper checks for argument types and the contents of the &lt;code&gt;:_positional_args&lt;/code&gt; and &lt;code&gt;:_positional_keys&lt;/code&gt; options. Also, you can probably not depend on this behaviour remaining on subsequent versions of Rails. But it still just might come in useful some time…&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:arjanvandergaag.nl,2011-12-23:/blog/customize-zsh-prompt-with-vcs-info.html</id>
    <title type="html">Customize your ZSH prompt with vcs_info</title>
    <published>2011-12-23T07:00:00Z</published>
    <updated>2011-12-23T07:00:00Z</updated>
    <link rel="alternate" href="/"/>
    <content type="html">&lt;p class="leader"&gt;You’re not cool if you’re don’t display some Git status information in your prompt. If you use &lt;a href="http://www.zsh.org"&gt;ZSH&lt;/a&gt; – and you &lt;em&gt;should&lt;/em&gt; – it’s quite easy to customize your prompt. &lt;span class="caps"&gt;ZSH&lt;/span&gt; comes with a nice package &lt;a href="http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#Version-Control-Information"&gt;&lt;code&gt;vcs_info&lt;/code&gt;&lt;/a&gt; that provides almost all the information you need.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vcs_info&lt;/code&gt; is a function that populates a variable for you. This variable can then be used inside your prompt to print information. What information is printed can be controlled by some configurations – which are essentially format strings.&lt;/p&gt;

&lt;h2 id="set-up"&gt;Set up&lt;/h2&gt;

&lt;p&gt;Assuming you are using &lt;span class="caps"&gt;ZSH&lt;/span&gt;, setting things up is easy enough:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable &lt;code&gt;vcs_info&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Call it in a pre-command.&lt;/li&gt;
  &lt;li&gt;Include the variable in your prompt.&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;To do so, modify your &lt;code&gt;~/.zshrc&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;autoload -Uz vcs_info
zstyle ':vcs_info:*' enable git svn
precmd() {
    vcs_info
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, include the output variable in your prompt:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;setopt prompt_subst
PROMPT='${vcs_info_msg_0_}%# '
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This example is a rather minimalist prompt, so make sure you customize it with additional information.&lt;/p&gt;

&lt;h2 id="configuring-vcsinfo"&gt;Configuring &lt;code&gt;vcs_info&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;There’s not too much documentation on &lt;code&gt;vcs_info&lt;/code&gt; available, but &lt;a href="http://zsh.sourceforge.net/Doc/Release/User-Contributions.html#Version-Control-Information"&gt;the official docs&lt;/a&gt; got enough to get you going. The defaults should be fine, but we wouldn’t be using &lt;span class="caps"&gt;ZSH&lt;/span&gt; and reading articles about &lt;code&gt;vcs_info&lt;/code&gt; if we were satisfied with defaults, would we?&lt;/p&gt;

&lt;h3 id="format-string"&gt;Format string&lt;/h3&gt;

&lt;p&gt;First, set the general format string of your &lt;code&gt;vcs_info_msg_0&lt;/code&gt; variable:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zstyle ':vcs_info:git*' formats "%{$fg[grey]%}%s %{$reset_color%}%r/%S%{$fg[grey]%} %{$fg[blue]%}%b%{$reset_color%}%m%u%c%{$reset_color%} "
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is, admittedly, a little hairy. Let’s remove the color codes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zstyle ':vcs_info:git*' formats "%s  %r/%S %b %m%u%c% "
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s a lot clearer. This would look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git my_project/. master %
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This prompt includes:&lt;/p&gt;

&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;%s&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;The current version control system, like &lt;code&gt;git&lt;/code&gt; or &lt;code&gt;svn&lt;/code&gt;.&lt;/dd&gt;
  &lt;dt&gt;&lt;code&gt;%r&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;The name of the root directory of the repository&lt;/dd&gt;
  &lt;dt&gt;&lt;code&gt;%S&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;The current path relative to the repository root directory&lt;/dd&gt;
  &lt;dt&gt;&lt;code&gt;%b&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;Branch information, like &lt;code&gt;master&lt;/code&gt;
&lt;/dd&gt;
  &lt;dt&gt;&lt;code&gt;%m&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;In case of Git, show information about stashes&lt;/dd&gt;
  &lt;dt&gt;&lt;code&gt;%u&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;Show unchanged changes in the repository&lt;/dd&gt;
  &lt;dt&gt;&lt;code&gt;%c&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;Show staged changes in the repository&lt;/dd&gt;
&lt;/dl&gt;&lt;p&gt;There’s a special format string for ‘actions’ – which in practice means a special format for when Git is currently performing a merge or rebase. Mine is identical to the normal format, but with the action string added:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zstyle ':vcs_info:git*' formats "%s  %r/%S %b (%a) %m%u%c% "
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Which would result in something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git my_project/. master (rebase) %
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is all I need, although some people do write their own functions to display how many commits the current branch is ahead or behind its remote. Knock yourself out if you’re so inclined.&lt;/p&gt;

&lt;h3 id="flags"&gt;Flags&lt;/h3&gt;

&lt;p&gt;There are also a couple of flags you can set to influence the &lt;code&gt;vcs_info&lt;/code&gt;’s behaviour:&lt;/p&gt;

&lt;dl&gt;
&lt;dt&gt;&lt;code&gt;check-for-changes&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;Disabled by default because it might slow things down, it tell the back-end to check for working-copy changes and staged changes. Enable it with &lt;code&gt;zstyle ':vcs_info:*' check-for-changes true&lt;/code&gt; if you want to use the &lt;code&gt;%c&lt;/code&gt; and &lt;code&gt;%u&lt;/code&gt; sequences.&lt;/dd&gt;
  &lt;dt&gt;&lt;code&gt;enable&lt;/code&gt;&lt;/dt&gt;
  &lt;dd&gt;List the versioning systems to enable. In the example above, I have enable Git and Subversion, but there’s many more – notably Mercurial.&lt;/dd&gt;
&lt;/dl&gt;&lt;p&gt;The &lt;code&gt;vcs_info&lt;/code&gt; format string, especially with lots of color codes, is not all that readable, but I nonetheless prefer using a &lt;span class="caps"&gt;ZSH&lt;/span&gt; library over hacking together my own functions that parse the output of various Git commands.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:arjanvandergaag.nl,2011-12-06:/blog/clarify-git-history-with-merge-commits.html</id>
    <title type="html">Clarify your Git history with merge commits</title>
    <published>2011-12-06T19:00:00Z</published>
    <updated>2011-12-06T19:00:00Z</updated>
    <link rel="alternate" href="/"/>
    <content type="html">&lt;p class="leader"&gt;The Git history is supposed to help you understand what has happened over time
in your project. In practice, &lt;em&gt;how&lt;/em&gt; stuff happened tends to obscure &lt;em&gt;what&lt;/em&gt;
happened. Here are two tips for Git merges to help keep your history clean.&lt;/p&gt;

&lt;h2 id="do-not-create-redundant-merge-commits"&gt;Do not create redundant merge commits&lt;/h2&gt;

&lt;p&gt;Suppose you are working on a branch with a colleague, be it &lt;code&gt;master&lt;/code&gt; or some
feature branch. You make some commits in your local repository:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;O [master, HEAD] Added comments to post
O Added comment model
O [origin/master] Created post model
O Initial commit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Your colleague has also made some in his local repository, and pushed them:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;O [origin/master, master] Added author to post
O Created user model
O Created post model
O Initial commit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When you want to push your changes, Git will reject the non-fast forward merge.
So you pull the remote changes, which will merge &lt;code&gt;origin/master&lt;/code&gt; into your
local &lt;code&gt;master&lt;/code&gt; branch. Although you can now safely push your changes, you end
up with the following history:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;O [origin/master, master, HEAD] Merge branch 'master' of remote-repo.git
|\
O | Added comments to post
O | Added comment model
| O  Added author to post
| O Created user model
|/
O Created post model
O Initial commit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This makes it seem there are two different branches of development here, while
actually this would have worked fine as a single linear history. This would
have been the result had Git used &lt;code&gt;rebase&lt;/code&gt; rather than &lt;code&gt;merge&lt;/code&gt; to combine the
remote and local commits. Simply use:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git pull --rebase
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;…and it shall be done. Here’s what happens under the hood:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;reset&lt;/code&gt; your &lt;code&gt;master&lt;/code&gt; branch back to &lt;code&gt;origin/master&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;
&lt;code&gt;fetch&lt;/code&gt; new commits from the remote &lt;code&gt;master&lt;/code&gt; branch&lt;/li&gt;
  &lt;li&gt;fast-forward &lt;code&gt;master&lt;/code&gt; to &lt;code&gt;origin/master&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;replay all your original commits on the new &lt;code&gt;master&lt;/code&gt; branch&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;This gives you:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;O [master, HEAD] Added comments to post
O Added comment model
O [origin/master] Added author to post
O Created user model
O Created post model
O Initial commit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So now you can safely &lt;code&gt;push&lt;/code&gt; your changes and be all in sync again. The history
now demonstrates all these commits were all part of a single feature.&lt;/p&gt;

&lt;p&gt;This behaviour is usually what you want to do, so you might want to make it
default:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git config branch.autosetuprebase always
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will ‘always’ set up remote tracking branches to pull using &lt;code&gt;--rebase&lt;/code&gt;.
There are more options though, so make sure to read the docs (&lt;code&gt;man git-config&lt;/code&gt;):&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;When never, rebase is never automatically set to true. When local, rebase
is set to true for tracked branches of other local branches. When remote,
rebase is set to true for tracked branches of remote-tracking branches.
When always, rebase will be set to true for all tracking branches.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id="do-create-redundant-merge-commits"&gt;Do create redundant merge commits&lt;/h2&gt;

&lt;p&gt;Usually, Git prefers to create a linear history, as usually that’s neat. But
when you develop your project with feature branches, and you want to look back
through your history to study what features are included, when and by whom, you
will have to start parsing a lot of commit dates, authors and log messages.&lt;/p&gt;

&lt;p&gt;Suppose the following history, where you have added commenting to a post model
in a feature branch called &lt;code&gt;comments&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;O [comments, HEAD] Added comments to post
O Added comment model
O [master] Added author to post
O Created user model
O Created post model
O Initial commit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You’re done and you want to merge the changes back into &lt;code&gt;master&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git checkout master
git merge comments
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will give you:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;O [comments, master, HEAD] Added comments to post
O Added comment model
O Added author to post
O Created user model
O Created post model
O Initial commit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Git figured out it only had to move the “master” pointer to point at the same
commit as “comments” does – a fast-forward merge. This is neat, but you lose
the information that the last two commits were a stand-alone feature. You want
to instruct Git to not perform a fast-forward merge, but create an explicit
merge commit:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git checkout master
git merge --no-ff comments
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gives you:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;O [master, HEAD] Merge branch 'comments'
|\
| O [comments] Added comments to post
| O Added comment model
|/
O Added author to post
O Created user model
O Created post model
O Initial commit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You could now remove the &lt;code&gt;comments&lt;/code&gt; branch (&lt;code&gt;git branch -d comments&lt;/code&gt;) and push
your commits.&lt;/p&gt;

&lt;p&gt;If you like the &lt;code&gt;--no-ff&lt;/code&gt; behaviour, you might want to configure Git (version
&lt;span class="caps"&gt;1.7.6&lt;/span&gt; and later) to use it by default (although I personally don’t do that):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git config --add merge.ff false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Although the end result is more noisy, it does convey useful information: both
that there was a group of related commits that constitute a feature; and what
it was named. You might even consider not immediately creating a commit, and
adjusting the commit message:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git checkout master
git merge --no-ff --no-commit comments
git commit -m "User story #4831: As\
a visitor I can comment on posts"
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Git merge commits can both clutter your history or help structure it. Create
them to indicate groups of related commits; omit them to avoid the illusion of
unrelated commits.&lt;/p&gt;</content>
  </entry>
</feed>

