<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Free PeepCode Blog</title>
  <generator uri="http://effectif.com/nesta">Nesta</generator>
  <id>tag:blog.peepcode.com,2009:/</id>
  <link href="http://blog.peepcode.com/articles.xml" rel="self"/>
  <link href="http://blog.peepcode.com" rel="alternate"/>
  <subtitle type="text">Short, Free Screencasts for Web Developers and Alpha Geeks</subtitle>
  <entry>
    <title>My Command Line Prompt</title>
    <link href="http://blog.peepcode.com/blog/2012/my-command-line-prompt" type="text/html" rel="alternate"/>
    <id>tag:blog.peepcode.com,2012-01-05:/blog/2012/my-command-line-prompt</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article is heavily styled and is best viewed at &lt;a href="http://blog.peepcode.com/blog/2012/my-command-line-prompt"&gt;PeepCode&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;&lt;div id='commandline'&gt;
  &lt;div class='row notations'&gt;
    &lt;div class='column'&gt;
      &lt;p id='by'&gt;
        by Geoffrey Grosenbach &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Paula Lavalle
      &lt;/p&gt;
      &lt;figure id='prompt'&gt;
        &lt;img alt='Command Line Prompt' height='325' src='my-command-line-prompt/img/prompt-with-arrows.png' width='940' /&gt;
        &lt;div class='notation' id='path'&gt;
          Current Path
          &lt;br /&gt;
          &lt;a href='#currentpath'&gt;More&lt;/a&gt;
        &lt;/div&gt;
        &lt;div class='notation' id='smiley'&gt;
          Last Command Status
          &lt;br /&gt;
          &lt;a href='#status'&gt;More&lt;/a&gt;
        &lt;/div&gt;
        &lt;div class='notation' id='scm-dirty'&gt;
          Uncommitted Git Changes
          &lt;br /&gt;
          &lt;a href='#gitbranch'&gt;More&lt;/a&gt;
        &lt;/div&gt;
        &lt;div class='notation' id='ruby'&gt;
          RVM Config
          &lt;br /&gt;
          &lt;a href='#rvmconfig'&gt;More&lt;/a&gt;
        &lt;/div&gt;
        &lt;div class='notation' id='git-status'&gt;
          Git Branch
          &lt;br /&gt;
          &lt;a href='#gitbranch'&gt;More&lt;/a&gt;
        &lt;/div&gt;
      &lt;/figure&gt;
      &lt;div id="buy"&gt;&lt;h2&gt;Advanced Git!&lt;/h2&gt;&lt;p class="small"&gt;One hour video.&lt;br /&gt;Only &lt;sup&gt;$&lt;/sup&gt;12!&amp;nbsp;&lt;a href="http://peepcode.com/products/advanced-git"&gt;More Info&amp;hellip;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div id='description'&gt;
  &lt;div class='row'&gt;
    &lt;div class='column'&gt;
      &lt;h2&gt;Your Command Line Dashboard&lt;/h2&gt;
      &lt;p&gt;In 10 years you&amp;#8217;ll probably be writing code in a different language, building web apps with a different framework, and wearing a different pair of underwear.&lt;/p&gt;
      &lt;p&gt;But the command line prompt you use today could still be serving you well.&lt;/p&gt;
      &lt;p&gt;Many of the elements of my command prompt were snitched from other developers (&lt;a href="https://github.com/chneukirchen"&gt;Christian Neukirchen&lt;/a&gt;, &lt;a href="https://github.com/freelancing-god"&gt;Pat Allan&lt;/a&gt;, and &lt;a href="https://github.com/benhoskings"&gt;Ben Hoskings&lt;/a&gt;). Here are my goals for my command prompt.&lt;/p&gt;
      &lt;h3&gt;Goals&lt;/h3&gt;
      &lt;ul&gt;
      	&lt;li&gt;&lt;strong&gt;Fast&lt;/strong&gt;: If I can tell there&amp;#8217;s a pause when I open a window or change directories, it&amp;#8217;s too slow.&lt;/li&gt;
      	&lt;li&gt;&lt;strong&gt;Terse&lt;/strong&gt;: Only show information that will change frequently between projects or between commands. If I always used the same version of Ruby, I would probably remove the Ruby version from my prompt.&lt;/li&gt;
      	&lt;li&gt;&lt;strong&gt;Mine&lt;/strong&gt;: I don&amp;#8217;t hesitate to customize a script that I copied from someone else. The prompt is not the place to worry about reusable or generalized code. It &lt;em&gt;should&lt;/em&gt; be easy to read and change when I need to.&lt;/li&gt;
      &lt;/ul&gt;
      &lt;h3&gt;Why &lt;span class="caps"&gt;ZSH&lt;/span&gt;?&lt;/h3&gt;
      &lt;p&gt;I switched to &lt;code&gt;zsh&lt;/code&gt; after receiving a one-on-one tutorial from &lt;a href="https://github.com/chneukirchen"&gt;Christian Neukirchen&lt;/a&gt;. It has some nice features:&lt;/p&gt;
      &lt;ul&gt;
      	&lt;li&gt;&lt;strong&gt;Separate prompt&lt;/strong&gt; for the right and left side of the screen.&lt;/li&gt;
      	&lt;li&gt;&lt;strong&gt;Inline completion&lt;/strong&gt; of directories, Git branch names, Rake task names, etc.&lt;/li&gt;
      	&lt;li&gt;&lt;strong&gt;Easy loop syntax&lt;/strong&gt;: &lt;code&gt;for f (`ls`) echo $f&lt;/code&gt;&lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;Try the source to a &lt;a href="https://github.com/topfunky/zsh-simple"&gt;simple version of my prompt on GitHub&lt;/a&gt;. Or read the explanation below and build your own.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='implement'&gt;
  &lt;div class='row'&gt;
    &lt;div class='column'&gt;
      &lt;h2&gt;
        Implementation
      &lt;/h2&gt;
      &lt;h3&gt;Setup&lt;/h3&gt;
      &lt;p&gt;The following configuration directives should be in &lt;code&gt;~/.zshrc&lt;/code&gt;. See the &lt;a href="https://github.com/topfunky/zsh-simple"&gt;full source&lt;/a&gt; for the complete setup.&lt;/p&gt;
      &lt;p&gt;Run these commands to load zsh&amp;#8217;s color variables. You&amp;#8217;ll be able to use readable values like &lt;code&gt;$fg[black]&lt;/code&gt; instead of cryptic ones like &lt;code&gt;\e[0m&lt;/code&gt;.&lt;/p&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# Colors&lt;/span&gt;&amp;#x000A;autoload -U colors&amp;#x000A;colors&amp;#x000A;setopt prompt_subst&lt;/pre&gt;&lt;/div&gt;
      &lt;a id='status'&gt;
        &lt;h3&gt;Last Command Status&lt;/h3&gt;
      &lt;/a&gt;
      &lt;p&gt;I first saw this technique in Pat Allan&amp;#8217;s shell. If the last command exited with a nonzero value, it will print a red Unicode frown: &lt;span style="color:red;"&gt;&#9785;&lt;/span&gt;. Successful commands will show a green smiley: &lt;span style="color:green;"&gt;&#9786;&lt;/span&gt;&lt;/p&gt;
      &lt;p&gt;It&amp;#8217;s a nice way to quickly see if tests failed or a compilation aborted.&lt;/p&gt;
      &lt;p&gt;And you&amp;#8217;re not limited to &lt;span class="caps"&gt;ASCII&lt;/span&gt;! Use the Unicode snowman, a skull and crossbones, or any other &lt;a href="http://en.wikipedia.org/wiki/Dingbat"&gt;dingbats character&lt;/a&gt;.&lt;/p&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# Save a smiley to a local variable if the last command exited with success.&lt;/span&gt;&amp;#x000A;&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;smiley&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%(?,%{$fg[green]%}&#9786;%{$reset_color%},%{$fg[red]%}&#9785;%{$reset_color%})&amp;quot;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;a id='currentpath'&gt;
        &lt;h3&gt;Current Path&lt;/h3&gt;
      &lt;/a&gt;
      &lt;p&gt;On my local machine I want to show only what&amp;#8217;s necessary. So I don&amp;#8217;t show the current user, hostname, or anything other than the relative path that I&amp;#8217;m currently in.&lt;/p&gt;
      &lt;p&gt;In zsh, that&amp;#8217;s &lt;code&gt;%~&lt;/code&gt;.&lt;/p&gt;
      &lt;p&gt;Assign it to &lt;code&gt;PROMPT&lt;/code&gt; to set the left-hand part of the prompt. It occupies two lines: the path is on one line and the previously saved &lt;code&gt;smiley&lt;/code&gt; is on the next. &lt;code&gt;$reset_color&lt;/code&gt; is a &lt;code&gt;zsh&lt;/code&gt; variable that restores your default text color.&lt;/p&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# Show the relative path on one line, then the smiley.&lt;/span&gt;&amp;#x000A;&lt;span class="nv"&gt;PROMPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&amp;#x000A;&lt;span class="s1"&gt;%~&lt;/span&gt;&amp;#x000A;&lt;span class="s1"&gt;${smiley}  %{$reset_color%}&amp;#39;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;a id='gitbranch'&gt;
        &lt;h3&gt;Git Branch, SHA &amp; Dirty Status&lt;/h3&gt;
      &lt;/a&gt;
      &lt;p&gt;It&amp;#8217;s surprisingly difficult to get Git to tell you what branch it&amp;#8217;s on. I&amp;#8217;ve tried several scripts, including the multi-&lt;span class="caps"&gt;SCM&lt;/span&gt; &lt;a href="http://vc.gerg.ca/hg/vcprompt/"&gt;vcprompt&lt;/a&gt; (which worked well).&lt;/p&gt;
      &lt;p&gt;My current favorite is a Ruby script that prints all kinds of useful information about your Git setup:&lt;/p&gt;
      &lt;ul&gt;
      	&lt;li&gt;&lt;strong&gt;Current branch name&lt;/strong&gt;&lt;/li&gt;
      	&lt;li&gt;&lt;strong&gt;The current &lt;span class="caps"&gt;SHA&lt;/span&gt;&lt;/strong&gt; (7 characters of it). Useful for anytime you need to get out of trouble with &lt;code&gt;git reset --hard&lt;/code&gt;. See the PeepCode &lt;a href="https://peepcode.com/products/advanced-git"&gt;Advanced Git&lt;/a&gt; video for this and other Git tips.&lt;/li&gt;
      	&lt;li&gt;&lt;strong&gt;Rebase status&lt;/strong&gt; (to know if you&amp;#8217;re in the middle of a rebase)&lt;/li&gt;
      	&lt;li&gt;&lt;strong&gt;Dirty status&lt;/strong&gt; Have any tracked files been edited? A Unicode &#10007; is displayed if changes have been made but not committed.&lt;/li&gt;
      &lt;/ul&gt;
      &lt;p&gt;The &lt;a href="https://github.com/benhoskings/dot-files/blob/master/files/bin/git_cwd_info"&gt;original script&lt;/a&gt; is from Ben Hoskings(requires Ruby 1.9). I edited it to work on Ruby 1.8 and used a brief &lt;code&gt;git-current-branch&lt;/code&gt; script (&lt;a href="https://github.com/topfunky/zsh-simple/blob/master/bin/git-cwd-info.rb"&gt;source&lt;/a&gt;). The relevant edit is on the last three lines where it specifies a format and colors for the final display.&lt;/p&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;RPROMPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%{$fg[white]%} $(~/.rvm/bin/rvm-prompt)$(~/bin/git-cwd-info.rb)%{$reset_color%}&amp;#39;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;p&gt;I chose to make the more important metadata stand out more. The Git branch name and dirty status are more important to me than the Ruby version or the current &lt;span class="caps"&gt;SHA&lt;/span&gt;, so they are a darker shade of grey. Ben uses an &lt;code&gt;@&lt;/code&gt; sign before the &lt;span class="caps"&gt;SHA&lt;/span&gt;, but I replaced it with whitespace.&lt;/p&gt;
      &lt;img src="/blog/2012/my-command-line-prompt/img/git-detail.png" alt="Ruby &amp;amp; Git metadata." title="Ruby &amp;amp; Git metadata." /&gt;&lt;p class="caption"&gt;Ruby &amp;amp; Git metadata.&lt;/p&gt;
      &lt;a id='rvmconfig'&gt;
        &lt;h3&gt;RVM Config&lt;/h3&gt;
      &lt;/a&gt;
      &lt;p&gt;The name of the current Ruby version as configured by &lt;acronym title="Ruby Version Manager"&gt;&lt;span class="caps"&gt;RVM&lt;/span&gt;&lt;/acronym&gt; is actually in the previous snippet. It calls &lt;code&gt;~/.rvm/bin/rvm-prompt&lt;/code&gt; and displays it at the left side of the right hand prompt.&lt;/p&gt;
      &lt;h2&gt;Put it Together&lt;/h2&gt;
      &lt;p&gt;The combined prompt looks like this.&lt;/p&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# Combined left and right prompt configuration.&lt;/span&gt;&amp;#x000A;&lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;smiley&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%(?,%{$fg[green]%}&#9786;%{$reset_color%},%{$fg[red]%}&#9785;%{$reset_color%})&amp;quot;&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="nv"&gt;PROMPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&amp;#x000A;&lt;span class="s1"&gt;%~&lt;/span&gt;&amp;#x000A;&lt;span class="s1"&gt;${smiley}  %{$reset_color%}&amp;#39;&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="nv"&gt;RPROMPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%{$fg[white]%} $(~/.rvm/bin/rvm-prompt)$(~/bin/git-cwd-info.rb)%{$reset_color%}&amp;#39;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;p&gt;The important thing is to customize your own prompt and make it work the way you want it to!&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div id='buyscreencast'&gt;
  &lt;div class='row'&gt;
    &lt;div class='column'&gt;
      &lt;h2&gt;
        Learn the command line, Git, and other great stuff!
      &lt;/h2&gt;
      &lt;p&gt;Check out our &lt;a href="https://peepcode.com/products/meet-the-command-line"&gt;Meet the Command Line&lt;/a&gt; and &lt;a href="https://peepcode.com/products/advanced-command-line"&gt;Advanced Command Line&lt;/a&gt; screencasts, plus our newest &lt;a href="http://peepcode.com/products/advanced-git"&gt;Advanced Git&lt;/a&gt; tutorial.&lt;/p&gt;
      &lt;div id="buy"&gt;&lt;h2&gt;Command Line&lt;/h2&gt;&lt;p class="small"&gt;Get started.&lt;br /&gt;Only &lt;sup&gt;$&lt;/sup&gt;12!&amp;nbsp;&lt;a href="http://peepcode.com/products/meet-the-command-line"&gt;More Info&amp;hellip;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;
      &lt;div id="buy"&gt;&lt;h2&gt;Adv Command&lt;/h2&gt;&lt;p class="small"&gt;Master it.&lt;br /&gt;Only &lt;sup&gt;$&lt;/sup&gt;12!&amp;nbsp;&lt;a href="http://peepcode.com/products/advanced-command-line"&gt;More Info&amp;hellip;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;
      &lt;div id="buy"&gt;&lt;h2&gt;Advanced Git&lt;/h2&gt;&lt;p class="small"&gt;One hour video.&lt;br /&gt;Only &lt;sup&gt;$&lt;/sup&gt;12!&amp;nbsp;&lt;a href="http://peepcode.com/products/advanced-git"&gt;More Info&amp;hellip;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</content>
    <published>Thu Jan 05 21:00:00 +0000 2012</published>
  </entry>
  <entry>
    <title>Geek Gift Guide 2011</title>
    <link href="http://blog.peepcode.com/blog/2011/geek-gift-guide-2011" type="text/html" rel="alternate"/>
    <id>tag:blog.peepcode.com,2011-12-13:/blog/2011/geek-gift-guide-2011</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article is heavily styled and is best viewed at &lt;a href="http://blog.peepcode.com/blog/2011/geek-gift-guide-2011"&gt;PeepCode&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;&lt;div id='geek-gift'&gt;
  &lt;div class='row'&gt;
    &lt;div class='column grid_12'&gt;
      &lt;p&gt;We&amp;#8217;ve all seen the geek gift guides put out by major publications. Somehow &lt;em&gt;all&lt;/em&gt; geeks, regardless of their connection to technology, like star wars legos, rubix cubes, and light-up keychains. Seriously? Not here. Not us.&lt;/p&gt;
      &lt;p&gt;Many geeks appreciate well-designed, thoughtful products. We know this because it&amp;#8217;s our bottom line. So here&amp;#8217;s our gift guide for classy geeks.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row'&gt;
    &lt;div class='column align-center'&gt;
      &lt;div class='price-range'&gt;
        &lt;div class='left-round-border'&gt;
          Filter:
        &lt;/div&gt;
        &lt;a class='active' href='#all'&gt;
          All
        &lt;/a&gt;
        &lt;a href='#1-20'&gt;&lt;sup&gt;$&lt;/sup&gt;1&#8211;20
        &lt;/a&gt;
        &lt;a href='#20-60'&gt;&lt;sup&gt;$&lt;/sup&gt;20&#8211;60
        &lt;/a&gt;
        &lt;a href='#60-100'&gt;&lt;sup&gt;$&lt;/sup&gt;60&#8211;100
        &lt;/a&gt;
        &lt;a href='#100-200'&gt;&lt;sup&gt;$&lt;/sup&gt;100&#8211;200
        &lt;/a&gt;
        &lt;a class='right-round-border' href='#200-800'&gt;&lt;sup&gt;$&lt;/sup&gt;200&#8211;800
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row gifts'&gt;
    &lt;div class='column grid_12'&gt;
      &lt;h2&gt;
        Gifts from
        &lt;a id='1-20'&gt;&lt;sup&gt;$&lt;/sup&gt;1-20
        &lt;/a&gt;
      &lt;/h2&gt;
    &lt;/div&gt;
    &lt;div class='column feature'&gt;
      &lt;a href='http://peepcode.com/gifts'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/peepcode-gift-single.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://peepcode.com/gifts'&gt;
          Single PeepCode Gift Card
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;12
        &lt;/span&gt;
        A single screencast for your developer friends or that up-and-coming youngster in your family who wants to get started with programming.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.amazon.com/Crowd-Complete-Season-One/dp/B001NOMOS8/'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/it-crowd.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.amazon.com/Crowd-Complete-Season-One/dp/B001NOMOS8/'&gt;
          The IT Crowd, Season 1
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;10
        &lt;/span&gt;
        Unfortunately, this is about stereotypical nerds. Fortunately, it&#8217;s awesomely hilarious.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='https://www.canoeonline.net/shop/inspect/worther-shorty-mechanical-pencil/2021'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/mechanical-pencil.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='https://www.canoeonline.net/shop/inspect/worther-shorty-mechanical-pencil/2021'&gt;
          Worther Shorty Mechanical Pencil
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;14
        &lt;/span&gt;
        Writing is much more fun with a beautiful pencil. Available in black, grey, or yellow.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='https://www.canoeonline.net/shop/inspect/field-notes-notebooks-state-fair-edition/2646'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/field-notes.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='https://www.canoeonline.net/shop/inspect/field-notes-notebooks-state-fair-edition/2646'&gt;
          Field Notes
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;10
        &lt;/span&gt;
        Now that smartphones have abandoned the stylus, there's nothing like paper and pen for brainstorming. Whether your field is a coffee shop or a bus, Field Notes are convenient and stylish.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.amazon.com/Wisdom-Crowds-James-Surowiecki/dp/0385721706/'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/wisdom-of-crowds.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.amazon.com/Wisdom-Crowds-James-Surowiecki/dp/0385721706/'&gt;
          The Wisdom of Crowds
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;11
        &lt;/span&gt;
        Both a classic and a quick read, this entertaining book is for entrepreneurs, sociologists, and deep thinkers of all kinds.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.theghostlystore.com/collections/goods/products/bluelounge-milo'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/milo.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.theghostlystore.com/collections/goods/products/bluelounge-milo'&gt;
          Milo
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;15
        &lt;/span&gt;
        An elegant stand for any smartphone with a smooth, hard surface.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='https://www.momastore.org/webapp/wcs/stores/servlet/ProductDisplay_Branch%20Earphone%20Splitter_10451_10001_111827_-1_26663_26666_111856'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/branch-splitter.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='https://www.momastore.org/webapp/wcs/stores/servlet/ProductDisplay_Branch%20Earphone%20Splitter_10451_10001_111827_-1_26663_26666_111856'&gt;
          Branch Earphone Splitter
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;10
        &lt;/span&gt;
        Split your music between three people. Useful for those cramped international plane flights to the next tech conference.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.surlatable.com/product/PRO-667766/Whisky-Stones,-Set-of-Nine'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/whisky-stones.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.surlatable.com/product/PRO-667766/Whisky-Stones,-Set-of-Nine'&gt;
          Whisky Stones
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;20
        &lt;/span&gt;
        These bad boys will keep your whisky chilled without watering it down? Oh, buddy.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.amazon.com/How-Booze-Exquisite-Cocktails-Unsound/dp/0061963305'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/how-to-booze.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.amazon.com/How-Booze-Exquisite-Cocktails-Unsound/dp/0061963305'&gt;
          How to Booze
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;20
        &lt;/span&gt;
        &lt;em&gt;Exquisite Cocktails and other Unsound Advice&lt;/em&gt; humorously suggests matching beverages for any social situation.
      &lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row gifts'&gt;
    &lt;div class='column grid_12'&gt;
      &lt;h2&gt;
        Gifts from
        &lt;a id='20-60'&gt;&lt;sup&gt;$&lt;/sup&gt;20-60
        &lt;/a&gt;
      &lt;/h2&gt;
    &lt;/div&gt;
    &lt;div class='column feature'&gt;
      &lt;a href='http://peepcode.com/gifts'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/peepcode-gift-5pack.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://peepcode.com/gifts'&gt;
          5-Pack Gift Card
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;55
        &lt;/span&gt;
        Give five screencasts to anyone, redeemable at any time.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://shop.peepcode.com/products/coffeescript-t-shirt'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/peepcodeshirt-coffeescript.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://shop.peepcode.com/products/coffeescript-t-shirt'&gt;
          CoffeeScript T-Shirt
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;26
        &lt;/span&gt;
        For that friend who loves CoffeeScript, or even just coffee.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://shop.peepcode.com/products/chris-wanstrath-t-shirt'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/peepcodeshirt-wanstrath.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://shop.peepcode.com/products/chris-wanstrath-t-shirt'&gt;
          Chris Wanstrath T-Shirt
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;26
        &lt;/span&gt;
        This one's a bit niche, but that's what makes the best gifts, right? A t-shirt featuring Chris Wanstrath, co-founder of GitHub.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.amazon.com/dp/B0042X8XQE/?tag=svpply01-20'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/powercup-mobile-inverter.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.amazon.com/dp/B0042X8XQE/?tag=svpply01-20'&gt;
          PowerCup Mobile Inverter
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;26
        &lt;/span&gt;
        Until Apple makes a power adapter for your car, this is the best way to stay energized on the road.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.mophie.com/product-p/2025_jpu-reserve-2.htm'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/juice-pack.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.mophie.com/product-p/2025_jpu-reserve-2.htm'&gt;
          Juice Pack Reserver
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;35
        &lt;/span&gt;
        We don't mind a keychain when it's this useful! Carry an extra charge for your portable Apple products.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.blessthisstuff.com/stuff/technology/computers/uboard-smart/'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/uboard-smart.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.blessthisstuff.com/stuff/technology/computers/uboard-smart/'&gt;
          UBoard Smart
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;49
        &lt;/span&gt;
        Keeping your desk orderly isn't quite as important as having a place for your phone, coffee, tea, and three USB devices.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.conranshop.co.uk/609968/MOSHI-MOSHI-POP-BLACK/Product'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/moshi-moshi-pop-black.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.conranshop.co.uk/609968/MOSHI-MOSHI-POP-BLACK/Product'&gt;
          MOSHI MOSHI Pop Black
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;40
        &lt;/span&gt;
        Make those serious business calls even more official. Also available in red, pink, green, and yellow.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.tortoisegeneralstore.com/online_store/index.php/by-category/crafts/braid-wood-puzzle.html'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/wood-puzzle.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.tortoisegeneralstore.com/online_store/index.php/by-category/crafts/braid-wood-puzzle.html'&gt;
          Braid Wood Puzzle
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;34
        &lt;/span&gt;
        A brain teaser in 6 or 12 pieces.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.lovescotch.com/p/pigs-nose-5-year-old'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/pigs-nose.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.lovescotch.com/p/pigs-nose-5-year-old'&gt;
          Pig's Nose 5 Year Scotch
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;44
        &lt;/span&gt;
        Not all scotch has to be serious. Recommended by our marketing department.
      &lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row gifts'&gt;
    &lt;div class='column grid_12'&gt;
      &lt;h2&gt;
        Gifts from
        &lt;a id='60-100'&gt;&lt;sup&gt;$&lt;/sup&gt;60-100
        &lt;/a&gt;
      &lt;/h2&gt;
    &lt;/div&gt;
    &lt;div class='column feature'&gt;
      &lt;a href='http://peepcode.com/gifts'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/peepcode-gift-10pack.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://peepcode.com/gifts'&gt;
          10-Pack Gift Card
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;99
        &lt;/span&gt;
        This gift won't collect dust in the bottom drawer!
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://coolmaterial.com/tech/wood-ipad-2-cases/'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/wood-case.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://coolmaterial.com/tech/wood-ipad-2-cases/'&gt;
          Wood iPad 2 Case
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;79
        &lt;/span&gt;
        Nothing goes together like machined aluminum and solid wood.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.etsy.com/listing/69589092/4-letter-pillows-inserts-included'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/scrabble-pillows.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.etsy.com/listing/69589092/4-letter-pillows-inserts-included'&gt;
          Four Scrabble Letter Pillows
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;98
        &lt;/span&gt;
        With letters in solid black felt.
      &lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row gifts'&gt;
    &lt;div class='column grid_12'&gt;
      &lt;h2&gt;
        Gifts from
        &lt;a id='100-200'&gt;&lt;sup&gt;$&lt;/sup&gt;100-200
        &lt;/a&gt;
      &lt;/h2&gt;
    &lt;/div&gt;
    &lt;div class='column feature'&gt;
      &lt;a href='http://peepcode.com/gifts'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/peepcode-gift-unlimited.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://peepcode.com/gifts'&gt;
          Unlimited Subscription Gift Card
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;199
        &lt;/span&gt;
        This one will keep a friend or family member occupied (and maybe even employed) until next year!
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://shop.creaturesofcomfort.us/yuetetrisl-shapepouch-red.aspx'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/tetris-pouch.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://shop.creaturesofcomfort.us/yuetetrisl-shapepouch-red.aspx'&gt;
          Tetris L-Shape Pouch
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;165
        &lt;/span&gt;
        "Extremely supple leather" and "lined in red velvet" should be all you need to know.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.unicahome.com/p23982/kikkerland/to-ca-wood-led-clock-by-kouji-iwasaki.html'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/wood-clock.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.unicahome.com/p23982/kikkerland/to-ca-wood-led-clock-by-kouji-iwasaki.html'&gt;
          To:Ca Wood LED Clock
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;150
        &lt;/span&gt;
        A natural contrast to all the stainless steel, titanium, and adamantium in your home.
      &lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row gifts'&gt;
    &lt;div class='column grid_12'&gt;
      &lt;h2&gt;
        Gifts from
        &lt;a id='200-800'&gt;&lt;sup&gt;$&lt;/sup&gt;200-800
        &lt;/a&gt;
      &lt;/h2&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.revo.co.uk/digital-radio/revo-heritage.php'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/heritage-radio.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.revo.co.uk/digital-radio/revo-heritage.php'&gt;
          Revo Renaissance Radio
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;357
        &lt;/span&gt;
        The ceiling of the Sistine Chapel may have turned out differently if Michaelangelo had access to thousands of Internet radio stations (plus a docking port).
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://store.apple.com/us/product/TX584ZM/A'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/bowers-wilkins-headphones.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://store.apple.com/us/product/TX584ZM/A'&gt;
          Bowers &amp; Wilkins P5 Headphones
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;300
        &lt;/span&gt;
        Soft and cushy on the ears, tiny for travel, beautiful looking, and noise isolating. Yes, yes, and yes.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.dwr.com/product/link-task-lamp-small.do'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/led-lamp.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.dwr.com/product/link-task-lamp-small.do'&gt;
          Link LED Task Lamp
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;350
        &lt;/span&gt;
        Move this guy anywhere. With 360&amp;deg; swivel, 15 high-power LED lights, and only 7.5 watts.
      &lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column item grid_6'&gt;
      &lt;a href='http://www.williams-sonoma.com/products/breville-espresso-machine-with-integrated-burr-grinder/'&gt;
        &lt;img src='geek-gift-guide-2011/imgs/espresso-maker.png' /&gt;
      &lt;/a&gt;
      &lt;p class='title'&gt;
        &lt;a href='http://www.williams-sonoma.com/products/breville-espresso-machine-with-integrated-burr-grinder/'&gt;
          Espresso Machine with Integrated Grinder
        &lt;/a&gt;
      &lt;/p&gt;
      &lt;p&gt;
        &lt;span class='price'&gt;&lt;sup&gt;$&lt;/sup&gt;800
        &lt;/span&gt;
        Run it on automatic for a cup in the morning and graduate to manual for an evening sip. An integrated grinder means maximum flavor every time.
      &lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div id='ribbons-bg'&gt;
  &amp;nbsp;
&lt;/div&gt;
</content>
    <published>Tue Dec 13 21:00:00 +0000 2011</published>
  </entry>
  <entry>
    <title>Free Ryan Singer UI Sketching Video</title>
    <link href="http://blog.peepcode.com/blog/2011/free-ryan-singer-ui-sketching-video" type="text/html" rel="alternate"/>
    <id>tag:blog.peepcode.com,2011-10-06:/blog/2011/free-ryan-singer-ui-sketching-video</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article is heavily styled and is best viewed at &lt;a href="http://blog.peepcode.com/blog/2011/free-ryan-singer-ui-sketching-video"&gt;PeepCode&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;&lt;div class='wrapper'&gt;
  &lt;div class='row'&gt;
    &lt;div class='column buy-above'&gt;
      &lt;a class='buttonify' href='http://peepcode.com/products/ryan-singer-ux'&gt;
        Read More &amp; Buy This Video
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='wrapper'&gt;
  &lt;div class='video'&gt;
&lt;iframe src="http://player.vimeo.com/video/30160052?title=0&amp;amp;byline=0&amp;amp;portrait=0&amp;amp;color=ffffff" width="1000" height="600" frameborder="0" webkitAllowFullScreen allowFullScreen&gt;&lt;/iframe&gt;

  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='wrapper'&gt;
  &lt;div class='row'&gt;
    &lt;div class='column article'&gt;
      &lt;h2&gt;
        Front-end Prototyping
      &lt;/h2&gt;
      &lt;p&gt;When we started the &lt;a href="https://peepcode.com/screencasts/play-by-play"&gt;Play by Play&lt;/a&gt; series, we wanted not only to learn how skilled back-end developers work, but also how front-end developers get work done.&lt;/p&gt;
      &lt;p&gt;Ryan Singer of 37signals was at the top of our list and he certainly delivered. We did an hour of &lt;a href="https://peepcode.com/products/ryan-singer-ux"&gt;sketching&lt;/a&gt; and an hour of &lt;a href="https://peepcode.com/products/ryan-singer-ii"&gt;prototyping&lt;/a&gt; with &lt;span class="caps"&gt;HTML&lt;/span&gt; and &lt;span class="caps"&gt;CSS&lt;/span&gt; (and even a bit of Rails 3.1).&lt;/p&gt;
      &lt;p&gt;Ryan&amp;#8217;s process is an incredible mix of back-end theory (such as test-driven development) and front-end utility (sketching and prototyping). It has already changed the way we do things at PeepCode and we think you&amp;#8217;ll like it too.&lt;/p&gt;
      &lt;p&gt;View a free ten minutes from the sketching session in the video above.&lt;/p&gt;
      &lt;p class='author'&gt;
        &lt;em&gt;
          production by
        &lt;/em&gt;
        Geoffrey Grosenbach
        &lt;em&gt;&amp;amp;&lt;/em&gt;
        Paula Lavalle
      &lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='wrapper'&gt;
  &lt;div class='row'&gt;
    &lt;div class='column buy-above'&gt;
      &lt;a class='buttonify' href='http://peepcode.com/products/ryan-singer-ux'&gt;
        Read More &amp; Buy This Video
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='wrapper end'&gt;
  &lt;div class='row'&gt;
    &lt;div class='column social'&gt;
      &lt;div class='tweet'&gt;
        &lt;a class='twitter-share-button' data-count='horizontal' href='https://twitter.com/share'&gt;
          Tweet
        &lt;/a&gt;
        &lt;script src='//platform.twitter.com/widgets.js' type='text/javascript'&gt;&lt;/script&gt;
      &lt;/div&gt;
      &lt;div id='fb-root'&gt;&lt;/div&gt;
      &lt;script type='text/javascript'&gt;
        //&lt;![CDATA[
          (function(d, s, id) {
            var js, fjs = d.getElementsByTagName(s)[0];
            if (d.getElementById(id)) {return;}
            js = d.createElement(s); js.id = id;
            js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
            fjs.parentNode.insertBefore(js, fjs);
          }(document, 'script', 'facebook-jssdk'));
        //]]&gt;
      &lt;/script&gt;
      &lt;div class='fb-like' data-href='http://peepcode.com/blog/2011/free-ryan-singer-ui-sketching-video' data-layout='button_count' data-send='false' data-show-faces='false' data-width='50'&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</content>
    <published>Thu Oct 06 23:00:00 +0000 2011</published>
  </entry>
  <entry>
    <title>My Avatar</title>
    <link href="http://blog.peepcode.com/blog/2011/my-avatar" type="text/html" rel="alternate"/>
    <id>tag:blog.peepcode.com,2011-07-06:/blog/2011/my-avatar</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article is heavily styled and is best viewed at &lt;a href="http://blog.peepcode.com/blog/2011/my-avatar"&gt;PeepCode&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;&lt;div class='row' id='avatars'&gt;
  &lt;div class='column'&gt;
    &lt;p id='author'&gt;
      by Geoffrey Grosenbach &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; Paula Lavalle
    &lt;/p&gt;
    &lt;ul id='circles'&gt;
      &lt;li id='circle1'&gt;
        &lt;img alt='Avatar' src='/blog/2011/my-avatar/circle1.jpg' /&gt;
      &lt;/li&gt;
      &lt;li id='circle2'&gt;
        &lt;img alt='Avatar' src='/blog/2011/my-avatar/circle2.jpg' /&gt;
      &lt;/li&gt;
      &lt;li id='circle3'&gt;
        &lt;img alt='Avatar' src='/blog/2011/my-avatar/circle3.jpg' /&gt;
      &lt;/li&gt;
      &lt;li id='circle4'&gt;
        &lt;img alt='Avatar' src='/blog/2011/my-avatar/circle4.jpg' /&gt;
      &lt;/li&gt;
      &lt;li id='circle5'&gt;
        &lt;img alt='Avatar' src='/blog/2011/my-avatar/circle5.jpg' /&gt;
      &lt;/li&gt;
      &lt;li class='bigun' id='circle6'&gt;
        &lt;img alt='Avatar' src='/blog/2011/my-avatar/circle6.jpg' /&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='row' id='prose'&gt;
  &lt;div class='column'&gt;
    &lt;h2&gt;The Hooligan&lt;/h2&gt;
    &lt;p&gt;In 2004 I worked at a grade school that hosted a highly
    anticipated field day every year. I decided to paint my face
    with my team&amp;#8217;s flag for that year: South Africa.&lt;/p&gt;
    &lt;p&gt;For the next few weeks, kindergarteners told me they had
    nightmares because of it.&lt;/p&gt;
    &lt;p&gt;The following year, I coached the team representing the &lt;span class="caps"&gt;USA&lt;/span&gt;. I
    carefully painted a flag on my face, only later to realize that
    I had put the stars on the wrong side (damn mirrors!). Fortunately
    no one noticed since I had started a trend. Almost every kid
    arrived with some kind of paint splashed on their face: stars,
    hearts, stripes, camouflage.&lt;/p&gt;
    &lt;p&gt;I used a photo from that day as my avatar for the next few
    years, but I managed to lose the original. Instead of adopting
    an entirely new avatar, I decided it was time to recreate
    it&amp;#8230;but better.&lt;/p&gt;
    &lt;p&gt;A studio flash, a digital &lt;span class="caps"&gt;SLR&lt;/span&gt;, and some face crayons solved the
    problem. I&amp;#8217;m now the owner of what may be the world&amp;#8217;s first
    studio photograph taken purely for the purpose of being
    displayed at 48&amp;#215;48 on Twitter, Facebook, GitHub, and other
    services.&lt;/p&gt;
    &lt;p&gt;People frequently tell me &amp;#8220;You look nothing like your avatar.&amp;#8221;
    Hopefully that&amp;#8217;s a little less true now.&lt;/p&gt;
    &lt;cite&gt;Geoffrey Grosenbach (&lt;a href="http://twitter.com/topfunky"&gt;@topfunky&lt;/a&gt;)&lt;/cite&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div id='colophon'&gt;
  &lt;div class='row'&gt;
    &lt;h2&gt;
      &lt;img alt='Colophon' src='/blog/2011/my-avatar/colophon/colophon-title.png' /&gt;
    &lt;/h2&gt;
    &lt;div class='column' id='mask-notes'&gt;
      &lt;h3&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt; Masks&lt;/h3&gt;
      &lt;p&gt;In order to achieve excruciatingly crisp curves around the
      images, we used &lt;span class="caps"&gt;CSS&lt;/span&gt; masks with &lt;span class="caps"&gt;SVG&lt;/span&gt; paths.&lt;/p&gt;
      &lt;p&gt;24-bit &lt;span class="caps"&gt;PNG&lt;/span&gt; images can be saved with transparency without the
      need for masks, but &lt;span class="caps"&gt;JPG&lt;/span&gt; photos can&amp;#8217;t. Using a compressed &lt;span class="caps"&gt;JPG&lt;/span&gt;
      image with a &lt;span class="caps"&gt;CSS&lt;/span&gt; mask gives you the best of both worlds.&lt;/p&gt;
      &lt;h4&gt;Webkit&lt;/h4&gt;
      &lt;p&gt;Webkit&amp;#8217;s masking is more full-featured than Firefox (see notes
      below). It can use &lt;span class="caps"&gt;SVG&lt;/span&gt; files straight from Adobe Illustrator
      and can stretch masks dynamically.&lt;/p&gt;
      &lt;p&gt;&lt;img src="/blog/2011/my-avatar/colophon/masks.jpg" title="CSS image mask" alt="CSS image mask" /&gt;&lt;/p&gt;
      &lt;p&gt;The &lt;span class="caps"&gt;HTML&lt;/span&gt; markup references square images (seen at left). A circular mask is
      applied. The result is an image that is opaque in the black
      parts of the mask and transparent in the other parts.&lt;/p&gt;
      &lt;ul&gt;
      	&lt;li&gt;An element can be masked directly, or an outer element can mask all the elements inside it.&lt;/li&gt;
      &lt;/ul&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&amp;#x000A;  &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;face.jpg&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&amp;#x000A;&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;ul&gt;
      	&lt;li&gt;In Adobe Illustrator or another graphics application, draw a black shape and &amp;#8220;Save As&amp;#8221; &lt;span class="caps"&gt;SVG&lt;/span&gt;. You can use it directly in Webkit with no further modification.&lt;/li&gt;
      &lt;/ul&gt;
      &lt;ul&gt;
      	&lt;li&gt;Use the &lt;code&gt;-webkit-mask-box-image&lt;/code&gt; directive in &lt;span class="caps"&gt;CSS&lt;/span&gt; to specify the path to the &lt;span class="caps"&gt;SVG&lt;/span&gt; file. We found it easiest to use the &lt;code&gt;stretch&lt;/code&gt; option to expand the mask to fill the area covered by the element being masked. This also works better for animation since the mask grows as the image is resized.&lt;/li&gt;
      &lt;/ul&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;box&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url(mask.svg)&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;stretch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;h4&gt;Firefox&lt;/h4&gt;
      &lt;p&gt;Firefox needs a slightly different &lt;span class="caps"&gt;SVG&lt;/span&gt; file and can&amp;#8217;t stretch the mask.&lt;/p&gt;
      &lt;ul&gt;
      	&lt;li&gt;Make a copy of the &lt;span class="caps"&gt;SVG&lt;/span&gt; file you used with Webkit. Open it in a text editor. Modify it to include a &lt;code&gt;mask&lt;/code&gt; element around the drawing directives. The &lt;code&gt;mask&lt;/code&gt; element should have an &lt;code&gt;id&lt;/code&gt; so you can refer to it in the next step (we used &lt;code&gt;avatar-mask&lt;/code&gt;).&lt;/li&gt;
      &lt;/ul&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;&amp;lt;!-- Note: Simplified for educational purposes.  --&amp;gt;&lt;/span&gt;&amp;#x000A;&lt;span class="nt"&gt;&amp;lt;svg&amp;gt;&lt;/span&gt;&amp;#x000A;  &lt;span class="nt"&gt;&amp;lt;mask&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;avatar-mask&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&amp;#x000A;    &lt;span class="nt"&gt;&amp;lt;circle&lt;/span&gt; &lt;span class="na"&gt;cx=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;100&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;cy=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;100&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;r=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;100&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;white&amp;quot;&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&amp;#x000A;  &lt;span class="nt"&gt;&amp;lt;/mask&amp;gt;&lt;/span&gt;&amp;#x000A;&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;ul&gt;
      	&lt;li&gt;You also need to specify &lt;code&gt;fill="white"&lt;/code&gt; for the drawing directives (such as the &lt;code&gt;circle&lt;/code&gt; above).&lt;/li&gt;
      &lt;/ul&gt;
      &lt;ul&gt;
      	&lt;li&gt;Add a line to your &lt;span class="caps"&gt;CSS&lt;/span&gt;. Ask for a &lt;code&gt;mask&lt;/code&gt; and include the &lt;span class="caps"&gt;URL&lt;/span&gt; of the Firefox mask file. Append the &lt;code&gt;id&lt;/code&gt; of the &lt;code&gt;mask&lt;/code&gt; element (&lt;code&gt;avatar-mask&lt;/code&gt; in this example).&lt;/li&gt;
      &lt;/ul&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;box&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url(mask.svg)&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="n"&gt;stretch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;  &lt;span class="c"&gt;/* Non-Webkit browsers */&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="sx"&gt;url(mask-firefox.svg#avatar-mask)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;p&gt;Because Firefox masks won&amp;#8217;t stretch with the element, we made
      a larger mask for the big version of the avatar. It makes the
      animation less elegant than the Webkit version, but it looks
      the same once the animation has completed.&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column' id='animation-notes'&gt;
      &lt;h3&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt; Animation&lt;/h3&gt;
      &lt;p&gt;We started out thinking that we would need to use jQuery or
      Scriptaculous to animate the circles into the center when
      clicked. It turns out that &lt;span class="caps"&gt;CSS&lt;/span&gt; animations are supported in
      most modern browsers and make the code much easier.&lt;/p&gt;
      &lt;h4&gt;CoffeeScript&lt;/h4&gt;
      &lt;p&gt;Now that we know it, why not use
      &lt;a href="https://peepcode.com/products/coffeescript"&gt;CoffeeScript&lt;/a&gt;? We
      used it with jQuery to listen for a click on any of the images
      and add a &lt;span class="caps"&gt;CSS&lt;/span&gt; class. The class repositions the item to the
      center and makes it larger.&lt;/p&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;jQuery&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&amp;#x000A;  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#circles li&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;click&lt;/span&gt; &lt;span class="nf"&gt;(event) -&amp;gt;&lt;/span&gt;&amp;#x000A;    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#circles li&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;removeClass&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;bigun&amp;#39;&lt;/span&gt;&amp;#x000A;    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;addClass&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;bigun&amp;#39;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;h4&gt;Animation&lt;/h4&gt;
      &lt;p&gt;Until two days ago, we thought &lt;span class="caps"&gt;CSS&lt;/span&gt; animation was a complicated
      system that would take weeks to figure out.&lt;/p&gt;
      &lt;p&gt;Animating it only took two lines.&lt;/p&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;p&gt;The easiest way is to specify &lt;code&gt;all&lt;/code&gt; properties. When you add a
      &lt;span class="caps"&gt;CSS&lt;/span&gt; class to an element, all the new properties will
      animate. Otherwise, you can use a comma-delimited list of only
      the properties you want to animate: &lt;code&gt;opacity,left,right&lt;/code&gt;, etc.&lt;/p&gt;
      &lt;p&gt;You can also add the same directives for Firefox and Opera:&lt;/p&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;  &lt;span class="c"&gt;/* Webkit */&lt;/span&gt;&amp;#x000A;  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;webkit&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;&amp;#x000A;  &lt;span class="c"&gt;/* Firefox */&lt;/span&gt;&amp;#x000A;  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;moz&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;moz&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;&amp;#x000A;  &lt;span class="c"&gt;/* Opera */&lt;/span&gt;&amp;#x000A;  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;o&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;property&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="err"&gt;o&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;transition&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1s&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;h4&gt;See also&lt;/h4&gt;
      &lt;ul&gt;
      	&lt;li&gt;&lt;a href="http://www.webkit.org/blog/138/css-animation/"&gt;Official Webkit blog post&lt;/a&gt;&lt;/li&gt;
      &lt;/ul&gt;
      &lt;h3&gt;Other&lt;/h3&gt;
      &lt;p&gt;Sass was instrumental in positioning the list items in a
      circular pattern. After calculating everything, we were able
      to change the radius of the hexagon and even the sizes of the
      circles until they fit.&lt;/p&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="nl"&gt;#circle1&lt;/span&gt;&amp;#x000A;  &lt;span class="nt"&gt;top&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;cy&lt;/span&gt; &lt;span class="nt"&gt;-&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;hexagon_radius&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nt"&gt;0&lt;/span&gt;&lt;span class="nc"&gt;.866&lt;/span&gt; &lt;span class="nt"&gt;-&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;radius&lt;/span&gt;&amp;#x000A;  &lt;span class="nt"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;cx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;hexagon_radius&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nt"&gt;2&lt;/span&gt; &lt;span class="nt"&gt;-&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;radius&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;p&gt;Oh, and some photographs. We fitted a Nikon D7000 camera with
      a 50mm lens and hooked it to an inexpensive studio strobe and
      umbrella from &lt;a href="http://alienbees.com"&gt;AlienBees&lt;/a&gt;.&lt;/p&gt;
      &lt;p&gt;And of course, some face paint!&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</content>
    <published>Wed Jul 06 00:00:00 +0000 2011</published>
  </entry>
  <entry>
    <title>CoffeeScript in Motion</title>
    <link href="http://blog.peepcode.com/blog/2011/coffeescript-in-motion" type="text/html" rel="alternate"/>
    <id>tag:blog.peepcode.com,2011-05-19:/blog/2011/coffeescript-in-motion</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article is heavily styled and is best viewed at &lt;a href="http://blog.peepcode.com/blog/2011/coffeescript-in-motion"&gt;PeepCode&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;&lt;div class='segment'&gt;
  &lt;div class='upper'&gt;
    &lt;h2&gt;In Motion&lt;/h2&gt;
    &lt;div id="buy"&gt;&lt;h2&gt;Learn it!&lt;/h2&gt;&lt;p class="small"&gt;One hour video.&lt;br /&gt;Only &lt;sup&gt;$&lt;/sup&gt;12!&amp;nbsp;&lt;a href="http://peepcode.com/products/coffeescript"&gt;More Info&amp;hellip;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;
    &lt;div class='videobox'&gt;
      &lt;a href='http://peepcode.com/system/uploads/2011/blog/coffeescript/b-1-coffeescript-jquery/b-1-coffeescript-jquery.mov'&gt;
        &lt;img alt='A snippet of code' class='screenshot' src='/blog/2011/coffeescript-in-motion/b-1-coffeescript-jquery.jpg' /&gt;
      &lt;/a&gt;
      &lt;h5&gt;COFFEESCRIPT:&lt;/h5&gt;
      &lt;pre class='coffee'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;jQuery&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&amp;#x000A;  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#entry&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;
      &lt;h5&gt;JAVASCRIPT:&lt;/h5&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;jQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &amp;#x000A;  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#entry&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;focus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
    &lt;h3&gt;
      1. A simple function
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='before'&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id='content-overalls'&gt;
  &lt;div class='segment content'&gt;
    &lt;h4&gt;Engineering + Creativity&lt;/h4&gt;
    &lt;div class='column'&gt;
      &lt;p&gt;In his book &lt;em&gt;Rise of the Creative Class&lt;/em&gt;, Richard Florida defines a list of creative professions that includes graphic designers, sculptors, architects, and&amp;#8230;software writers.&lt;/p&gt;
      &lt;p&gt;It&amp;#8217;s hard to think of a better place to see creativity and engineering than in CoffeeScript, a little language that compiles to JavaScript.&lt;/p&gt;
      &lt;p&gt;CoffeeScript is beautiful. It&amp;#8217;s sensibly designed around syntactic indentation. It adds useful features to JavaScript. Most importantly, it&amp;#8217;s a very thin layer over JavaScript. For any line of CoffeeScript, one can easily predict the line of JavaScript that the compiler will emit.&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column'&gt;
      &lt;p&gt;CoffeeScript invents some good ideas and steals many others. The number one source I could identify for the most useful ideas in CoffeeScript? Perl.&lt;/p&gt;
      &lt;p&gt;Yes, Perl. The language that&amp;#8217;s guaranteed to produce an audible gasp if mentioned in civilized programming circles today. Yet for ten solid years, Perl was a petri dish of syntactic innovation. Extended regular expressions, destructuring assignment.&lt;/p&gt;
      &lt;p&gt;Which is why it&amp;#8217;s exciting to see syntactic experimentation happening with such vigor in CoffeeScript.&lt;/p&gt;
      &lt;p&gt;In these video snippets, you&amp;#8217;ll see how JavaScript and CoffeeScript compare.&lt;/p&gt;
      &lt;div id='prose-credits'&gt;
        &amp;mdash; Geoffrey Grosenbach
        &lt;div class='small'&gt;
          Design &amp; Motion Graphics by Paula Lavalle
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='after'&gt;&amp;nbsp;&lt;/div&gt;
&lt;div id='video-overalls'&gt;
  &lt;div class='segment video'&gt;
    &lt;center&gt;
      &lt;img alt='' class='ornament' src='/blog/2011/coffeescript-in-motion/ornament.png' /&gt;
    &lt;/center&gt;
    &lt;h3 class='ondark'&gt;
      2. Jasmine&amp;#8217;s &amp;#8216;describe&amp;#8217; function with args
    &lt;/h3&gt;
    &lt;div class='videobox'&gt;
      &lt;a href='http://peepcode.com/system/uploads/2011/blog/coffeescript/b-2-coffeescript-jasmine/b-2-coffeescript-jasmine.mov'&gt;
        &lt;img alt='A snippet of code' class='screenshot' src='/blog/2011/coffeescript-in-motion/b-2-coffeescript-jasmine.jpg' /&gt;
      &lt;/a&gt;
      &lt;h5 class='ondark'&gt;COFFEESCRIPT:&lt;/h5&gt;
      &lt;pre class='coffee'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;constructor&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;
      &lt;h5 class='ondark'&gt;JAVASCRIPT:&lt;/h5&gt;
      &lt;pre&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;constructor&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;h3 class='ondark'&gt;
      3. The @ syntax for instance properties
    &lt;/h3&gt;
    &lt;div class='videobox'&gt;
      &lt;a href='http://peepcode.com/system/uploads/2011/blog/coffeescript/b-3-coffeescript-beforeEach/b-3-coffeescript-beforeEach.mov'&gt;
        &lt;img alt='A snippet of code' class='screenshot' src='/blog/2011/coffeescript-in-motion/b-3-coffeescript-beforeEach.jpg' /&gt;
      &lt;/a&gt;
      &lt;h5 class='ondark'&gt;COFFEESCRIPT:&lt;/h5&gt;
      &lt;pre class='coffee'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;beforeEach&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&amp;#x000A;  &lt;span class="vi"&gt;@dish = &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Dish&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Steak $18.99&amp;#39;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;
      &lt;h5 class='ondark'&gt;JAVASCRIPT:&lt;/h5&gt;
      &lt;pre&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;beforeEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Dish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Steak $18.99&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;div class='quotation'&gt;
      &lt;blockquote&gt;&amp;#8220;Everybody shows off&lt;br /&gt;And wants to look presentable&lt;br /&gt;But the fact of the matter&lt;br /&gt;Is that accidents are preventable.&amp;#8221; &lt;cite&gt;&amp;mdash; Buck 65&lt;/cite&gt;&lt;/blockquote&gt;
    &lt;/div&gt;
    &lt;h3 class='ondark'&gt;
      4. An instance method
    &lt;/h3&gt;
    &lt;div class='videobox'&gt;
      &lt;a href='http://peepcode.com/system/uploads/2011/blog/coffeescript/b-4-coffeescript-instance-method/b-4-coffeescript-instance-method.mov'&gt;
        &lt;img alt='A snippet of code' class='screenshot' src='/blog/2011/coffeescript-in-motion/b-4-coffeescript-instance-method.jpg' /&gt;
      &lt;/a&gt;
      &lt;h5 class='ondark'&gt;COFFEESCRIPT:&lt;/h5&gt;
      &lt;pre class='coffee'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;add: &lt;/span&gt;&lt;span class="nf"&gt;(dish) -&amp;gt;&lt;/span&gt;&amp;#x000A;  &lt;span class="nx"&gt;@dishes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt; &lt;span class="nx"&gt;dish&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;
      &lt;h5 class='ondark'&gt;JAVASCRIPT:&lt;/h5&gt;
      &lt;pre&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;Meal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dish&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dishes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dish&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;};&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;h3 class='ondark'&gt;
      5. A full class with constructor
    &lt;/h3&gt;
    &lt;div class='videobox'&gt;
      &lt;a href='http://peepcode.com/system/uploads/2011/blog/coffeescript/b-5-coffeescript-class/b-5-coffeescript-class.mov'&gt;
        &lt;img alt='A snippet of code' class='screenshot' src='/blog/2011/coffeescript-in-motion/b-5-coffeescript-class.jpg' /&gt;
      &lt;/a&gt;
      &lt;h5 class='ondark'&gt;COFFEESCRIPT:&lt;/h5&gt;
      &lt;pre class='coffee'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;Money&lt;/span&gt;&amp;#x000A;  &lt;span class="nv"&gt;constructor: &lt;/span&gt;&lt;span class="nf"&gt;(rawString) -&amp;gt;&lt;/span&gt;&amp;#x000A;    &lt;span class="vi"&gt;@cents = &lt;/span&gt;&lt;span class="nx"&gt;@parseCents&lt;/span&gt; &lt;span class="nx"&gt;rawString&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;
      &lt;h5 class='ondark'&gt;JAVASCRIPT:&lt;/h5&gt;
      &lt;pre&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;Money&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parseCents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&amp;#x000A;  &lt;span class="p"&gt;}&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Money&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;})();&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;h3 class='ondark'&gt;
      6. Object literal
    &lt;/h3&gt;
    &lt;div class='videobox'&gt;
      &lt;a href='http://peepcode.com/system/uploads/2011/blog/coffeescript/b-6-coffeescript-json/b-6-coffeescript-json.mov'&gt;
        &lt;img alt='A snippet of code' class='screenshot' src='/blog/2011/coffeescript-in-motion/b-6-coffeescript-json.jpg' /&gt;
      &lt;/a&gt;
      &lt;h5 class='ondark'&gt;COFFEESCRIPT:&lt;/h5&gt;
      &lt;pre class='coffee'&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nv"&gt;toJSON: &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&amp;#x000A;  &lt;span class="nv"&gt;title: &lt;/span&gt;&lt;span class="nx"&gt;@title&lt;/span&gt;&amp;#x000A;  &lt;span class="nv"&gt;price: &lt;/span&gt;&lt;span class="nx"&gt;@price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;
      &lt;h5 class='ondark'&gt;JAVASCRIPT:&lt;/h5&gt;
      &lt;pre&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;toJSON&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&amp;#x000A;    &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&amp;#x000A;  &lt;span class="p"&gt;};&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/pre&gt;
    &lt;/div&gt;
    &lt;h4 class='buy-ondark'&gt;
      Intrigued?
      &lt;a href='http://peepcode.com/products/coffeescript'&gt;
        Buy the 75 minute video at PeepCode!
      &lt;/a&gt;
    &lt;/h4&gt;
    &lt;center&gt;
      &lt;img alt='' class='ornament end' src='/blog/2011/coffeescript-in-motion/ornament.png' /&gt;
    &lt;/center&gt;
  &lt;/div&gt;
&lt;/div&gt;
</content>
    <published>Thu May 19 18:00:00 +0000 2011</published>
  </entry>
  <entry>
    <title>R.I.P. Ruby Hash Rocket Syntax 1993-2010</title>
    <link href="http://blog.peepcode.com/blog/2011/rip-ruby-hash-rocket-syntax" type="text/html" rel="alternate"/>
    <id>tag:blog.peepcode.com,2011-01-05:/blog/2011/rip-ruby-hash-rocket-syntax</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article is heavily styled and is best viewed at &lt;a href="http://blog.peepcode.com/blog/2011/rip-ruby-hash-rocket-syntax"&gt;PeepCode&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;&lt;div class='column article'&gt;
  &lt;p&gt;&lt;img src="/blog/2011/rip-ruby-hash-rocket-syntax/comic.jpg" id="comic" alt="" /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column prose'&gt;
  &lt;p&gt;The hash rocket is dead. In Ruby 1.9, hashes whose keys are symbols can be built with a single colon.&lt;/p&gt;
  &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;dr_nic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;The Comedian&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&amp;#x000A;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;p&gt;No longer will you need to remember different syntax when switching between JavaScript and Ruby (or even Python!). And you&amp;#8217;ll save at least three characters every time.&lt;/p&gt;
  &lt;p&gt;It&amp;#8217;s one more reason to start using Ruby 1.9!&lt;/p&gt;
  &lt;p&gt;Please update your code accordingly.&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column footnotes'&gt;
  &lt;p&gt;Learn more about Ruby 1.9 at &lt;a href="https://peepcode.com/screencasts/ruby"&gt;PeepCode&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt;Inspiration from the &lt;a href="http://www.flickr.com/photos/21633523@N03/2697517999/"&gt;opening panels&lt;/a&gt; of &lt;a href="http://en.wikipedia.org/wiki/Watchmen"&gt;The Watchmen&lt;/a&gt;.&lt;/p&gt;
  &lt;p&gt;Comment on this post at &lt;a href="http://news.ycombinator.com/item?id=2073004"&gt;Hacker News&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
</content>
    <published>Wed Jan 05 22:00:00 +0000 2011</published>
  </entry>
  <entry>
    <title>Happy Holidays from PeepCode</title>
    <link href="http://blog.peepcode.com/blog/2010/happy-holidays" type="text/html" rel="alternate"/>
    <id>tag:blog.peepcode.com,2010-12-23:/blog/2010/happy-holidays</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article is heavily styled and is best viewed at &lt;a href="http://blog.peepcode.com/blog/2010/happy-holidays"&gt;PeepCode&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;&lt;div class='column article'&gt;
  &lt;p&gt;Thanks for making 2010 the biggest year yet at PeepCode!&lt;/p&gt;
  &lt;p&gt;We&amp;#8217;re excited about keeping you informed and on top of your game. We&amp;#8217;ve got big plans for 2011!&lt;/p&gt;
&lt;/div&gt;
</content>
    <published>Thu Dec 23 01:00:00 +0000 2010</published>
  </entry>
  <entry>
    <title>Rethinking Rails 3 Controllers and Routes</title>
    <link href="http://blog.peepcode.com/blog/2010/rethinking-rails-3-routes" type="text/html" rel="alternate"/>
    <id>tag:blog.peepcode.com,2010-06-02:/blog/2010/rethinking-rails-3-routes</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article is heavily styled and is best viewed at &lt;a href="http://blog.peepcode.com/blog/2010/rethinking-rails-3-routes"&gt;PeepCode&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;&lt;div class='column' id='disclaimer'&gt;
  &lt;p&gt;&lt;span class="caps"&gt;DISCLAIMER&lt;/span&gt;: Reg Braithwaite delivered this quote in a completely different context&lt;sup class="footnote"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;, but I think it&amp;#8217;s applicable to the design of almost any software &lt;span class="caps"&gt;API&lt;/span&gt;. Illustration by Mike Rohde.&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column article'&gt;
  &lt;div class='row'&gt;
    &lt;div class='column' id='intro'&gt;
      &lt;p&gt;The &lt;strong&gt;Rails router&lt;/strong&gt; has been written and rewritten at least four
      times&lt;sup class="footnote"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;, including a recent rewrite for the upcoming Rails
      3. The syntax is now more concise.&lt;/p&gt;
      &lt;p&gt;But never mind making it shorter! It&amp;#8217;s time for a &lt;strong&gt;final
      rewrite&lt;/strong&gt;: Let&amp;#8217;s get rid of it altogether!&lt;/p&gt;
      &lt;p&gt;Let&amp;#8217;s &lt;strong&gt;get rid&lt;/strong&gt; of the &lt;strong&gt;seven controller actions&lt;/strong&gt;: &lt;code&gt;index&lt;/code&gt;,
      &lt;code&gt;show&lt;/code&gt;, &lt;code&gt;new&lt;/code&gt;, &lt;code&gt;create&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt; and &lt;code&gt;delete&lt;/code&gt;. Their
      meaning is blurred in the context of &lt;span class="caps"&gt;REST&lt;/span&gt;. They&amp;#8217;re an unhelpful
      layer between programmer and protocol.&lt;/p&gt;
      &lt;p&gt;Let&amp;#8217;s get rid of the trivial but &lt;strong&gt;cumbersome mental
      translation&lt;/strong&gt; you have to do everytime you want to think about
      the &lt;span class="caps"&gt;HTTP&lt;/span&gt; &lt;code&gt;GET&lt;/code&gt; method, the &lt;span class="caps"&gt;URL&lt;/span&gt;, the &lt;code&gt;index&lt;/code&gt; action, and the
      &lt;code&gt;plural_path&lt;/code&gt; &lt;span class="caps"&gt;URL&lt;/span&gt; helper.&lt;/p&gt;
      &lt;p&gt;Let&amp;#8217;s get rid of &lt;strong&gt;duplicate functionality&lt;/strong&gt; already implemented
      in the controller. If you need to redirect, take action based
      on the user agent, or examine headers, that should be done in
      a controller!&lt;/p&gt;
      &lt;p&gt;And let&amp;#8217;s &lt;strong&gt;start thinking in URLs&lt;/strong&gt;, resources, and APIs instead of
      doing image caching in models or asset bundling in
      view helpers. That&amp;#8217;s the controller&amp;#8217;s job. It scales better, too.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row'&gt;
    &lt;div class='column' id='manifesto'&gt;
      
      &lt;ul&gt;
      	&lt;li&gt;Routes are unnecessary configuration.&lt;/li&gt;
      	&lt;li&gt;The seven standard controller actions are legacy.&lt;/li&gt;
      	&lt;li&gt;Become intimate with your URLs &amp;#8211; don&amp;#8217;t abstract them away.&lt;/li&gt;
      	&lt;li&gt;Decrease the distance between thought and implementation.&lt;/li&gt;
      	&lt;li&gt;Let the controller do its job.&lt;/li&gt;
      &lt;/ul&gt;
      &lt;li&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row problems first'&gt;
    &lt;div class='column diagram'&gt;
      &lt;h2&gt;Get Back to Thinking in URLs&lt;/h2&gt;
      &lt;p&gt;A big part of the problem with a routing layer is that it
      abstracts the developer away from the URLs that define the
      application. This leads to poor &lt;span class="caps"&gt;API&lt;/span&gt; designs and convoluted
      solutions to otherwise easy problems.&lt;/p&gt;
      &lt;p&gt;This epiphany came while writing a few Sinatra
      applications. The exact &lt;span class="caps"&gt;URL&lt;/span&gt; for a handler sits right in
      front of my eyes as I write the code for it. I can&amp;#8217;t ignore it.&lt;/p&gt;
      &lt;p&gt;As a result, I find myself spending more time thinking about
      how my URLs are designed. Should I be serving &lt;span class="caps"&gt;JSON&lt;/span&gt; from the
      same controller that serves the &lt;span class="caps"&gt;HTML&lt;/span&gt; interface, or should it
      be organized separately?&lt;/p&gt;
      &lt;p&gt;In contrast, you can write an entire Rails application without
      ever looking at a &lt;span class="caps"&gt;URL&lt;/span&gt;. The design of URLs is delegated to the
      framework, out of sight and out of mind.&lt;/p&gt;
      &lt;p&gt;This isn&amp;#8217;t to say that we need to lose the good parts of how
      Rails works with URLs. &lt;span class="caps"&gt;URL&lt;/span&gt; helper methods like
      &lt;code&gt;pancake_path(:id)&lt;/code&gt; are a great idea for reducing duplication
      and typos. They could be implemented apart from any router.&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column prose'&gt;
      &lt;blockquote&gt;&amp;#8220;I love URLs. I dream about them at night. I think about them before I think about anything else.&amp;#8221; &lt;cite&gt;&amp;mdash; Adrian Holovaty, co-creator of Django&lt;/cite&gt;&lt;/blockquote&gt;&lt;p class="caption"&gt;* From &lt;a href="http://matthewbuchanan.name/post/79527495/i-love-urls"&gt;Webstock 2009&lt;/a&gt;&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row problems'&gt;
    &lt;div class='column diagram'&gt;
      &lt;h2&gt;Retire the Seven Action Names&lt;/h2&gt;
      &lt;p&gt;It has been three years since the seven controller actions had
      any immediate meaning. The &lt;span class="caps"&gt;API&lt;/span&gt; no longer adds to the
      programmer&amp;#8217;s understanding of the tasks at hand.&lt;/p&gt;
      &lt;p&gt;Experienced programmers know that inline comments mark code
      that&amp;#8217;s too confusing or too clever.&lt;/p&gt;
      &lt;p&gt;Yet every Rails controller is generated with two lines of
      repetitive comments for every action. That&amp;#8217;s a code smell! And
      a failure of &lt;span class="caps"&gt;API&lt;/span&gt; design.&lt;/p&gt;
      &lt;p&gt;Every Rails developer must memorize the table at right,
      mapping &lt;span class="caps"&gt;HTTP&lt;/span&gt; method and &lt;span class="caps"&gt;URL&lt;/span&gt; to the controller action name. If
      we can get rid of the action name, the rest of the table is
      already self-explanatory.&lt;/p&gt;
      &lt;p&gt;So instead of going through this extra syntactical layer, let&amp;#8217;s
      deal directly with &lt;span class="caps"&gt;GET&lt;/span&gt;, &lt;span class="caps"&gt;POST&lt;/span&gt;, &lt;span class="caps"&gt;PUT&lt;/span&gt;, and &lt;span class="caps"&gt;DELETE&lt;/span&gt;. (Suggestions follow.)&lt;/p&gt;
      &lt;p&gt;You can tell this is a great idea because it&amp;#8217;s the way unit tests
      already work! Let&amp;#8217;s bring this syntax back to the controller and
      complete the &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column prose'&gt;
      &lt;table&gt;
      	&lt;tr&gt;
      		&lt;th&gt;Method&lt;/th&gt;
      		&lt;th&gt;&lt;span class="caps"&gt;URL&lt;/span&gt;&lt;/th&gt;
      		&lt;th&gt;Action&lt;/th&gt;
      		&lt;th&gt;Helper&lt;/th&gt;
      	&lt;/tr&gt;
      	&lt;tr&gt;
      		&lt;td&gt;&lt;span class="caps"&gt;GET&lt;/span&gt;&lt;/td&gt;
      		&lt;td&gt;/pancakes&lt;/td&gt;
      		&lt;td class="action"&gt;index&lt;/td&gt;
      		&lt;td&gt;pancakes_path&lt;/td&gt;
      	&lt;/tr&gt;
      	&lt;tr class="odd"&gt;
      		&lt;td&gt; &lt;span class="caps"&gt;GET&lt;/span&gt;&lt;/td&gt;
      		&lt;td&gt;/pancakes/:id&lt;/td&gt;
      		&lt;td class="action"&gt;show&lt;/td&gt;
      		&lt;td&gt;pancake_path(:id)&lt;/td&gt;
      	&lt;/tr&gt;
      	&lt;tr&gt;
      		&lt;td&gt;&lt;span class="caps"&gt;GET&lt;/span&gt;&lt;/td&gt;
      		&lt;td&gt;/pancakes/new&lt;/td&gt;
      		&lt;td class="action"&gt;new&lt;/td&gt;
      		&lt;td&gt;new_pancake_path&lt;/td&gt;
      	&lt;/tr&gt;
      	&lt;tr class="odd"&gt;
      		&lt;td&gt; &lt;span class="caps"&gt;POST&lt;/span&gt;&lt;/td&gt;
      		&lt;td&gt;/pancakes&lt;/td&gt;
      		&lt;td class="action"&gt;create&lt;/td&gt;
      		&lt;td&gt;pancakes_path&lt;/td&gt;
      	&lt;/tr&gt;
      	&lt;tr&gt;
      		&lt;td&gt;&lt;span class="caps"&gt;GET&lt;/span&gt;&lt;/td&gt;
      		&lt;td&gt;/pancakes/:id/edit&lt;/td&gt;
      		&lt;td class="action"&gt;edit&lt;/td&gt;
      		&lt;td&gt;edit_pancake_path(:id)&lt;/td&gt;
      	&lt;/tr&gt;
      	&lt;tr class="odd"&gt;
      		&lt;td&gt; &lt;span class="caps"&gt;PUT&lt;/span&gt;&lt;/td&gt;
      		&lt;td&gt;/pancakes/:id&lt;/td&gt;
      		&lt;td class="action"&gt;update&lt;/td&gt;
      		&lt;td&gt;pancake_path(:id)&lt;/td&gt;
      	&lt;/tr&gt;
      	&lt;tr&gt;
      		&lt;td&gt;&lt;span class="caps"&gt;DELETE&lt;/span&gt;&lt;/td&gt;
      		&lt;td&gt;/pancakes/:id&lt;/td&gt;
      		&lt;td class="action"&gt;destroy&lt;/td&gt;
      		&lt;td&gt;pancake_path(:id)&lt;/td&gt;
      	&lt;/tr&gt;
      &lt;/table&gt;
      &lt;p class="highlight-file-link small"&gt;&lt;a href="/blog/2010/rethinking-rails-3-routes/controller-comments.rb"&gt;controller-comments.rb&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# GET /pancakes&lt;/span&gt;&amp;#x000A;&lt;span class="c1"&gt;# GET /pancakes.xml&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="c1"&gt;# POST /pancakes&lt;/span&gt;&amp;#x000A;&lt;span class="c1"&gt;# POST /pancakes.xml&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;p class="highlight-file-link small"&gt;&lt;a href="/blog/2010/rethinking-rails-3-routes/test-with-http-method.rb"&gt;test-with-http-method.rb&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;should create pancake&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="ss"&gt;:create&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;assert_redirected_to&lt;/span&gt; &lt;span class="n"&gt;pancake_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row problems last'&gt;
    &lt;div class='column diagram'&gt;
      &lt;h2&gt;Assets Are Resources&lt;/h2&gt;
      &lt;p&gt;Thinking in URLs helps you solve web-related problems in the
      right way.&lt;/p&gt;
      &lt;p&gt;Exhibit A: If you deploy to a site whose view fragments are
      already cached in memcached, it&amp;#8217;s likely that Rails&amp;#8217; asset
      caching view helpers will not be called and &lt;span class="caps"&gt;CSS&lt;/span&gt; bundles will
      not be generated.&lt;/p&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# Caching shouldn&amp;#39;t happen here&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;stylesheet_link_tag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&amp;#x000A;                    &lt;span class="ss"&gt;:cache&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;p&gt;This whole problem is easily solved by &lt;em&gt;using controllers to
      do what they do best&lt;/em&gt;. Views and helpers should not generate
      &lt;span class="caps"&gt;URL&lt;/span&gt;-based resources.&lt;/p&gt;
      &lt;p&gt;The task of combining several &lt;span class="caps"&gt;CSS&lt;/span&gt; files into one file and
      caching them to disk is &lt;em&gt;exactly&lt;/em&gt; the kind of task controllers
      are built to do&lt;sup class="footnote"&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column prose'&gt;
      &lt;img src="/blog/2010/rethinking-rails-3-routes/asset-urls.png" alt="Controllers should generate and cache assets, not view helpers." title="Controllers should generate and cache assets, not view helpers." /&gt;&lt;p class="caption"&gt;Controllers should generate and cache assets, not view helpers.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row'&gt;
    &lt;div class='column half'&gt;
      &lt;h2&gt;Idea 1: Sinatra&lt;/h2&gt;
      &lt;p&gt;There are many ways the controller &lt;span class="caps"&gt;API&lt;/span&gt; could be
      improved. Existing attempts have failed to achieve wide
      adoption because they have tried to handle controllers, views,
      and models all at once&lt;sup class="footnote"&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
      &lt;p&gt;Instead, I think a more limited, controller-only approach
      could work better.&lt;/p&gt;
      &lt;p&gt;The first is already in wide use: Sinatra.&lt;/p&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# Sinatra-style handler&lt;/span&gt;&amp;#x000A;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/api/v1/report/:id&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&amp;#x000A;  &lt;span class="c1"&gt;# ...&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;p&gt;Sinatra is arguably the most widely replicated Ruby web
      framework, having inspired implementations in Node.js,
      Clojure, &lt;span class="caps"&gt;PHP&lt;/span&gt;, Scala, and many other languages.&lt;/p&gt;
      &lt;p&gt;Part of the problem with writing a routing &lt;span class="caps"&gt;API&lt;/span&gt; is finding a
      way to describe multiple URLs in a single string. This problem
      is solved if you handle each &lt;span class="caps"&gt;URL&lt;/span&gt; on its own.&lt;/p&gt;
      &lt;p&gt;There&amp;#8217;s no middle routing layer with arbitrary action
      names. &lt;span class="caps"&gt;HTTP&lt;/span&gt; method and &lt;span class="caps"&gt;URL&lt;/span&gt; are all you need (but handlers can
      filter on the user agent or other header information).&lt;/p&gt;
      &lt;p&gt;Thanks to Rack, Sinatra apps can be embedded in Rails
      applications. Or, Carl Lerche is writing a Rails 3 plugin that
      provides this syntax to Rails controllers&lt;sup class="footnote"&gt;&lt;a href="#fn5"&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
    &lt;/div&gt;
    &lt;div class='column half'&gt;
      &lt;h2&gt;Idea 2: Method, Member, Collection&lt;/h2&gt;
      &lt;p&gt;Jamis Buck introduced an implementation of &lt;span class="caps"&gt;REST&lt;/span&gt; as a plugin
      &lt;em&gt;four years&lt;/em&gt; ago. Yet unlike other areas of Rails that have
      seen massive improvements, Rails&amp;#8217; implementation of &lt;span class="caps"&gt;REST&lt;/span&gt; is
      basically the same as it was in Rails 1.2.&lt;/p&gt;
      &lt;p&gt;A halfway approach could combine elements of the Rails 3
      router syntax with the class method style of configuration
      that&amp;#8217;s already familiar to Rails developers.&lt;/p&gt;
      &lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# Class method and HTTP-style methods.&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReportsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;AppController&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;before_filter&lt;/span&gt; &lt;span class="ss"&gt;:authenticate&lt;/span&gt;&amp;#x000A;  &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/api/v1/reports(/:id)&amp;quot;&lt;/span&gt;&amp;#x000A;&amp;#x000A;  &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:collection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;  &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:member&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;  &lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:member&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
      &lt;p&gt;Variations on this syntax could easily accomodate nested
      resources, singleton resources, or other custom &lt;span class="caps"&gt;URL&lt;/span&gt; schemes.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row'&gt;
    &lt;div class='column' id='conclusion'&gt;
      &lt;h2&gt;Conclusion&lt;/h2&gt;
      &lt;p&gt;For several years, Rails has charged forward and defined new,
      innovative syntaxes for writing web applications. It&amp;#8217;s time for
      it to happen again.&lt;/p&gt;
      &lt;p&gt;An improved syntax could &lt;strong&gt;get rid of stale controller
      actions&lt;/strong&gt;, &lt;strong&gt;reduce confusion&lt;/strong&gt;, &lt;strong&gt;reduce duplication&lt;/strong&gt;, and
      &lt;strong&gt;improve&lt;/strong&gt; the way we think about solving technical problems
      with web applications.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='row'&gt;
    &lt;div class='column' id='addendum'&gt;
      &lt;h2&gt;Reactions&lt;/h2&gt;
      &lt;p class="caption"&gt;Thanks to &lt;a href="http://reginald.braythwayt.com/"&gt;Reg Braithwaite&lt;/a&gt; and &lt;a href="http://benhoskin.gs/"&gt;Ben Hoskings&lt;/a&gt; for feedback on this article.&lt;/p&gt;&lt;p&gt;&lt;a href="http://benhoskin.gs/"&gt;Ben Hoskings&lt;/a&gt; said&lt;/p&gt;
      &lt;blockquote&gt;
      &lt;p&gt;I think the mere fact that a controller can be generated means that code shouldn&amp;#8217;t be there. There&amp;#8217;s no intelligence in code that can be generated from a single resource name.&lt;/p&gt;
      &lt;/blockquote&gt;
      &lt;blockquote&gt;
      &lt;p&gt;I think it&amp;#8217;s doubly important because once you free the controller from having to implement the specifics of each action (like models doesn&amp;#8217;t have to implement the specifics of &lt;code&gt;#save&lt;/code&gt;), you have a lot more room to raise the abstraction level and start getting declarative.&lt;/p&gt;
      &lt;/blockquote&gt;
      &lt;blockquote&gt;
      &lt;p&gt;I think making the controller more declarative is probably the end goal. Instead of the bulk of each action being an imperative mess, the controller can be heavier on the class-level configuration that&amp;#8217;s really proven itself in the model (associations, scopes, plugin configuration, etc.).&lt;/p&gt;
      &lt;/blockquote&gt;
      &lt;p&gt;The &lt;code&gt;provides&lt;/code&gt; class-level configuration directive in Merb/Rails 3 is a signal that controllers can head in this direction.&lt;/p&gt;
      &lt;p&gt;Kyle Neath gives several &lt;a href="http://warpspire.com/posts/url-design/"&gt;useful guidelines&lt;/a&gt; in detail for thinking about &lt;span class="caps"&gt;URL&lt;/span&gt; design.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='column footnotes'&gt;
  &lt;p&gt;Thoughts and reactions? Reply to &lt;a href="http://twitter.com/topfunky"&gt;@topfunky&lt;/a&gt; on Twitter, write a blog post of your own, or comment at &lt;a href="http://news.ycombinator.com/item?id=1398654"&gt;Hacker News&lt;/a&gt;.&lt;/p&gt;
  &lt;p class="footnote" id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; &lt;a href="http://www.infoq.com/presentations/braithwaite-rewrite-ruby"&gt;Video&lt;/a&gt; of Reg Braithwaite at RubyFringe. Quote is about 15:30 in.&lt;/p&gt;
  &lt;p class="footnote" id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; The original version by David Heinemeier Hansson, then by
  Ulysses, then by Koz and Jamis Buck (together), and most recently
  by Yehuda Katz, Josh Peek, and the Rails 3 team.&lt;/p&gt;
  &lt;p class="footnote" id="fn3"&gt;&lt;sup&gt;3&lt;/sup&gt; &lt;a href="/blog/2010/rethinking-rails-3-routes/javascripts_controller.rb"&gt;Sample controller code&lt;/a&gt;. Versioning and expiration of assets are easily solved by storing a
  version number in the application and appending it to the link
  tag.&lt;/p&gt;
  &lt;p class="footnote" id="fn4"&gt;&lt;sup&gt;4&lt;/sup&gt; See &lt;a href="http://github.com/benhoskings/hammock"&gt;hammock&lt;/a&gt; by Ben Hoskings, &lt;a href="http://github.com/hcatlin/make_resourceful"&gt;make_resourceful&lt;/a&gt; by Hampton Catlin and &lt;a href="http://github.com/jamesgolick/resource_controller"&gt;resource_controller&lt;/a&gt; by James Golick.&lt;/p&gt;
  &lt;p class="footnote" id="fn5"&gt;&lt;sup&gt;5&lt;/sup&gt; Carl Lerche&amp;#8217;s &lt;a href="http://github.com/carllerche/astaire"&gt;Astaire&lt;/a&gt; plugin.&lt;/p&gt;
&lt;/div&gt;
</content>
    <published>Wed Jun 02 16:00:00 +0000 2010</published>
  </entry>
  <entry>
    <title>Am I the Only One Who Uses a Text Editor to Edit Files?</title>
    <link href="http://blog.peepcode.com/blog/2010/file-navigation-in-text-editors" type="text/html" rel="alternate"/>
    <id>tag:blog.peepcode.com,2010-03-25:/blog/2010/file-navigation-in-text-editors</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article is heavily styled and is best viewed at &lt;a href="http://blog.peepcode.com/blog/2010/file-navigation-in-text-editors"&gt;PeepCode&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;&lt;div class='column article'&gt;
  &lt;img src="/blog/2010/file-navigation-in-text-editors/mockup-cropped.png" alt="Files should be navigable by file, class, or method name and show metadata useful for distinguishing between similar files (mockup)." title="Files should be navigable by file, class, or method name and show metadata useful for distinguishing between similar files (mockup)." /&gt;&lt;p class="caption"&gt;Files should be navigable by file, class, or method name and show metadata useful for distinguishing between similar files (mockup).&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column article split'&gt;
  &lt;p&gt;If I had no experience with computers and were to guess which
  group of people had the best software tools to do their job, I
  would guess &amp;#8220;computer programmers.&amp;#8221;&lt;/p&gt;
  &lt;p&gt;And if I were to guess what task would have been extensively
  optimized, I would guess &amp;#8220;opening files.&amp;#8221;&lt;/p&gt;
  &lt;p&gt;If you &lt;em&gt;are&lt;/em&gt; a programmer, you know that I would be wrong.&lt;/p&gt;
  &lt;p&gt;Last summer, Dave Peck wrote about his hopes for a modern,
  progressive, text editor.&lt;sup class="footnote"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt; I&amp;#8217;d like to focus on one missing feature
  that&amp;#8217;s absolutely possible today: powerful file navigation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column article title'&gt;
  &lt;p&gt;&lt;img src="/blog/2010/file-navigation-in-text-editors/title-what-i-want.png" alt="" /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column feature first'&gt;
  &lt;p&gt;&lt;img src="/blog/2010/file-navigation-in-text-editors/icon-keyboard.png" alt="" /&gt;&lt;/p&gt;
  &lt;h4&gt;Keyboard&lt;/h4&gt;
  &lt;p&gt;Perform any navigation task without touching the mouse.&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column feature'&gt;
  &lt;p&gt;&lt;img src="/blog/2010/file-navigation-in-text-editors/icon-fuzzy.png" alt="" /&gt;&lt;/p&gt;
  &lt;h4&gt;Fuzzy Search&lt;/h4&gt;
  &lt;p&gt;Find files by typing only a few letters.&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column feature'&gt;
  &lt;p&gt;&lt;img src="/blog/2010/file-navigation-in-text-editors/icon-path.png" alt="" /&gt;&lt;/p&gt;
  &lt;h4&gt;Paths&lt;/h4&gt;
  &lt;p&gt;Search includes folder names (relative to the project).&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column feature'&gt;
  &lt;p&gt;&lt;img src="/blog/2010/file-navigation-in-text-editors/icon-metadata.png" alt="" /&gt;&lt;/p&gt;
  &lt;h4&gt;Metadata&lt;/h4&gt;
  &lt;p&gt;File modification date and &lt;span class="caps"&gt;SCM&lt;/span&gt; status aid in file picking.&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column feature'&gt;
  &lt;p&gt;&lt;img src="/blog/2010/file-navigation-in-text-editors/icon-beautiful.png" alt="" /&gt;&lt;/p&gt;
  &lt;h4&gt;Beautiful&lt;/h4&gt;
  &lt;p&gt;Terminal raster graphics don&amp;#8217;t count! I want &lt;span class="caps"&gt;GUI&lt;/span&gt; beauty.&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column article split'&gt;
  &lt;p&gt;As every Vim user knows, most of one&amp;#8217;s time spent in a text editor is
  spent &lt;em&gt;editing&lt;/em&gt;, not writing (this is why &lt;em&gt;Normal&lt;/em&gt; mode in Vim is
  the one you use for navigation and editing).&lt;/p&gt;
  &lt;p&gt;For most programming tasks, editing involves opening several files at
  once and switching between them (e.g. &lt;span class="caps"&gt;HTML&lt;/span&gt;/JavaScript/&lt;span class="caps"&gt;CSS&lt;/span&gt;).&lt;/p&gt;
  &lt;p&gt;I&amp;#8217;m talking about three tasks:&lt;/p&gt;
  &lt;ul&gt;
  	&lt;li&gt;Open any file on the computer.&lt;/li&gt;
  	&lt;li&gt;Open any file in the current project.&lt;/li&gt;
  	&lt;li&gt;Activate a file that&amp;#8217;s already open in another tab.&lt;/li&gt;
  &lt;/ul&gt;
  &lt;p&gt;And yet most text editors offload these important tasks to the
  operating system or implement half-hearted custom solutions. Even
  worse, third-party plugins frequently implement file-jumping
  functionality for different frameworks with unique, cryptic key
  mappings (e.g. between implementation and test or controller and
  view template).&lt;/p&gt;
  &lt;p&gt;This is a core task! Editors should approach it with the same
  innovation and care they spend on basic text entry.&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column article title'&gt;
  &lt;p&gt;&lt;img src="/blog/2010/file-navigation-in-text-editors/title-current-editors.png" alt="" /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column editor'&gt;
  &lt;h5&gt;TextMate&lt;/h5&gt;
  &lt;div class="keyboard"&gt;Keyboard&lt;/div&gt;
  &lt;div class="fuzzy"&gt;Fuzzy&lt;/div&gt;
  &lt;div class="beautiful"&gt;Beautiful&lt;/div&gt;
  &lt;p&gt;Command-T with &lt;strong&gt;fuzzy search was revolutionary&lt;/strong&gt; and was one of the
  main reasons I bought a copy of TextMate. &lt;strong&gt;But it breaks down&lt;/strong&gt; for
  projects with many files of the same name (such as Ruby on Rails).&lt;/p&gt;
  &lt;img src="/blog/2010/file-navigation-in-text-editors/textmate-index.png" alt="There&amp;#8217;s no way to filter by directory." title="There&amp;#8217;s no way to filter by directory." /&gt;&lt;p class="caption"&gt;There&amp;#8217;s no way to filter by directory.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tabs are even worse&lt;/strong&gt;. I frequently open more tabs than can fit on
   my screen, which means that &lt;strong&gt;both usability and the extra tabs
   get thrown out the window&lt;/strong&gt;. The tab menu can only be accessed
   with the mouse and becomes a human-powered binary search of an
   unsorted list.&lt;sup class="footnote"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column editor'&gt;
  &lt;h5&gt;Xcode&lt;/h5&gt;
  &lt;div class="keyboard"&gt;Keyboard&lt;/div&gt;
  &lt;div class="beautiful"&gt;Beautiful&lt;/div&gt;
  &lt;p&gt;Xcode&amp;#8217;s &lt;em&gt;Open Quickly&lt;/em&gt; command (Command-Shift-D) only works with
  &lt;strong&gt;the exact file name&lt;/strong&gt; starting with the &lt;strong&gt;first letter.&lt;/strong&gt;&lt;/p&gt;
  &lt;img src="/blog/2010/file-navigation-in-text-editors/xcode-open-quickly.png" alt="Xcode&amp;#8217;s Open Quickly dialog" title="Xcode&amp;#8217;s Open Quickly dialog" /&gt;&lt;p class="caption"&gt;Xcode&amp;#8217;s Open Quickly dialog&lt;/p&gt;&lt;p&gt;Many Cocoa developers &lt;strong&gt;store all their code files in the root
  directory&lt;/strong&gt; of the project and rely on Xcode&amp;#8217;s virtual directories
  for organization, which is the only reason it&amp;#8217;s even &lt;strong&gt;barely
  usable&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column editor'&gt;
  &lt;h5&gt;Emacs&lt;/h5&gt;
  &lt;div class="keyboard"&gt;Keyboard&lt;/div&gt;
  &lt;div class="fuzzy"&gt;Fuzzy&lt;/div&gt;
  &lt;div class="path"&gt;Path&lt;/div&gt;
  &lt;p&gt;Emacs is the &lt;strong&gt;closest to satisfying&lt;/strong&gt; my requirements.&lt;/p&gt;
  &lt;p&gt;The &lt;code&gt;ido-menu&lt;/code&gt; provides &lt;strong&gt;fuzzy search, including pathnames&lt;/strong&gt;. Chris
  Wanstrath&amp;#8217;s textmate.el plugin&lt;sup class="footnote"&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt; wraps it in even more useful
  functionality, such as autodiscovery of a project root based on
  the existence of a &lt;code&gt;.git&lt;/code&gt; directory.&lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;Open buffers&lt;/strong&gt; (similar to tabs) can be searched for by name (&lt;code&gt;C-x b&lt;/code&gt;) or in a list (&lt;code&gt;C-x C-b&lt;/code&gt;).&lt;/p&gt;
  &lt;p&gt;But the inline menu is an &lt;strong&gt;ugly&lt;/strong&gt; paragraph.&lt;/p&gt;
  &lt;img src="/blog/2010/file-navigation-in-text-editors/emacs-find.png" alt="A powerful search hidden behind a mess of text." title="A powerful search hidden behind a mess of text." /&gt;&lt;p class="caption"&gt;A powerful search hidden behind a mess of text.&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column article'&gt;
  &lt;blockquote&gt;&amp;#8220;The only solution I can think of, so far,&lt;br /&gt;Is to smash out the windows with a crowbar.&amp;#8221; &lt;cite&gt;&amp;mdash; Buck 65&lt;/cite&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class='column article prototype'&gt;
  &lt;p&gt;Once you start thinking about making file navigation better, the
  ideas flow freely. Could a dialog &lt;strong&gt;search on class or method
  names&lt;/strong&gt; instead of just filenames? What about a free-form search for
  times and classes such as &amp;#8220;&lt;code&gt;yesterday Bacon#save&lt;/code&gt;&amp;#8221;?&lt;/p&gt;
  &lt;p&gt;This article started with &lt;strong&gt;pain&lt;/strong&gt;, developed into an &lt;strong&gt;idea&lt;/strong&gt;, and ended up as an &lt;strong&gt;unexpected prototype&lt;/strong&gt; implemented in MacRuby. I&amp;#8217;m using it daily and am fine-tuning the interaction, visuals, features, and performance.&lt;/p&gt;
  &lt;p&gt;The app is now available as &lt;a href="http://peepcode.com/products/peepopen"&gt;PeepOpen&lt;/a&gt; with a beautiful icon. Works with TextMate, Emacs, and MacVim.&lt;/p&gt;
  &lt;p&gt;For other updates, follow @peepcode on Twitter &lt;a href="http://twitter.com/peepcode"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column article prototype-image'&gt;
  &lt;img src="/blog/2010/file-navigation-in-text-editors/fuzzy-window-screenshot.png" alt="The initial prototype performs a fuzzy search on paths and lists file modification dates." title="The initial prototype performs a fuzzy search on paths and lists file modification dates." /&gt;&lt;p class="caption"&gt;The initial prototype performs a fuzzy search on paths and lists file modification dates.&lt;/p&gt;
&lt;/div&gt;
&lt;div class='column footnotes'&gt;
  &lt;p&gt;You can contribute your own froth over the design and content of this article with the Neanderthals at &lt;a href="http://news.ycombinator.com/item?id=1219401"&gt;Hacker News&lt;/a&gt;.&lt;/p&gt;
  &lt;p class="footnote" id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Dave Peck sends supplication to &lt;a href="http://davepeck.org/2009/05/14/dear-osx-editor-gods/"&gt;the text editor gods&lt;/a&gt;.&lt;/p&gt;
  &lt;p class="footnote" id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; The &lt;a href="http://code.leadmediapartners.com/"&gt;RubyAMP&lt;/a&gt; bundle for TextMate shows a simple list of open windows, but without fuzzy search.&lt;/p&gt;
  &lt;p class="footnote" id="fn3"&gt;&lt;sup&gt;3&lt;/sup&gt; Chris Wanstrath&amp;#8217;s &lt;a href="http://github.com/defunkt/textmate.el"&gt;textmate.el&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
</content>
    <published>Thu Mar 25 12:00:00 +0000 2010</published>
  </entry>
  <entry>
    <title>About this Blog</title>
    <link href="http://blog.peepcode.com/blog/2010/about-this-blog" type="text/html" rel="alternate"/>
    <id>tag:blog.peepcode.com,2010-02-24:/blog/2010/about-this-blog</id>
    <content type="html">&lt;p&gt;&lt;strong&gt;This article is heavily styled and is best viewed at &lt;a href="http://blog.peepcode.com/blog/2010/about-this-blog"&gt;PeepCode&lt;/a&gt;!&lt;/strong&gt;&lt;/p&gt;&lt;div class='column toc style'&gt;
  &lt;h2&gt;Style&lt;/h2&gt;
  &lt;p&gt;
    Each post is uniquely styled within a grid.
    &lt;a href='#style'&gt;&amp;darr;&lt;/a&gt;
  &lt;/p&gt;
&lt;/div&gt;
&lt;div class='column toc sinatra'&gt;
  &lt;h2&gt;Sinatra&lt;/h2&gt;
  &lt;p&gt;
    Generates static pages and graphics. Styles code samples.
    &lt;a href='#sinatra'&gt;&amp;darr;&lt;/a&gt;
  &lt;/p&gt;
&lt;/div&gt;
&lt;div class='column toc nosql'&gt;
  &lt;h2&gt;No SQL&lt;/h2&gt;
  &lt;p&gt;
    Not even a database! File-based metadata.
    &lt;a href='#nosql'&gt;&amp;darr;&lt;/a&gt;
  &lt;/p&gt;
&lt;/div&gt;
&lt;div class='column toc haml'&gt;
  &lt;h2&gt;Haml&lt;/h2&gt;
  &lt;p&gt;
    Powers article templates and markup.
    &lt;a href='#haml'&gt;&amp;darr;&lt;/a&gt;
  &lt;/p&gt;
&lt;/div&gt;
&lt;div class='column toc css'&gt;
  &lt;h2&gt;SASS/CSS&lt;/h2&gt;
  &lt;p&gt;
    Comprehensive and reusable styling.
    &lt;a href='#css'&gt;&amp;darr;&lt;/a&gt;
  &lt;/p&gt;
&lt;/div&gt;
&lt;div class='column toc javascript'&gt;
  &lt;h2&gt;JavaScript&lt;/h2&gt;
  &lt;p&gt;
    Taking it further&amp;hellip;custom behavior &amp;amp; graphics.
    &lt;a href='#javascript'&gt;&amp;darr;&lt;/a&gt;
  &lt;/p&gt;
&lt;/div&gt;
&lt;div class='column article' id='style'&gt;
  &lt;h2&gt;Style&lt;/h2&gt;
  &lt;div class='quote'&gt;
    &lt;blockquote&gt;
    &lt;p&gt;Before there were blogs we had websites. Beautiful, random websites that felt more like a zine &amp;#8212; one page looking nothing like the one before or after it.&lt;/p&gt;
    &lt;/blockquote&gt;
    &lt;cite&gt;Greg Storey, Airbag Industries&lt;sup class="footnote"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/cite&gt;&lt;p&gt;&lt;img src="/blog/2010/about-this-blog/grid.png" alt="" /&gt;&lt;/p&gt;
  &lt;/div&gt;
  &lt;div class='prose'&gt;
    &lt;p&gt;Many developments in computer science have nothing to do with
    the capabilities of computers, but with the way we use them.&lt;/p&gt;
    &lt;p&gt;A few years ago, an article on Airbag Industries&lt;sup class="footnote"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt; inspired me to
    think about writing a blog with a unique design per post.&lt;/p&gt;
    &lt;p&gt;There are many benefits:&lt;/p&gt;
    &lt;ul&gt;
    	&lt;li&gt;It encourages creativity both at the computer and away from it&lt;/li&gt;
    	&lt;li&gt;It&amp;#8217;s like a code kata for design&lt;/li&gt;
    	&lt;li&gt;You can easily experiment with cutting-edge CSS3 features or just learn CSS2&lt;/li&gt;
    	&lt;li&gt;You&amp;#8217;ll learn how to build a style foundation for other designs in other applications&lt;/li&gt;
    &lt;/ul&gt;
    &lt;p&gt;On the downside, it takes more time than simply writing prose.&lt;/p&gt;
    &lt;p&gt;Building an art-directed blog may seem as easy as dropping an
    extra &lt;span class="caps"&gt;CSS&lt;/span&gt; &lt;code&gt;link&lt;/code&gt; tag into every blog post, but a little extra
    work upfront makes it a lot easier.&lt;/p&gt;
    &lt;p&gt;First, I started with a layout grid in &lt;span class="caps"&gt;CSS&lt;/span&gt;. Grids have been used
    extensively in print design but have only recently become
    popular in website design. I like Tyler Tate&amp;#8217;s 1kb grid&lt;sup class="footnote"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;
    because it&amp;#8217;s the simplest thing necessary to accomplish the task.&lt;/p&gt;
    &lt;p&gt;In standard website design, elements can be placed anywhere on a
    page. In contrast, a grid defines boundaries in regular
    increments, limiting the possibilities. Instead of stifling
    creativity, it encourages experimentation by making it easier to
    think about a finite number of widths for text or images.&lt;/p&gt;
    &lt;p&gt;I use a 12 column grid (double-click anywhere on this page to
    see it). Twelve columns are easily divided into other
    increments: 12 &amp;middot; 6+6 &amp;middot; 2+5+5 &amp;middot; 4+4+4 &amp;middot; 3+3+3+3&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='column article' id='sinatra'&gt;
  &lt;h2&gt;Sinatra&lt;/h2&gt;
  &lt;div class='prose'&gt;
    &lt;p&gt;The Sinatra web framework has a beautiful &lt;span class="caps"&gt;REST&lt;/span&gt; &lt;span class="caps"&gt;API&lt;/span&gt;, can be
    extremely powerful, and is super fast.&lt;/p&gt;
    &lt;p&gt;It&amp;#8217;s easily deployed with Phusion Passenger alongside my other
    Rack-based web applications.&lt;/p&gt;
    &lt;p&gt;I started with the Nesta&lt;sup class="footnote"&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt; blog engine and enhanced it with the
    additional &lt;span class="caps"&gt;CSS&lt;/span&gt; and graphic generation features I needed. All
    pages are cached statically with Sinatra::Cache&lt;sup class="footnote"&gt;&lt;a href="#fn5"&gt;5&lt;/a&gt;&lt;/sup&gt; for even
    greater speed. Although this blog could be generated with a
    static site generator, I find it more natural to write it in a
    dynamic style.&lt;/p&gt;
    &lt;p&gt;One example is the generation of text headline images with the
    Textorize&lt;sup class="footnote"&gt;&lt;a href="#fn6"&gt;6&lt;/a&gt;&lt;/sup&gt; renderer from Thomas Fuchs. I reference the images
    by &lt;span class="caps"&gt;URL&lt;/span&gt; in my &lt;span class="caps"&gt;CSS&lt;/span&gt; files. Sinatra generates the graphic on the fly
    when that &lt;span class="caps"&gt;URL&lt;/span&gt; is accesed (then caches it). Sinatra keeps URLs at
    the forefront of the web developer&amp;#8217;s mind &amp;#8212; where they should be!&lt;/p&gt;
    &lt;p&gt;Other resources are generated at the view level when
    needed. Code snippets are formatted by the Pygments&lt;sup class="footnote"&gt;&lt;a href="#fn7"&gt;7&lt;/a&gt;&lt;/sup&gt;
    command-line script via a special RedCloth tag implemented as a
    Haml filter.&lt;/p&gt;
  &lt;/div&gt;
  &lt;div class='graphic'&gt;
    &lt;img alt='textorize' src='/blog/2010/about-this-blog/textorize.png' /&gt;
    &lt;p class='caption'&gt;
      Textorize (right half) renders text edges smoothly.
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='column article' id='nosql'&gt;
  &lt;h2&gt;No SQL&lt;/h2&gt;
  &lt;div class='code'&gt;
    &lt;p class="highlight-file-link small"&gt;&lt;a href="/blog/2010/about-this-blog/metadata.yml"&gt;metadata.yml&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="l-Scalar-Plain"&gt;heading&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;About this Blog&lt;/span&gt;&amp;#x000A;&lt;span class="l-Scalar-Plain"&gt;heading-font&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Klavika-BoldCondensed&lt;/span&gt;&amp;#x000A;&lt;span class="l-Scalar-Plain"&gt;heading-color&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;#000&lt;/span&gt;&amp;#x000A;&lt;span class="l-Scalar-Plain"&gt;heading-background&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;transparent&lt;/span&gt;&amp;#x000A;&lt;span class="l-Scalar-Plain"&gt;published&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;December 30 2019 at 6pm&lt;/span&gt;&amp;#x000A;&lt;span class="l-Scalar-Plain"&gt;categories&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;meta design&lt;/span&gt;&amp;#x000A;&lt;span class="l-Scalar-Plain"&gt;summary&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;An article about...&lt;/span&gt;&amp;#x000A;&lt;span class="l-Scalar-Plain"&gt;format&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;haml&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="l-Scalar-Plain"&gt;.column.article&lt;/span&gt;&amp;#x000A;  &lt;span class="l-Scalar-Plain"&gt;%h2 Bacon&lt;/span&gt;&amp;#x000A;&amp;#x000A;  &lt;span class="l-Scalar-Plain"&gt;:custom&lt;/span&gt;&amp;#x000A;    &lt;span class="l-Scalar-Plain"&gt;Haml and textile together...&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class='prose'&gt;
    &lt;p&gt;It&amp;#8217;s much easier to debug a visual design in development on the
    local machine, check the whole thing into Git, and deploy when
    ready. No need to write an authentication system or an article
    preview mechanism.&lt;/p&gt;
    &lt;p&gt;Article files are stored on disk with a bit of &lt;span class="caps"&gt;YAML&lt;/span&gt;-esque
    metadata at the top. Each article can be in Textile format, or
    can use the full power of Haml for more complicated markup.&lt;/p&gt;
    &lt;p&gt;Early on I needed to store information about the title&amp;#8217;s font
    size and color. Later I needed to add other custom fields for
    additional tagging. With an &lt;span class="caps"&gt;ORM&lt;/span&gt; this would have meant writing a
    migration and installing a plugin to manage tags.&lt;/p&gt;
    &lt;p&gt;There was no such problem here! I just added a few key-value
    pairs to the article&amp;#8217;s metadata and started using them in the
    application immediately.&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='column article' id='haml'&gt;
  &lt;h2&gt;Haml&lt;/h2&gt;
  &lt;div class='prose'&gt;
    &lt;p&gt;Not only does each post get its own &lt;span class="caps"&gt;CSS&lt;/span&gt;, it can also specify its
    own &lt;span class="caps"&gt;HTML&lt;/span&gt;, via Haml&lt;sup class="footnote"&gt;&lt;a href="#fn8"&gt;8&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
    &lt;p&gt;When I&amp;#8217;m designing visually in the browser, I&amp;#8217;m thinking
    primarily about blocks of text and images, and how they will be
    styled. I don&amp;#8217;t want to be thinking about &lt;span class="caps"&gt;HTML&lt;/span&gt; boilerplate or
    need to hunt to find a matching end tag.&lt;/p&gt;
    &lt;p&gt;Haml decreases the mental distance between &lt;span class="caps"&gt;HTML&lt;/span&gt; and &lt;span class="caps"&gt;CSS&lt;/span&gt;. I work
    directly with &lt;span class="caps"&gt;CSS&lt;/span&gt; selectors no matter what file I happen to be
    in.&lt;/p&gt;
    &lt;p&gt;But Haml isn&amp;#8217;t well suited to working with inline
    text. Fortunately, there&amp;#8217;s Textile&lt;sup class="footnote"&gt;&lt;a href="#fn9"&gt;9&lt;/a&gt;&lt;/sup&gt; for that!&lt;/p&gt;
    &lt;p&gt;The differences between the basic syntaxes of Textile and
    Markdown are negligible. Where it pulls away from Markdown is
    when you add new tags of your own. You can write view helpers
    that take a simple string and turn it into a group of &lt;span class="caps"&gt;HTML&lt;/span&gt;
    tags. It&amp;#8217;s not only faster to type, but I can build reusable
    elements for movie links, syntax-highlighted code snippets, pull
    quotes, and product boxes.&lt;/p&gt;
    &lt;p&gt;Textile enhancements are easily used inline within any Haml
    document. In RedCloth 4, the steps are:&lt;/p&gt;
    &lt;ul&gt;
    	&lt;li&gt;Write a module with methods for each of the tags you want to use (such as &lt;code&gt;movie&lt;/code&gt; at right).&lt;/li&gt;
    	&lt;li&gt;In each method, examine the &lt;code&gt;:text&lt;/code&gt; key in the options, then build and return an &lt;span class="caps"&gt;HTML&lt;/span&gt; string. I build links for the &lt;code&gt;mov&lt;/code&gt; and &lt;code&gt;m4v&lt;/code&gt; versions of each movie.&lt;/li&gt;
    	&lt;li&gt;Write a Haml filter. The name of your module will be used as the name of the filter.&lt;/li&gt;
    	&lt;li&gt;Extend RedCloth with your custom module.&lt;/li&gt;
    	&lt;li&gt;Add more methods to your tags module as needed.&lt;/li&gt;
    &lt;/ul&gt;
    &lt;p&gt;The code samples at right were built this way. I specify a path
    to a source file and it runs it through &lt;code&gt;pygmentize&lt;/code&gt;. It also
    prepends a link to the source file itself.&lt;/p&gt;
    &lt;p&gt;The end result is a text system customized for writing about
    code, but it looks great, too! I can&amp;#8217;t imagine using a &lt;span class="caps"&gt;CMS&lt;/span&gt; that
    was any less powerful than this.&lt;/p&gt;
  &lt;/div&gt;
  &lt;div class='code'&gt;
    &lt;p class="highlight-file-link small"&gt;&lt;a href="/blog/2010/about-this-blog/textile_in_use.haml"&gt;textile_in_use.haml&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nc"&gt;.column.article&lt;/span&gt;&amp;#x000A;&amp;#x000A;  &lt;span class="nt"&gt;%h2&lt;/span&gt; Custom Filter Sample&amp;#x000A; &amp;#x000A;  &lt;span class="nd"&gt;:custom_red_cloth&lt;/span&gt;&amp;#x000A;&amp;#x000A;    &lt;span class="nd"&gt;movie. http://example.com/movie.mov&lt;/span&gt;&amp;#x000A;&amp;#x000A;    &lt;span class="nd"&gt;source. /blog/code.rb&lt;/span&gt;&amp;#x000A;&amp;#x000A;    &lt;span class="nd"&gt;buy. http://peepcode.com/products&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p class="highlight-file-link small"&gt;&lt;a href="/blog/2010/about-this-blog/custom_tags.rb"&gt;custom_tags.rb&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;CustomTags&lt;/span&gt;&amp;#x000A;  &amp;#x000A;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;    &lt;span class="n"&gt;my_text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:text&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&amp;#x000A;    &lt;span class="c1"&gt;# Build an HTML string around my_text&lt;/span&gt;&amp;#x000A;    &lt;span class="c1"&gt;# ...&lt;/span&gt;&amp;#x000A;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;my_text&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;  &amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p class="highlight-file-link small"&gt;&lt;a href="/blog/2010/about-this-blog/custom_haml_filter.rb"&gt;custom_haml_filter.rb&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Haml&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Filters&lt;/span&gt;&amp;#x000A;&amp;#x000A;    &lt;span class="c1"&gt;# Renders custom textile.    &lt;/span&gt;&amp;#x000A;    &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;CustomRedCloth&lt;/span&gt;&amp;#x000A;      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Haml&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Filters&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&amp;#x000A;      &lt;span class="n"&gt;lazy_require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;custom_tags&amp;#39;&lt;/span&gt;&amp;#x000A;&amp;#x000A;      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;        &lt;span class="n"&gt;red_cloth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;RedCloth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&amp;#x000A;        &lt;span class="n"&gt;red_cloth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hard_breaks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&amp;#x000A;        &lt;span class="n"&gt;red_cloth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;CustomTags&lt;/span&gt;&amp;#x000A;        &lt;span class="n"&gt;red_cloth&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_html&lt;/span&gt;&amp;#x000A;      &lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;    &lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;end&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='column article' id='css'&gt;
  &lt;h2&gt;SASS/CSS&lt;/h2&gt;
  &lt;div class='code'&gt;
    &lt;p class="highlight-file-link small"&gt;&lt;a href="/blog/2010/about-this-blog/_article_sample.sass"&gt;_article_sample.sass&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="nn"&gt;page_util&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="nn"&gt;pygments_pastie&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nt"&gt;masthead-reset&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nt"&gt;dark-logo&lt;/span&gt;&amp;#x000A;&lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nt"&gt;dark-masthead-menu&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;base_color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;#d1e3ff&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="nc"&gt;.prose&lt;/span&gt;&amp;#x000A;  &lt;span class="k"&gt;@include&lt;/span&gt; &lt;span class="nt"&gt;grid_6&lt;/span&gt;&amp;#x000A;  &lt;span class="nt"&gt;float&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nt"&gt;left&lt;/span&gt;&amp;#x000A;  &lt;span class="nt"&gt;margin&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&amp;#x000A;    &lt;span class="nt"&gt;left&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;grid_gutter_width&lt;/span&gt;&amp;#x000A;    &lt;span class="nt"&gt;top&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nt"&gt;line_height&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;5&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
    &lt;p&gt;&lt;img src="/blog/2010/about-this-blog/archives-screenshot.png" alt="" /&gt;&lt;/p&gt;
    &lt;p class="caption"&gt;Archives page with screenshots&lt;/p&gt;
  &lt;/div&gt;
  &lt;div class='prose'&gt;
    &lt;p&gt;In a recent copy of &lt;em&gt;Print Magazine&lt;/em&gt;&lt;sup class="footnote"&gt;&lt;a href="#fn11"&gt;11&lt;/a&gt;&lt;/sup&gt;, someone talked about
    designing a &amp;#8220;style sheet&amp;#8221; for the magazine back in the 70&amp;#8217;s. For
    some reason, the extra space jolted my brain into thinking
    differently. Style. Sheet.&lt;/p&gt;
    &lt;p&gt;A stylesheet isn&amp;#8217;t supposed to be a receptacle into which one
    tosses a bunch of unrelated visual directives. It&amp;#8217;s a coherent
    guideline for how things should look. It should be planned and
    reusable. And like backend code, it may take several iterations
    of use in the real world to get it right.&lt;/p&gt;
    &lt;p&gt;&lt;acronym title="Syntactically Awesome Style Sheets"&gt;&lt;span class="caps"&gt;SASS&lt;/span&gt;&lt;/acronym&gt; is a huge part of
    achieving that concept in this blog.&lt;/p&gt;
    &lt;p&gt;People get emotional when they hear about &lt;span class="caps"&gt;SASS&lt;/span&gt;. Either they see
    it as a threat to traditional &lt;span class="caps"&gt;CSS&lt;/span&gt; (used only by hacks who
    haven&amp;#8217;t taken the time to learn it) or they welcome it as the
    best thing to happen to the Internet.&lt;/p&gt;
    &lt;p&gt;After working with this blog for a few months, I&amp;#8217;m in the second camp.&lt;/p&gt;
    &lt;p&gt;As an example, any page can be designed with a light or a dark
    background. A few mixins at the top automatically adjust the
    page background, logo color (implemented as an image sprite),
    and menu colors. All these are contained in the stylesheet and
    don&amp;#8217;t require any modification of the page&amp;#8217;s &lt;span class="caps"&gt;HTML&lt;/span&gt;.&lt;/p&gt;
    &lt;p&gt;The technical parts of the grid and vertical rhythm are also
    wired into my &lt;span class="caps"&gt;SASS&lt;/span&gt; stylesheets. I can give elements meaningful
    names in &lt;span class="caps"&gt;HTML&lt;/span&gt;, then specify &lt;code&gt;+grid_6&lt;/code&gt; in &lt;span class="caps"&gt;SASS&lt;/span&gt; to make the
    element six columns wide (alternately, I could have used
    arguments like &lt;code&gt;grid(6)&lt;/code&gt;).&lt;/p&gt;
    &lt;p&gt;Variables like &lt;code&gt;grid_gutter_width&lt;/code&gt; and &lt;code&gt;line_height&lt;/code&gt; are
    available to the whole application. I rarely type a number;
    instead I use meaningful variables to add margins or manipulate
    elements into position.&lt;/p&gt;
    &lt;p class="highlight-file-link small"&gt;&lt;a href="http://blog.peepcode.com/stylesheets/sass/_grid.sass"&gt;_grid.sass&lt;/a&gt;&lt;/p&gt;&lt;p&gt;And if I&amp;#8217;m going to spend that much time in the powder room, I
    want to show it off. The &lt;a href="/archives"&gt;archives&lt;/a&gt; page uses
    webkit2png.py&lt;sup class="footnote"&gt;&lt;a href="#fn10"&gt;10&lt;/a&gt;&lt;/sup&gt; to take a screenshot of each page and display
    it in a grid.&lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='column article' id='javascript'&gt;
  &lt;h2&gt;JavaScript&lt;/h2&gt;
  &lt;div class='prose'&gt;
    &lt;p&gt;A unique design for each post is great, but how about unique
    &lt;em&gt;JavaScript&lt;/em&gt; for each post?&lt;/p&gt;
    &lt;p&gt;For my Rails 3 upgrade screencast, I wanted to show a timeline
    of Rails release dates. I&amp;#8217;ve recently become enamored with
    RaphaelJS&lt;sup class="footnote"&gt;&lt;a href="#fn12"&gt;12&lt;/a&gt;&lt;/sup&gt; and it took only a few lines of code to import a
    JavaScript file for posts that want one.&lt;/p&gt;
    &lt;p&gt;I wrote a custom &lt;code&gt;Timeline&lt;/code&gt; function that plots dates as large
    dots.&lt;/p&gt;
    &lt;h4&gt;Conclusion&lt;/h4&gt;
    &lt;p&gt;As with many features of this blog, it will take a while to
    figure out how to use them all fully. In the meantime, it&amp;#8217;s a
    great learning experience and a fun output for creativity.&lt;/p&gt;
    &lt;p&gt;I haven&amp;#8217;t published the source yet and may never. But now you
    have the ideas&amp;#8230;implement them on your own blog!&lt;/p&gt;
  &lt;/div&gt;
  &lt;div class='code'&gt;
    &lt;p&gt;&lt;img src="/blog/2010/about-this-blog/graph.png" alt="" /&gt;&lt;/p&gt;
    &lt;p class="caption"&gt;In an earlier post, RaphaelJS was used to chart Rails release dates.&lt;/p&gt;&lt;p class="highlight-file-link small"&gt;&lt;a href="/blog/2010/about-this-blog/custom.js"&gt;custom.js&lt;/a&gt;&lt;/p&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nx"&gt;jQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&amp;#x000A;&amp;#x000A;  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;paper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Raphael&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;graph&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;940&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;81&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&amp;#x000A;    &lt;span class="nx"&gt;timeline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&amp;#x000A;&amp;#x000A;  &lt;span class="nx"&gt;timeline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Timeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&amp;#x000A;    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;06/25/2004&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0.5&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&amp;#x000A;    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;12/13/2005&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1.0.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&amp;#x000A;    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;12/07/2007&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2.0.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&amp;#x000A;    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;6/10/2010&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;3.0 ?&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&amp;#x000A;  &lt;span class="p"&gt;]);&lt;/span&gt;&amp;#x000A;&amp;#x000A;&lt;span class="p"&gt;});&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class='column footnotes'&gt;
  &lt;p class="footnote" id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Airbag Industries wrote on &lt;a href="http://www.airbagindustries.com/archives/airbag/boxes.php"&gt;the old days when blogs were designed like zines&lt;/a&gt;.&lt;/p&gt;
  &lt;p class="footnote" id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; The &lt;a href="http://1kbgrid.com/"&gt;1kb grid&lt;/a&gt; is the simplest thing necessary to get the job done. I convert it to &lt;span class="caps"&gt;SASS&lt;/span&gt; with the included &lt;code&gt;css2sass&lt;/code&gt; command.&lt;/p&gt;
  &lt;p class="footnote" id="fn3"&gt;&lt;sup&gt;3&lt;/sup&gt; With a hack to &lt;a href="http://github.com/topfunky/emacs-starter-kit/blob/master/topfunky-sinatra.el"&gt;ruby-mode&lt;/a&gt; in Emacs, I can easily jump to any Sinatra &lt;span class="caps"&gt;URL&lt;/span&gt; handler in a file.&lt;/p&gt;
  &lt;p class="footnote" id="fn4"&gt;&lt;sup&gt;4&lt;/sup&gt; &lt;a href="http://effectif.com/nesta"&gt;Nesta&lt;/a&gt; is a minimal blog engine by Graham Ashton (but easy to extend). It&amp;#8217;s built on the &lt;a href="http://www.sinatrarb.com/"&gt;Sinatra&lt;/a&gt; web framework.&lt;/p&gt;
  &lt;p class="footnote" id="fn5"&gt;&lt;sup&gt;5&lt;/sup&gt; Sinatra::Cache &lt;a href="http://github.com/kematzy/sinatra-cache"&gt;source code&lt;/a&gt;&lt;/p&gt;
  &lt;p class="footnote" id="fn6"&gt;&lt;sup&gt;6&lt;/sup&gt; &lt;a href="http://textorize.org/"&gt;Textorize text renderer&lt;/a&gt;&lt;/p&gt;
  &lt;p class="footnote" id="fn7"&gt;&lt;sup&gt;7&lt;/sup&gt; &lt;a href="http://pygments.org/"&gt;Pygments&lt;/a&gt; is the best syntax highlighter out there. When you view diffs and code at &lt;a href="http://github.com"&gt;GitHub&lt;/a&gt;, you&amp;#8217;re viewing pygments. &lt;a href="http://gist.github.com/23914"&gt;Pipe code to it&lt;/a&gt; on the command line.&lt;/p&gt;
  &lt;p class="footnote" id="fn8"&gt;&lt;sup&gt;8&lt;/sup&gt; The &lt;a href="http://haml-lang.com"&gt;Haml&lt;/a&gt; template engine is available for Ruby and other languages.&lt;/p&gt;
  &lt;p class="footnote" id="fn9"&gt;&lt;sup&gt;9&lt;/sup&gt; &lt;a href="http://www.textism.com/tools/textile/"&gt;Textile&lt;/a&gt; is a syntax for formatting prose.&lt;/p&gt;
  &lt;p class="footnote" id="fn10"&gt;&lt;sup&gt;10&lt;/sup&gt; &lt;a href="http://www.paulhammond.org/webkit2png/"&gt;webkit2png.py&lt;/a&gt; is a capable screenshot capturing script for Mac OS X. There&amp;#8217;s a Ruby port, but the original works well enough that I don&amp;#8217;t see the need. I&amp;#8217;ve wrapped it in the &lt;a href="http://github.com/topfunky/osxscreenshot"&gt;osxscreenshot&lt;/a&gt; gem.&lt;/p&gt;
  &lt;p class="footnote" id="fn11"&gt;&lt;sup&gt;11&lt;/sup&gt; &lt;a href="http://printmag.com/"&gt;Print Magazine&lt;/a&gt; is a classic (over 70 years in publication). &lt;a href="http://www.baselinemagazine.com/browse_buy/magazine/current_issue/cover/"&gt;Baseline Magazine&lt;/a&gt; is a more academic European counterpart. I recently bought a subscription to both.&lt;/p&gt;
  &lt;p class="footnote" id="fn12"&gt;&lt;sup&gt;12&lt;/sup&gt; &lt;a href="http://raphaeljs.com/"&gt;RaphaelJS&lt;/a&gt; is a JavaScript-based &lt;span class="caps"&gt;SVG&lt;/span&gt; drawing library.&lt;/p&gt;
  &lt;p class="footnote" id="fn13"&gt;&lt;sup&gt;13&lt;/sup&gt; The &lt;a href="http://www.barbariangroup.com/software/plainview"&gt;Plainview web browser&lt;/a&gt; is a full-screen browser, useful not only for &lt;span class="caps"&gt;HTML&lt;/span&gt;-based presentations.&lt;/p&gt;
&lt;/div&gt;
</content>
    <published>Wed Feb 24 18:00:00 +0000 2010</published>
  </entry>
</feed>

