<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>Laurel Fan - Home</title>
  <id>tag:laurelfan.com,2008:mephisto/</id>
  <generator version="0.7.3" uri="http://mephistoblog.com">Mephisto Noh-Varr</generator>
  <link href="http://laurelfan.com/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://laurelfan.com/" rel="alternate" type="text/html"/>
  <updated>2008-06-25T19:26:06Z</updated>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2008-06-18:36</id>
    <published>2008-06-18T00:36:00Z</published>
    <updated>2008-06-25T19:26:06Z</updated>
    <category term="Trips"/>
    <category term="climbing"/>
    <category term="mt baker"/>
    <category term="trip report"/>
    <category term="wac"/>
    <link href="http://laurelfan.com/2008/6/18/mt-baker-easton-glacier-june-14-15-2008" rel="alternate" type="text/html"/>
    <title>Mt Baker, Easton Glacier, June 14-15 2008</title>
<content type="html">
            &lt;p&gt;The trip started on Saturday, plodding up from Schreiber&#8217;s Meadow to a campsite on the Easton Glacier.  All 20 or so of us straggled in, started digging, and we soon had our multicolored tent village.  The sun was warm, the wind was light, and the mood was relaxed as we lazily set up tents, ate freeze dried dinners, and lounged around the rocks.  We tried to sleep under the still hot afternoon sun to prepare for getting up at midnight the &#8220;next day&#8221;.&lt;/p&gt;


	&lt;p&gt;The first hours of the ascent were like nothing else.  The glow of headlamps strung out along the route, neighboring peaks floating above pink clouds at dawn, seeing the moon set and sun rise. Though I was literally tied to four other people, my task as second on the rope was simple and constrained: keep walking, don&#8217;t fall, watch the rope in front of me.  In the darkness and silence, separated by 10 meters or so of rope from anyone else, I knew nothing of their private struggles with cold, nausea, dying batteries, uncertainty, impatience, and they knew nothing of mine.  I didn&#8217;t know if anyone else saw the same thin clouds drifting in front of the red setting moon, or the same drape of icicles off the edge of a crevasse.&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://laurelfan.com/assets/2008/6/17/baker_clouds.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;(&lt;a href=&quot;http://flickr.com/photos/laurelfan/sets/72157605657857119/&quot;&gt;more of my pictures&lt;/a&gt;)&lt;/p&gt;


	&lt;p&gt;The climb was uneventful (which was a good thing &#8211; nobody wants an event).  We reached the summit 5 or 6 hours after we started, spent some time taking pictures, and descended to camp before noon.  All that was left was a mildly unpleasant walk through soupy slush and on melting gravel roads and we were in the car heading back to sea level and back to the city.  We had glimpses of the mountain all the way home, but we were already in a different world of traffic, laundry, work, and hot showers.&lt;/p&gt;


	&lt;p&gt;(other pictures from &lt;a href=&quot;http://picasaweb.google.com/KristinKaupang/MtBaker2008&quot;&gt;Kristin&lt;/a&gt;, &lt;a href=&quot;http://picasaweb.google.com/sanford.stm/MtBaker&quot;&gt;John&lt;/a&gt;, &lt;a href=&quot;http://picasaweb.google.com/mdherndon3/MtBaker2008&quot;&gt;Daniel&lt;/a&gt;, &lt;a href=&quot;http://www.flickr.com/photos/27503402@N08/sets/72157605670149705/&quot;&gt;Cara&lt;/a&gt;, and &lt;a href=&quot;http://picasaweb.google.com/bengadbaw/MtBakerJune08&quot;&gt;Ben&lt;/a&gt;)&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;http://www.wacweb.org/Trips/TripReports/default.view?_mode=details&amp;amp;#38;RowId=441&quot;&gt;Official trip report on the &lt;span class=&quot;caps&quot;&gt;WAC&lt;/span&gt; site&lt;/a&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2008-05-22:34</id>
    <published>2008-05-22T18:57:00Z</published>
    <updated>2008-05-22T18:57:52Z</updated>
    <category term="Nonsense"/>
    <category term="hawaii"/>
    <category term="screenshot"/>
    <category term="surfboards"/>
    <link href="http://laurelfan.com/2008/5/22/surfboards" rel="alternate" type="text/html"/>
    <title>0 Surfboards</title>
<content type="html">
            &lt;p&gt;The web checkin form for Hawaiian Airlines asked me how many surfboards I will be bringing:&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://laurelfan.com/assets/2008/5/22/surfboards.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;Unfortunately I had to click 0.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2008-04-21:33</id>
    <published>2008-04-21T17:04:00Z</published>
    <updated>2008-04-21T20:47:13Z</updated>
    <category term="Code"/>
    <category term="bugs"/>
    <category term="code"/>
    <category term="emacs"/>
    <category term="features"/>
    <category term="ruby"/>
    <category term="testing"/>
    <link href="http://laurelfan.com/2008/4/21/bugs-and-features" rel="alternate" type="text/html"/>
    <title>Bugs and Features</title>
<content type="html">
            &lt;p&gt;Too bad this only works in unit tests:&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://laurelfan.com/assets/2008/4/21/bug_feature.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2008-04-08:32</id>
    <published>2008-04-08T00:33:00Z</published>
    <updated>2008-04-08T00:35:25Z</updated>
    <category term="Code"/>
    <category term="43things"/>
    <category term="graphs"/>
    <category term="gruff"/>
    <category term="robot coop"/>
    <category term="work"/>
    <link href="http://laurelfan.com/2008/4/8/playing-with-graphs" rel="alternate" type="text/html"/>
    <title>Playing with graphs</title>
<content type="html">
            &lt;p&gt;I&#8217;ve always liked playing with graphs and representing data, so when we we decided to implement a version of &lt;a href=&quot;http://morale.erikbenson.com/&quot;&gt;Buster&#8217;s Morale-O-Meter&lt;/a&gt; for the &lt;a href=&quot;http://blog.robotcoop.com/2008/01/31/43-things-profile-page/&quot;&gt;new 43 Things profile page&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;I started with &lt;a href=&quot;http://nubyonrails.com/pages/gruff&quot;&gt;gruff&lt;/a&gt;, but I wanted something a little more stylized and less techy looking, so I took out all of the axes and hacked it to use numbers as the points.  I kind of like how it turned out:&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://laurelfan.com/assets/2008/4/8/morale.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;


	&lt;p&gt;(This isn&#8217;t the final version, and the feature isn&#8217;t live on &lt;a href=&quot;http://www.43things.com&quot;&gt;43 Things&lt;/a&gt; yet, but it will be &#8220;soon&#8221;...)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2008-02-28:28</id>
    <published>2008-02-28T01:23:00Z</published>
    <updated>2008-02-28T01:52:56Z</updated>
    <category term="Code"/>
    <category term="Refactoring Of The Day"/>
    <category term="don't repeat yourself"/>
    <category term="dry"/>
    <category term="refactoring"/>
    <category term="ruby"/>
    <category term="ruby on rails"/>
    <category term="sql"/>
    <link href="http://laurelfan.com/2008/2/28/refactoring-sql-strings" rel="alternate" type="text/html"/>
    <title>Refactoring SQL Strings</title>
<content type="html">
            &lt;p&gt;Our apps have a lot of custom sql.  A lot of the time it&#8217;s easier just to write exactly the sql we want instead of messing around with ActiveRecord.  But any time two programming languages run in to each other things can get out of hand, so there are lots of opportunities for refactoring.&lt;/p&gt;


	&lt;h3&gt;Before:&lt;/h3&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;co&quot;&gt;NUM_STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/span&gt; = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;&amp;lt;-SQL&lt;/span&gt;&lt;/span&gt;.prettify_sql&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;        SELECT count(*) FROM listed_items &lt;tt&gt;
&lt;/tt&gt;        WHERE active = 1 &lt;tt&gt;
&lt;/tt&gt;        AND person_id = ?&lt;tt&gt;
&lt;/tt&gt;        AND ( (completed_on IS NULL &lt;tt&gt;
&lt;/tt&gt;        AND complete = 0 &lt;tt&gt;
&lt;/tt&gt;        AND give_up = 0 &lt;tt&gt;
&lt;/tt&gt;        AND posted_date &amp;gt; ? &lt;tt&gt;
&lt;/tt&gt;        AND posted_date &amp;lt; ?)&lt;tt&gt;
&lt;/tt&gt;        OR (completed_on &amp;gt; FROM_UNIXTIME(?) &lt;tt&gt;
&lt;/tt&gt;        AND completed_on &amp;lt; FROM_UNIXTIME(?) ) )&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;    SQL&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;co&quot;&gt;STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/span&gt; = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;&amp;lt;-SQL&lt;/span&gt;&lt;/span&gt;.prettify_sql&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;         SELECT * FROM listed_items&lt;tt&gt;
&lt;/tt&gt;         WHERE active = 1&lt;tt&gt;
&lt;/tt&gt;         AND person_id = ?&lt;tt&gt;
&lt;/tt&gt;         AND ( (completed_on IS NULL&lt;tt&gt;
&lt;/tt&gt;         AND complete = 0&lt;tt&gt;
&lt;/tt&gt;         AND give_up = 0 &lt;tt&gt;
&lt;/tt&gt;         AND posted_date &amp;gt; ?&lt;tt&gt;
&lt;/tt&gt;         AND posted_date &amp;lt; ?)&lt;tt&gt;
&lt;/tt&gt;         OR (completed_on &amp;gt; FROM_UNIXTIME(?)&lt;tt&gt;
&lt;/tt&gt;         AND completed_on &amp;lt; FROM_UNIXTIME(?) ) )&lt;tt&gt;
&lt;/tt&gt;         ORDER BY updated_date DESC&lt;tt&gt;
&lt;/tt&gt;         LIMIT 0, 100&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;    SQL&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;num_completed_or_started_items_during_range&lt;/span&gt;(start_date, stop_date)&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;co&quot;&gt;ListedItem&lt;/span&gt;.count_by_sql [&lt;span class=&quot;co&quot;&gt;NUM_STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/span&gt;, &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.id, start_date, stop_date, start_date, stop_date]&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;completed_or_started_items_during_range&lt;/span&gt;(start_date, stop_date, offset=&lt;span class=&quot;i&quot;&gt;0&lt;/span&gt;, limit=&lt;span class=&quot;i&quot;&gt;20&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;        items = &lt;span class=&quot;co&quot;&gt;ListedItem&lt;/span&gt;.find_by_sql [&lt;span class=&quot;co&quot;&gt;STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/span&gt;, &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.id, start_date, stop_date, start_date, stop_date]    &lt;tt&gt;
&lt;/tt&gt;        item_to_sort = &lt;span class=&quot;co&quot;&gt;Hash&lt;/span&gt;.new&lt;tt&gt;
&lt;/tt&gt;        items.each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |item| &lt;tt&gt;
&lt;/tt&gt;            item_to_sort[item.id] = item.completed_on ? &lt;span class=&quot;co&quot;&gt;Time&lt;/span&gt;.at(item.completed_on).to_i : item.posted_date&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        items.sort{|a,b| item_to_sort[a.id] &amp;lt;=&amp;gt; item_to_sort[b.id]}.reverse[offset .. (offset + limit - &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;)]&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;h3&gt;What&#8217;s wrong with this?&lt;/h3&gt;


	&lt;p&gt;First of all, there are no tests.  So first step is to write some.  If
I were just refactoring, I&#8217;d write tests that pass, but the reason I&#8217;m
in this code is that there&#8217;s a bug (long story short, the bug is
caused by the fact that a listed_item can have a non-null completed_on
but have completed = 0).  So I write a failing one that catches the
bug too.&lt;/p&gt;


	&lt;p&gt;The &lt;code&gt;STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/code&gt; and
&lt;code&gt;NUM_STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/code&gt; string constants are
almost identical.  So when I start changing the strings I realize that
I&#8217;m going to mess things up if I leave them duplicated like that (even
if I do the right thing, change both strings, it&#8217;ll be wrong for
the moment where I&#8217;m moving the cursor 10 lines down), so I stop and
factor out the where clause.&lt;/p&gt;


	&lt;p&gt;The next thing is that I don&#8217;t like the way the parameters for the &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt;
string work.  Parameters are repeated: if you look at
&lt;code&gt;completed_or_started_items_during_range&lt;/code&gt;, the &lt;code&gt;start_date&lt;/code&gt; and
&lt;code&gt;stop_date&lt;/code&gt; parameters are both in there twice.  Also, it&#8217;s annoying
and error prone to keep paging between the string and the methods (I
pasted the excerpt together, so it doesn&#8217;t look like it here, but this
file is arranged so all of the constants are together at the top of
the class definition, so there are several pages separating these
constants and methods) to remember what the parameters mean.  Rails
lets me use &lt;a href=&quot;http://api.rubyonrails.org/classes/ActiveRecord/Base.html&quot;&gt;named
bind variables&lt;/a&gt;
so I can give them names like a real programming language.&lt;/p&gt;


	&lt;p&gt;Ok, now that I have &lt;code&gt;&amp;gt; :start&lt;/code&gt; and &lt;code&gt;&amp;lt; :end&lt;/code&gt; instead of &lt;code&gt;&amp;gt; ?&lt;/code&gt; and &lt;code&gt;&amp;lt; ?&lt;/code&gt;, I&#8217;m more comfortable changing that to use the &lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/comparison-operators.html#operator_between&quot;&gt;&lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; between
operator&lt;/a&gt;,
and it looks a lot nicer (and one line shorter).  I realize that
between doesn&#8217;t quite have the semantics of &amp;lt; and &amp;gt;, but that&#8217;s fine
with me in this case.&lt;/p&gt;


	&lt;p&gt;It&#8217;s a good thing it&#8217;s shorter because I&#8217;m going to take a break from
refactoring and fix the bug, which involves adding a line.  Ok,
finally the tests pass.&lt;/p&gt;


	&lt;p&gt;We&#8217;re doing sorting and limiting with ruby.  Sometimes it&#8217;s faster to
do the sorting in ruby because the database is doing something dumb,
so I&#8217;ll have to keep track of the timings.  And sometimes it looks
nicer in Ruby if it&#8217;s complicated code.  But in this case the Ruby
code is 5 lines of really dense code (use of the ternary operator
&lt;em&gt;and&lt;/em&gt; the compact {} form of blocks makes it look like you&#8217;re trying
to hide something).  After staring at it for a while, it&#8217;s just doing
a
&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/comparison-operators.html#function_coalesce&quot;&gt;coalesce&lt;/a&gt;
and a normal limit with offset, so doing it in &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; looks nicer to me.&lt;/p&gt;


	&lt;h3&gt;After:&lt;/h3&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;co&quot;&gt;WHERE_STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/span&gt; = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;&amp;lt;-SQL&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;        WHERE active = 1 &lt;tt&gt;
&lt;/tt&gt;        AND person_id = :person_id&lt;tt&gt;
&lt;/tt&gt;        AND ( (completed_on IS NULL &lt;tt&gt;
&lt;/tt&gt;               AND complete = 0 &lt;tt&gt;
&lt;/tt&gt;               AND give_up = 0 &lt;tt&gt;
&lt;/tt&gt;               AND posted_date BETWEEN :start AND :end)&lt;tt&gt;
&lt;/tt&gt;           OR (completed_on BETWEEN FROM_UNIXTIME(:start) AND FROM_UNIXTIME(:end)&lt;tt&gt;
&lt;/tt&gt;               AND complete = 1 ) )&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;    SQL&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;co&quot;&gt;NUM_STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/span&gt; = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;&amp;lt;-SQL&lt;/span&gt;&lt;/span&gt;.prettify_sql&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;        SELECT count(*) FROM listed_items&lt;tt&gt;
&lt;/tt&gt;        &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;WHERE_STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;    SQL&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;co&quot;&gt;STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/span&gt; = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;lt;&amp;lt;-SQL&lt;/span&gt;&lt;/span&gt;.prettify_sql&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;        SELECT * FROM listed_items&lt;tt&gt;
&lt;/tt&gt;        &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;WHERE_STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;        ORDER BY COALESCE(completed_on, FROM_UNIXTIME(posted_date)) DESC&lt;tt&gt;
&lt;/tt&gt;        LIMIT :offset, :limit&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;    SQL&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;num_completed_or_started_items_during_range&lt;/span&gt;(start_date, stop_date)&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;co&quot;&gt;ListedItem&lt;/span&gt;.count_by_sql [&lt;span class=&quot;co&quot;&gt;NUM_STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;                                 {&lt;span class=&quot;sy&quot;&gt;:person_id&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.id,&lt;tt&gt;
&lt;/tt&gt;                                     &lt;span class=&quot;sy&quot;&gt;:start&lt;/span&gt; =&amp;gt; start_date,&lt;tt&gt;
&lt;/tt&gt;                                     &lt;span class=&quot;sy&quot;&gt;:end&lt;/span&gt; =&amp;gt; stop_date}]&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;completed_or_started_items_during_range&lt;/span&gt;(start_date, stop_date, offset=&lt;span class=&quot;i&quot;&gt;0&lt;/span&gt;, limit=&lt;span class=&quot;i&quot;&gt;20&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;co&quot;&gt;ListedItem&lt;/span&gt;.find_by_sql [&lt;span class=&quot;co&quot;&gt;STARTED_OR_COMPLETED_ITEMS_DURING_RANGE&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;                                {&lt;span class=&quot;sy&quot;&gt;:person_id&lt;/span&gt; =&amp;gt; &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.id,&lt;tt&gt;
&lt;/tt&gt;                                    &lt;span class=&quot;sy&quot;&gt;:start&lt;/span&gt; =&amp;gt; start_date,&lt;tt&gt;
&lt;/tt&gt;                                    &lt;span class=&quot;sy&quot;&gt;:end&lt;/span&gt; =&amp;gt; stop_date,&lt;tt&gt;
&lt;/tt&gt;                                    &lt;span class=&quot;sy&quot;&gt;:offset&lt;/span&gt; =&amp;gt; offset,&lt;tt&gt;
&lt;/tt&gt;                                    &lt;span class=&quot;sy&quot;&gt;:limit&lt;/span&gt; =&amp;gt; limit}]&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2008-02-27:27</id>
    <published>2008-02-27T01:50:00Z</published>
    <updated>2008-02-28T01:28:38Z</updated>
    <category term="Code"/>
    <category term="Refactoring Of The Day"/>
    <category term="plugin"/>
    <category term="rails"/>
    <category term="ruby"/>
    <category term="ruby on rails"/>
    <category term="time"/>
    <link href="http://laurelfan.com/2008/2/27/getting-the-weekday-name-and-month-name-from-a-time" rel="alternate" type="text/html"/>
    <title>Getting the weekday name and month name from a Time</title>
<content type="html">
            &lt;p&gt;Pop quiz: how do you get the month (as a name, not a number) of a Time in Ruby (without looking at the &lt;a href=&quot;http://www.ruby-doc.org/core/classes/Time.html#M000297&quot;&gt;Time#strftime documentation&lt;/a&gt;)?&lt;/p&gt;


All I remembered was that it was some meaningless looking format string.  Here&#8217;s my first guess:
&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;irb(main):&lt;span class=&quot;i&quot;&gt;001&lt;/span&gt;:&lt;span class=&quot;i&quot;&gt;0&lt;/span&gt;&amp;gt; &lt;span class=&quot;co&quot;&gt;Time&lt;/span&gt;.now.strftime(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;%a&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;=&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Tue&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


Oops, it&#8217;s actually:
&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;irb(main):&lt;span class=&quot;i&quot;&gt;002&lt;/span&gt;:&lt;span class=&quot;i&quot;&gt;0&lt;/span&gt;&amp;gt; &lt;span class=&quot;co&quot;&gt;Time&lt;/span&gt;.now.strftime(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;%b&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;=&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Feb&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;That doesn&#8217;t look very ruby-like. Aren&#8217;t % format strings for C programmers (whoever wrote the code I&#8217;m currently refactoring is probably a recovering C programmer.  They even use sprintf&#8230;)?&lt;/p&gt;


How about:
&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt; irb(main):&lt;span class=&quot;i&quot;&gt;003&lt;/span&gt;:&lt;span class=&quot;i&quot;&gt;0&lt;/span&gt;&amp;gt; &lt;span class=&quot;co&quot;&gt;Time&lt;/span&gt;.now.short_month_name&lt;tt&gt;
&lt;/tt&gt;=&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Feb&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;I&#8217;m sure others have done this already, but I couldn&#8217;t find it so I made my own Rails plugin, and stuck it here:
&lt;a href=&quot;http://svn.laurelfan.com/decorated_time/&quot;&gt;http://svn.laurelfan.com/decorated_time/&lt;/a&gt;, mostly to see if I could set up an svn repository on dreamhost.  The stuff that actually does the work is a total of about &lt;a href=&quot;http://svn.laurelfan.com/decorated_time/lib/decorated_time.rb&quot;&gt;4 lines of code&lt;/a&gt; since Ruby nicely lets me reopen the Time class at will.&lt;/p&gt;


	&lt;p&gt;(speaking of the day of week, I noticed that 1.9 added &lt;a href=&quot;http://www.ruby-doc.org/core-1.9/classes/Time.html#M000301&quot;&gt;monday?&lt;/a&gt;, &lt;a href=&quot;http://www.ruby-doc.org/core-1.9/classes/Time.html#M000302&quot;&gt;tuesday?&lt;/a&gt;, etc methods)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2008-02-19:26</id>
    <published>2008-02-19T19:36:00Z</published>
    <updated>2008-03-11T21:19:12Z</updated>
    <category term="Code"/>
    <category term="emacs"/>
    <category term="rails"/>
    <category term="refactoring"/>
    <category term="ruby"/>
    <link href="http://laurelfan.com/2008/2/19/fun-with-emacs" rel="alternate" type="text/html"/>
    <title>Fun with Emacs</title>
<content type="html">
            &lt;p&gt;One good part of doing a big refactoring is that I get to have fun with emacs.&lt;/p&gt;


	&lt;p&gt;I found a great step by step &lt;a href=&quot;http://xahlee.org/emacs/find_replace_inter.html&quot;&gt;tutorial&lt;/a&gt; with all the details.  But basically, first you get in to dired (directory editing), then mark the files you want to search through, and then do &lt;code&gt;dired-do-query-replace-regexp&lt;/code&gt;.&lt;/p&gt;


	&lt;p&gt;So for example, to replace &lt;code&gt;@params&lt;/code&gt; with &lt;code&gt;params&lt;/code&gt; in all controllers:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;M-x find-dired&lt;/code&gt;
	&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Run find in directory:&lt;/strong&gt; &lt;code&gt;app/controllers&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Run find (with args):&lt;/strong&gt; &lt;code&gt;-name '*.rb'&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;
	&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;%m&lt;/code&gt;
	&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Mark files (regexp):&lt;/strong&gt; &lt;code&gt;.&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;
	&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;M-x dired-do-query-replace-regexp&lt;/code&gt;
	&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Query replace in marked files (regexp):&lt;/strong&gt; &lt;code&gt;@params&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;&lt;strong&gt;Query replace @params by:&lt;/strong&gt; &lt;code&gt;params&lt;/code&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Dired is fun stuff like emacs&#8217;s other &#8220;everything is a buffer!!&#8221; things (just like unix&#8217;s &#8220;everything is a file!!&#8221;).  I&#8217;m not quite emacs-hacker enough to use it as a shell for extended periods of time though.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2008-02-14:25</id>
    <published>2008-02-14T22:04:00Z</published>
    <updated>2008-02-14T22:15:02Z</updated>
    <category term="Code"/>
    <category term="exceptions"/>
    <category term="refactoring"/>
    <category term="robotcoop"/>
    <category term="ruby"/>
    <link href="http://laurelfan.com/2008/2/14/reraising-exceptions-in-ruby" rel="alternate" type="text/html"/>
    <title>Reraising Exceptions in Ruby</title>
<content type="html">
            Don&#8217;t do this:
&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;r&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;Exception&lt;/span&gt; =&amp;gt; e&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;c&quot;&gt;# other stuff&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      raise &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;e.class&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;e.message&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


Do this:
&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;    &lt;span class=&quot;r&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;Exception&lt;/span&gt; =&amp;gt; e&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;c&quot;&gt;# other stuff&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      raise&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;raise without any arguments will reraise the current exception, complete with class, message, and stack trace.&lt;/p&gt;


	&lt;p&gt;See also &lt;a href=&quot;http://ruby-doc.org/docs/ProgrammingRuby/html/tut_exceptions.html&quot;&gt;Programming Ruby&lt;/a&gt; on exceptions.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2008-01-17:16</id>
    <published>2008-01-17T23:36:00Z</published>
    <updated>2008-01-17T23:37:54Z</updated>
    <category term="Code"/>
    <category term="apache rewrite"/>
    <category term="dns"/>
    <category term="hacker"/>
    <category term="seo"/>
    <link href="http://laurelfan.com/2008/1/17/stupid-seo-tricks" rel="alternate" type="text/html"/>
    <title>Stupid SEO Tricks</title>
<content type="html">
            &lt;p&gt;We found a site that looked like it was stealing our content.  Then we
go there, and it&#8217;s exactly the same site! What are they doing? Are
they crawling the site and sucking up all of our pages?  Proxying us?&lt;/p&gt;


But wait:
&lt;pre&gt; &amp;gt; dig d****list.com
d****list.com.          1736    IN      A       209.61.175.237
&lt;/pre&gt;

That IP address looks familiar!
&lt;pre&gt; &amp;gt; dig 43things.com  
43things.com.           86400   IN      A       209.61.175.237
&lt;/pre&gt;

	&lt;p&gt;Why would someone do that? Is it some &lt;span class=&quot;caps&quot;&gt;SEO&lt;/span&gt; trick to steal our google
rank for their domain?&lt;/p&gt;


	&lt;p&gt;Josh noticed that the domain was registered to someone in China (we
don&#8217;t think this is a good person trying to get us around the Great
Firewall&#8212;a test tool we tried showed that 43things.com isn&#8217;t
blocked). So we decided to cause them some trouble:&lt;/p&gt;


&lt;pre&gt;    RewriteCond %{HTTP_HOST} .*d****list.com$
    RewriteRule ^/(.*) http://en.wikipedia.org/wiki/Tiananmen_Square_protests_of_1989 [R]
&lt;/pre&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2008-01-15:15</id>
    <published>2008-01-15T19:50:00Z</published>
    <updated>2008-01-16T20:03:20Z</updated>
    <category term="Code"/>
    <category term="memory"/>
    <category term="memory leak"/>
    <category term="ps"/>
    <category term="ruby"/>
    <link href="http://laurelfan.com/2008/1/15/ruby-memory-usage" rel="alternate" type="text/html"/>
    <title>Ruby Memory Usage</title>
<content type="html">
            &lt;p&gt;Tracking down a memory leak?  Here&#8217;s a way to find the memory usage of the current process on Ruby:&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;memory_usage = &lt;span class=&quot;sh&quot;&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;ps -o rss= -p &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;co&quot;&gt;Process&lt;/span&gt;.pid&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;/span&gt;.to_i &lt;span class=&quot;c&quot;&gt;# in kilobytes &lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;&lt;strong&gt;-o rss=&lt;/strong&gt; asks ps to print only the &lt;span class=&quot;caps&quot;&gt;RSS&lt;/span&gt; (Resident Set Size, or physical memory used).  You could also use vsz/vsize (virtual memory).  The hanging = sign sets the header text to a blank string so you don&#8217;t have to filter out the header line.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;-p #{&lt;a href=&quot;http://ruby-doc.org/core/classes/Process.html#M003190&quot;&gt;Process.pid&lt;/a&gt;}&lt;/strong&gt; limits the ps to only show the current process.&lt;/p&gt;


	&lt;p&gt;The backticks are kind of hacky, but this cuts down on the piping and grepping.  It works on all of the unixes I&#8217;ve tried (Linux, FreeBSD, &lt;span class=&quot;caps&quot;&gt;OSX&lt;/span&gt;), but of course ps is notoriously nonstandardized.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2008-01-10:12</id>
    <published>2008-01-10T22:29:00Z</published>
    <updated>2008-01-12T07:17:02Z</updated>
    <category term="Code"/>
    <category term="class"/>
    <category term="mysql"/>
    <category term="performance"/>
    <category term="performance tuning"/>
    <link href="http://laurelfan.com/2008/1/10/mysql-performance-tuning-links" rel="alternate" type="text/html"/>
    <title>MySQL Performance Tuning Links</title>
<content type="html">
            &lt;p&gt;Here are some links to things mentioned at the &lt;a href=&quot;http://www.mysql.com/training/courses/performance_tuning.html&quot;&gt;MySQL Performance Tuning&lt;/a&gt; class that I&#8217;ve been attending this past week.&lt;/p&gt;


Day 1 Morning: MySQL website, basics, upsell for more training classes and certifications
	&lt;ul&gt;
	&lt;li&gt;Documentation pages for &lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/mysqld-option-tables.html&quot;&gt;all options and variables&lt;/a&gt; and &lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/server-system-variables.html&quot;&gt;the system variables&lt;/a&gt; page (which indicates which ones are dynamic).&lt;/li&gt;
	&lt;/ul&gt;


Day 1 Afternoon: architecture overview
	&lt;ul&gt;
	&lt;li&gt;Documentation for the &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.0/en/innodb-transaction-model.html&quot;&gt;innodb transaction model&lt;/a&gt;
	&lt;ul&gt;
	&lt;li&gt;multiple versions of uncommitted rows are stored on disk&lt;/li&gt;
	&lt;/ul&gt;
	&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/show-table-status.html&quot;&gt;&lt;span class=&quot;caps&quot;&gt;SHOW TABLE STATUS&lt;/span&gt;&lt;/a&gt; shows statistics like table size, number of rows (it&#8217;s actually an approximation)&lt;/li&gt;
	&lt;/ul&gt;


Day 2 Morning: data types, benchmarking, logs, admin tools, indexes
	&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/slow-query-log.html&quot;&gt;slow query log&lt;/a&gt; and mysqldumpslow (which summarizes the information in the slow query log)&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/procedure-analyse.html&quot;&gt;&lt;span class=&quot;caps&quot;&gt;PROCEDURE&lt;/span&gt; &lt;acronym title=&quot;&quot;&gt;ANALYSE&lt;/acronym&gt;&lt;/a&gt;, which tries to figure out the optimal data type for the columns of a table&lt;/li&gt;
		&lt;li&gt;Benchmarking tools: &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.1/en/mysqlslap.html&quot;&gt;mysqlslap&lt;/a&gt;, which comes with 5.1 and might not work with 4.1 and &lt;a href=&quot;http://vegan.net/tony/supersmack/&quot;&gt;Super Smack&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://hackmysql.com/mysqlreport&quot;&gt;mysqlreport&lt;/a&gt;, a more human readable version of &lt;span class=&quot;caps&quot;&gt;SHOW STATUS&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://jeremy.zawodny.com/mysql/mytop/&quot;&gt;mytop&lt;/a&gt;, a top-view of &lt;span class=&quot;caps&quot;&gt;SHOW PROCESSLIST&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://www.xaprb.com/blog/2006/07/02/innotop-mysql-innodb-monitor/&quot;&gt;innotop&lt;/a&gt; monitors all kinds of innodb stuff&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://sourceforge.net/projects/maatkit&quot; title=&quot;formerly MySQL Toolkit&quot;&gt;Maatkit&lt;/a&gt; contains essential command-line tools for MySQL, such as table checksums, a query profiler, and a visual &lt;span class=&quot;caps&quot;&gt;EXPLAIN&lt;/span&gt; tool. It provides missing features such as checking whether slaves have the same data as the master.&lt;/li&gt;
	&lt;/ul&gt;


Day 2 Afternoon: statement tuning, query cache
	&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.mysqlperformanceblog.com/2006/07/24/extended-explain/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;EXPLAIN EXTENDED&lt;/span&gt;&lt;/a&gt; and then &lt;span class=&quot;caps&quot;&gt;SHOW WARNINGS&lt;/span&gt; will show you the actual &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; being executed (which can be different if the optimizer wants to rewrite it).&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/query-cache.html&quot;&gt;Query cache documentation&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


Day 3 Morning: server configuration
	&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/table-cache.html&quot;&gt;table_cache&lt;/a&gt; setting (aka table_definition_cache and table_open_cache in 5.1) how many file descriptors are used to open table files.&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/too-many-connections.html&quot;&gt;max_connections&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/server-options.html#option_mysqld_open-files-limit&quot;&gt;open_files_limit&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/miscellaneous-optimization-tips.html&quot;&gt;thread_cache_size&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


Day 3 Afternoon: MyISAM
	&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/myisam-storage-engine.html&quot;&gt;MyISAM storage engine&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/spatial-extensions.html&quot;&gt;spatial index&lt;/a&gt; for efficiently searching geographical data&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/myisam-key-cache.html&quot;&gt;MyISAM key cache&lt;/a&gt; for caching MyISAM indexes&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/merge-storage-engine.html&quot;&gt;&lt;span class=&quot;caps&quot;&gt;MERGE&lt;/span&gt; storage engine&lt;/a&gt; concatenates (like &lt;span class=&quot;caps&quot;&gt;UNION ALL&lt;/span&gt; not &lt;span class=&quot;caps&quot;&gt;UNION&lt;/span&gt;) more than one MyISAM table with the same schema&lt;/li&gt;
	&lt;/ul&gt;


Day 4 Morning: InnoDB, Transactions, Locking
	&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/5.0/en/innodb.html&quot;&gt;InnoDB storage engine&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;Configuring InnoDB to use &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.0/en/multiple-tablespaces.html&quot;&gt;a separate file per table&lt;/a&gt; (instead of the default of one shared ibdata file for all tables)&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/5.1/en/partitioning.html&quot;&gt;Partitioning&lt;/a&gt; (new in 5.1), partitions a table over multiple files.&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/miscellaneous-functions.html&quot;&gt;Advisory locks&lt;/a&gt;  are semaphores implemented in MySQL (not InnoDB specific).  These don&#8217;t affect table locks.&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/innodb-next-key-locking.html&quot;&gt;Next key/gap locks&lt;/a&gt; means that when a locking &lt;span class=&quot;caps&quot;&gt;SELECT&lt;/span&gt; on a range of indexed values is done, the table is also locked for INSERTs within that range (and the gap before that range!).&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://www.mysqlperformanceblog.com/2006/08/04/innodb-double-write/&quot;&gt;doublewrite setting&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/innodb-parameters.html&quot;&gt;innodb_flush_log_at_trx_commit&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/file-space-management.html&quot;&gt;Disk I/O&lt;/a&gt;&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/innodb-monitor.html&quot;&gt;InnoDB status and monitors&lt;/a&gt; that print information about the InnoDB internal state&lt;/li&gt;
		&lt;li&gt;More about &lt;a href=&quot;http://www.mysqlperformanceblog.com/2006/07/17/show-innodb-status-walk-through/&quot;&gt;&lt;span class=&quot;caps&quot;&gt;SHOW INNODB STATUS&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


Day 4 Afternoon: Other Storage Engines: Memory, Blackhole, &lt;span class=&quot;caps&quot;&gt;CSV&lt;/span&gt;, Falcon
	&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/memory-storage-engine.html&quot;&gt;Memory&lt;/a&gt; is a table that&#8217;s stored completely in memory&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/blackhole-storage-engine.html&quot;&gt;Blackhole&lt;/a&gt; is like /dev/null&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/csv-storage-engine.html&quot;&gt;&lt;span class=&quot;caps&quot;&gt;CSV&lt;/span&gt;&lt;/a&gt; yes, Comma Separated Value file&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/6.0/en/se-falcon.html&quot;&gt;Falcon&lt;/a&gt; the 6.0 storage engine that will solve all of our perf problems&lt;/li&gt;
		&lt;li&gt;&lt;a href=&quot;http://dev.mysql.com/doc/refman/4.1/en/example-storage-engine.html&quot;&gt;Example&lt;/a&gt; for writing your own storage engine&lt;/li&gt;
	&lt;/ul&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2008-01-08:13</id>
    <published>2008-01-08T06:01:00Z</published>
    <updated>2008-01-08T18:41:40Z</updated>
    <category term="plural"/>
    <category term="rails"/>
    <category term="rails 2.0"/>
    <category term="ruby"/>
    <category term="ruby on rails"/>
    <category term="singular"/>
    <link href="http://laurelfan.com/2008/1/8/singular-and-plural-in-rails" rel="alternate" type="text/html"/>
    <title>Singular and Plural in Rails</title>
<content type="html">
            &lt;p&gt;One powerful and confusing thing in rails is how it wires up different things (database tables, models, controllers, urls&#8230;) with the &#8220;same&#8221; name.  Rails uses both singular and plural, and is opinionated about grammar.  One clue about what Rails wants is what happens when you generate a resource.&lt;/p&gt;


&lt;em&gt;&amp;gt; ./script/generate resource pancake&lt;/em&gt;
&lt;pre&gt;&lt;code&gt;      create  db/migrate/001_create_pancakes.rb # plural 
      create  app/models/pancake.rb # singular
      create  test/unit/pancake_test.rb # singular
      create  test/fixtures/pancakes.yml # plural
      create  app/controllers/pancakes_controller.rb # plural
      create  test/functional/pancakes_controller_test.rb # plural
      create  app/views/pancakes # plural
      create  app/helpers/pancakes_helper.rb # plural
      route  map.resources :pancakes # plural
&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The &lt;strong&gt;database table&lt;/strong&gt; is &lt;strong&gt;plural&lt;/strong&gt;.&lt;/p&gt;


&lt;em&gt;db/migrate/001_create_pancakes.rb&lt;/em&gt;
&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;CreatePancakes&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Migration&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.up&lt;tt&gt;
&lt;/tt&gt;    create_table &lt;span class=&quot;sy&quot;&gt;:pancakes&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |t|&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;The &lt;strong&gt;model&lt;/strong&gt; is &lt;strong&gt;singular&lt;/strong&gt;, and associations are pluralization sensitive (the associations should be easy).&lt;/p&gt;


&lt;em&gt;app/models/pancake.rb&lt;/em&gt;
&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;Pancake&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ActiveRecord&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  belongs_to &lt;span class=&quot;sy&quot;&gt;:eater&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# singular&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  has_many &lt;span class=&quot;sy&quot;&gt;:ingredients&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# plural&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;This is probably the confusing part: resource-based &lt;strong&gt;controllers&lt;/strong&gt; should be &lt;strong&gt;plural&lt;/strong&gt; (which means the directory for the &lt;strong&gt;views&lt;/strong&gt; and the &lt;strong&gt;helper&lt;/strong&gt; is also &lt;strong&gt;plural&lt;/strong&gt;).&lt;/p&gt;


&lt;em&gt;app/controllers/pancake_controller.rb&lt;/em&gt;
&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;span class=&quot;r&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;PancakesController&lt;/span&gt; &amp;lt; &lt;span class=&quot;co&quot;&gt;ApplicationController&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;The &lt;strong&gt;route&lt;/strong&gt; name and the &lt;strong&gt;urls&lt;/strong&gt; it generates/recognizes are &lt;strong&gt;plural&lt;/strong&gt;.&lt;/p&gt;


&lt;em&gt;config/routes.rb&lt;/em&gt;
&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;  &lt;span class=&quot;c&quot;&gt;# /pancakes/:id =&amp;gt; PancakesController#show, etc&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  map.resources &lt;span class=&quot;sy&quot;&gt;:pancakes&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;The &lt;strong&gt;rake routes&lt;/strong&gt; command (also a good reminder of what to call your controller actions) will tell you what routes are generated from this.  Here are a few of the pancake routes:&lt;/p&gt;


&lt;em&gt;&amp;gt; rake routes&lt;/em&gt;
	&lt;table&gt;
		&lt;tr&gt;
			&lt;td&gt;# named route&lt;/td&gt;
			&lt;td&gt;&lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; verb&lt;/td&gt;
			&lt;td&gt;path&lt;/td&gt;
			&lt;td&gt;generated parameters&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;pancakes&lt;/td&gt;
			&lt;td&gt; GET&lt;/td&gt;
			&lt;td&gt;    /pancakes&lt;/td&gt;
			&lt;td&gt;                        {:controller=&amp;gt;&#8221;pancakes&#8221;, :action=&amp;gt;&#8221;index&#8221;}&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt; &amp;nbsp;      &lt;/td&gt;
			&lt;td&gt;&lt;span class=&quot;caps&quot;&gt;POST&lt;/span&gt;&lt;/td&gt;
			&lt;td&gt;   /pancakes&lt;/td&gt;
			&lt;td&gt;                        {:controller=&amp;gt;&#8221;pancakes&#8221;, :action=&amp;gt;&#8221;create&#8221;}&lt;/td&gt;
		&lt;/tr&gt;
		&lt;tr&gt;
			&lt;td&gt;pancake&lt;/td&gt;
			&lt;td&gt; GET&lt;/td&gt;
			&lt;td&gt;    /pancakes/:id&lt;/td&gt;
			&lt;td&gt;                    {:controller=&amp;gt;&#8221;pancakes&#8221;, :action=&amp;gt;&#8221;show&#8221;}&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/table&gt;




	&lt;p&gt;(Is this right?  Or am I still confused?)&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2007-12-26:11</id>
    <published>2007-12-26T19:48:00Z</published>
    <updated>2007-12-26T19:48:37Z</updated>
    <category term="Nonsense"/>
    <category term="43things"/>
    <category term="anorexia"/>
    <category term="logs"/>
    <link href="http://laurelfan.com/2007/12/26/anorexia-causes-inability-to-spell" rel="alternate" type="text/html"/>
    <title>Anorexia Causes Inability to Spell</title>
<content type="html">
            &lt;p&gt;From our logs:&lt;/p&gt;


	&lt;blockquote&gt;
		&lt;p&gt;Dec 26 00:00:00 43things: Parameters: {&#8220;action&#8221;=&amp;gt;&#8221;query&#8221;, &#8220;q&#8221;=&amp;gt;&#8221;&lt;strong&gt;hw to be aorexic&lt;/strong&gt;&#8221;, &#8220;controller&#8221;=&amp;gt;&#8221;search&#8221;}&lt;/p&gt;
	&lt;/blockquote&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2007-12-18:9</id>
    <published>2007-12-18T18:14:00Z</published>
    <updated>2007-12-18T18:15:42Z</updated>
    <category term="Nonsense"/>
    <category term="web 2.0"/>
    <link href="http://laurelfan.com/2007/12/18/instant-web-2-0" rel="alternate" type="text/html"/>
    <title>Instant Web 2.0</title>
<content type="html">
            &lt;p&gt;2.0-ize the entire web!&lt;/p&gt;


	&lt;p&gt;&lt;img src=&quot;http://laurelfan.com/assets/2007/12/18/instant_web_20.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://laurelfan.com/">
    <author>
      <name>laurel</name>
    </author>
    <id>tag:laurelfan.com,2007-12-11:4</id>
    <published>2007-12-11T01:34:00Z</published>
    <updated>2007-12-11T01:36:03Z</updated>
    <category term="Code"/>
    <category term="facebook"/>
    <category term="flexmock"/>
    <category term="mocks"/>
    <category term="rfacebook"/>
    <category term="ruby"/>
    <category term="testing"/>
    <link href="http://laurelfan.com/2007/12/11/mocking" rel="alternate" type="text/html"/>
    <title>Mocking Facebook</title>
<content type="html">
            &lt;p&gt;Any sort of interaction with external services is a serious hassle when trying to do &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt; or even Development with Some Tests In It.  External services could include anything from web services like facebook to our own drb ferret service (the real purists would include your database in this, but one step at a time&#8230;).  The worst thing to do is to actually interact with the service in the test&#8212;it makes tests slow, dependent on a network connection, potentially messes up production data, etc.&lt;/p&gt;


	&lt;p&gt;The solution is mock objects.  For a long time I did mock objects the wrong way, by inheriting from the real object and essentially reimplementing the functionality.  This is pretty painful, so I didn&#8217;t do it much.  Fortunately, really good mocking frameworks are everywhere now.  Ruby even has two of them&#8212;&lt;a href=&quot;http://mocha.rubyforge.org/&quot;&gt;mocha&lt;/a&gt; and &lt;a href=&quot;http://onestepback.org/software/flexmock/&quot;&gt;flexmock&lt;/a&gt;.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;test_facebook_publish_complete_goal&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@mock_fbsession&lt;/span&gt; = valid_facebook_session&lt;tt&gt;
&lt;/tt&gt;      &lt;tt&gt;
&lt;/tt&gt;      person = people(&lt;span class=&quot;sy&quot;&gt;:rob_cooper&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;      person.facebook_session = &lt;span class=&quot;iv&quot;&gt;@mock_fbsession&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@mock_team_member&lt;/span&gt; = flexmock&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@mock_team_member&lt;/span&gt;.should_receive(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;goal.name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).and_return(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;write a facebook app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@mock_team_member&lt;/span&gt;.should_receive(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;goal_is_complete?&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).and_return(&lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@mock_team_member&lt;/span&gt;.should_receive(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;give_up?&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).and_return(&lt;span class=&quot;pc&quot;&gt;false&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@mock_fbsession&lt;/span&gt;.should_receive(&lt;span class=&quot;sy&quot;&gt;:feed_publishActionOfUser&lt;/span&gt;).&lt;tt&gt;
&lt;/tt&gt;        with(&lt;span class=&quot;sy&quot;&gt;:title&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;has completed the goal: write a facebook app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;).once&lt;tt&gt;
&lt;/tt&gt;      &lt;tt&gt;
&lt;/tt&gt;      person.facebook_publish_goal_activity(&lt;span class=&quot;iv&quot;&gt;@mock_team_member&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;

&lt;/div&gt;

	&lt;p&gt;&lt;strong&gt;First some preliminaries&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;First I need to set up a mock FacebookSession (I use a pseudomock wrapped around a real FacebookWebSession because I&#8217;m lazy and don&#8217;t want to mock the session_id and session_key accessors).  The RFacebook library obviously wasn&#8217;t implemented &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt;, so there are a few ways that it&#8217;s a bit messy to test.&lt;/p&gt;


	&lt;p&gt;&lt;a href=&quot;#&quot;&gt;Hide the description&lt;/a&gt;
&lt;div&gt;
&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;valid_facebook_session&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      mock_session =  flexmock(&lt;span class=&quot;co&quot;&gt;RFacebook&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;FacebookWebSession&lt;/span&gt;.new(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;))&lt;tt&gt;
&lt;/tt&gt;      mock_session.should_receive(&lt;span class=&quot;sy&quot;&gt;:is_valid?&lt;/span&gt;).and_return(&lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;      mock_session.should_receive(&lt;span class=&quot;sy&quot;&gt;:is_ready?&lt;/span&gt;).and_return(&lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;return&lt;/span&gt; mock_session&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;
&lt;/p&gt;


Next, I&#8217;m making a mock team member (a TeamMember is a model that represents a Person doing a Goal), but this time I use a plain mock that doesn&#8217;t reference the &#8220;real&#8221; object at all.  And check out this line:
&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@mock_team_member&lt;/span&gt;.should_receive(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;goal.name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).and_return(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;write a facebook app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;This call is actually making a chain of mock objects, so I can call @mock_team_member.goal.name without having to explicitly create a mock object for the goal.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Here&#8217;s the guts&lt;/strong&gt;&lt;/p&gt;


	&lt;p&gt;The first line sets up the &lt;em&gt;expectation&lt;/em&gt;&#8212;kind of like an assert.&lt;/p&gt;


&lt;table class=&quot;CodeRay&quot;&gt;&lt;tr&gt;
  &lt;td title=&quot;click to toggle&quot; class=&quot;line_numbers&quot;&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class=&quot;code&quot;&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@mock_fbsession&lt;/span&gt;.should_receive(&lt;span class=&quot;sy&quot;&gt;:feed_publishActionOfUser&lt;/span&gt;).&lt;tt&gt;
&lt;/tt&gt;        with(&lt;span class=&quot;sy&quot;&gt;:title&lt;/span&gt; =&amp;gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;has completed the goal: write a facebook app&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;).once&lt;tt&gt;
&lt;/tt&gt;      &lt;tt&gt;
&lt;/tt&gt;      person.facebook_publish_goal_activity(&lt;span class=&quot;iv&quot;&gt;@mock_team_member&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;


	&lt;p&gt;The second line calls the method we wants to test.  The expectation (that the method feed_publishActionOfUser will be called once with the specified arguments) will magically be evaluated when the test is over.&lt;/p&gt;
          </content>  </entry>
</feed>
