<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Jacob Swanner</title>
 <link href="https://jacobswanner.com/atom.xml" rel="self"/>
 <link href="https://jacobswanner.com/"/>
 <updated>2025-05-05T17:07:54+00:00</updated>
 <id>https://jacobswanner.com</id>
 <author>
   <name>Jacob Swanner</name>
   <email>site@jacobswanner.com</email>
 </author>

 
 <entry>
   <title>PostgreSQL MERGE and Sequences</title>
   <link href="https://jacobswanner.com/development/2022/postgresql-merge-and-sequences/"/>
   <updated>2022-10-30T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2022/postgresql-merge-and-sequences</id>
   <content type="html">&lt;p&gt;Recently released &lt;a href=&quot;https://www.postgresql.org/about/news/postgresql-15-released-2526/&quot;&gt;PostgreSQL version 15&lt;/a&gt; contains a new command:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MERGE&lt;/code&gt;. We can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MERGE&lt;/code&gt; to do “upsert” operations, much like when providing
an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ON CONFLICT&lt;/code&gt; clause to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INSERT&lt;/code&gt;, but &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MERGE&lt;/code&gt; can be used for other tasks as
well. There’s an interesting difference when doing upserts between the two
commands, and that’s what we’re going to discuss here.&lt;/p&gt;

&lt;h2 id=&quot;using-insert--on-conflict&quot;&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INSERT&lt;/code&gt; … &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ON CONFLICT&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Suppose we have a table defined as (note the unique email constraint):&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;CREATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;TABLE&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bigserial&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;PRIMARY&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;KEY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;citext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;UNIQUE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After the table is created, we can run the follow &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INSERT&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ON CONFLICT&lt;/code&gt; 4
times. The first time will insert a new record, and the other times will update
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;name&lt;/code&gt; since the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;email&lt;/code&gt; conflicts with the existing record:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;alex@email.com&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Alex&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CONFLICT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DO&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EXCLUDED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, we run the following query to insert another record:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;billie@email.com&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Billie&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CONFLICT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;DO&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;EXCLUDED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Afterwards, we query the table for all of its records:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; id |      email       |  name
----+------------------+--------
  1 | alex@email.com   | Alex
  5 | billie@email.com | Billie
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we can see, there’s a gap in the value of the IDs, and that’s because the
sequence used for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; column is advanced with every &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INSERT&lt;/code&gt; query even it
ends up doing an update via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ON CONFLICT&lt;/code&gt;. Because of that behavior, it’s
highly suggested to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bigint&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bigserial&lt;/code&gt; for auto-incrementing columns when
you are going to upsert data into the table.&lt;/p&gt;

&lt;h2 id=&quot;using-merge&quot;&gt;Using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MERGE&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;Now, let’s see what happens if we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MERGE&lt;/code&gt; instead. We’ll keep the table as
it was, and we’ll upsert that last record several times using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MERGE&lt;/code&gt; query:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;MERGE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;USING&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;billie@email.com&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Billie&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MATCHED&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MATCHED&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we then use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MERGE&lt;/code&gt; to insert a new record:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;MERGE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;INTO&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;USING&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;charlie@email.com&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Charlie&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ON&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;NOT&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MATCHED&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;VALUES&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WHEN&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MATCHED&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;THEN&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And check all the records:&lt;/p&gt;

&lt;div class=&quot;language-sql highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;people&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; id |       email       |  name
----+-------------------+---------
  1 | alex@email.com    | Alex
  5 | billie@email.com  | Billie
  6 | charlie@email.com | Charlie
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We now see that there’s no gap with the ID of the last two records, and that’s
because our sequence was not advanced when the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MERGE&lt;/code&gt; was used as an update
task. Granted, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MERGE&lt;/code&gt; queries are more verbose than the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;INSERT&lt;/code&gt;…&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ON
CONFLICT&lt;/code&gt; equivalents, but I believe that verboseness also provides clarity
into the intentions of the query. I should also note that neither &lt;a href=&quot;https://hexdocs.pm/ecto/Ecto.html&quot;&gt;Ecto&lt;/a&gt;
nor &lt;a href=&quot;https://rubygems.org/gems/activerecord&quot;&gt;ActiveRecord&lt;/a&gt; currently provide first class support for
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MERGE&lt;/code&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>NimbleCSV: Parsing into Elixir Maps</title>
   <link href="https://jacobswanner.com/development/2022/nimble-csv-maps/"/>
   <updated>2022-07-15T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2022/nimble-csv-maps</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://hex.pm/packages/nimble_csv&quot;&gt;NimbleCSV&lt;/a&gt; is a great option when parsing CSV files in Elixir. By
design, it will only give you the data for each row as a &lt;a href=&quot;https://hexdocs.pm/elixir/List.html&quot;&gt;List&lt;/a&gt; –
there’s no option for it to generate a &lt;a href=&quot;https://hexdocs.pm/elixir/Map.html&quot;&gt;Map&lt;/a&gt; (using the headers as keys)
for each row. When processing data from CSV files, I much prefer to use maps
instead of lists, that way the order of the columns in the file doesn’t matter.
Luckily, we can using &lt;a href=&quot;https://hexdocs.pm/elixir/Stream.html#transform/3&quot;&gt;Stream.transform/3&lt;/a&gt; to generate a map
for each row of data:&lt;/p&gt;

&lt;div class=&quot;language-elixir highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NimbleCSV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RFC4180&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;as:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CSV&lt;/span&gt;

&lt;span class=&quot;s2&quot;&gt;&quot;path/to/file.csv&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stream!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CSV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse_stream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;skip_headers:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{[],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And, that’s it! Quite a bit is happening in a few lines of code. For the
initial accumulator, we need to use something that will not match the first row
of the CSV, so &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; or some other atom is a great choice here. We match on our
initial accumulator in the first clause of the function to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Stream.transform/3&lt;/code&gt;
to know we’re on the headers row and we’ll use the headers as the accumulator
from thereon. For the rest of the rows, since we know the order of the headers
will correspond to the order of the values in each row, we zip the headers and
row values together into a list of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{key, value}&lt;/code&gt; tuples and then turn that
list into a map. After that we have an &lt;a href=&quot;https://hexdocs.pm/elixir/Enumerable.html&quot;&gt;Enumerable&lt;/a&gt; of maps that we
can use for processing the data.&lt;/p&gt;

&lt;p&gt;To see it in action, I’ll use a String instead of a File:&lt;/p&gt;

&lt;div class=&quot;language-elixir highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NimbleCSV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RFC4180&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;as:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CSV&lt;/span&gt;

&lt;span class=&quot;sd&quot;&gt;&quot;&quot;&quot;
name,age
Alex,21
Billie,8
Charlie,32
&quot;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CSV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;skip_headers:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{[],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   %{&quot;age&quot; =&amp;gt; &quot;21&quot;, &quot;name&quot; =&amp;gt; &quot;Alex&quot;},&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   %{&quot;age&quot; =&amp;gt; &quot;8&quot;, &quot;name&quot; =&amp;gt; &quot;Billie&quot;},&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   %{&quot;age&quot; =&amp;gt; &quot;32&quot;, &quot;name&quot; =&amp;gt; &quot;Charlie&quot;}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A similar approach can be taken with
&lt;a href=&quot;https://hexdocs.pm/elixir/Enum.html#flat_map_reduce/3&quot;&gt;Enum.flat_map_reduce/3&lt;/a&gt;, if you really wanted:&lt;/p&gt;

&lt;div class=&quot;language-elixir highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NimbleCSV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RFC4180&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;as:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CSV&lt;/span&gt;

&lt;span class=&quot;sd&quot;&gt;&quot;&quot;&quot;
name,age
Alex,21
Billie,8
Charlie,32
&quot;&quot;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CSV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;skip_headers:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;flat_map_reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{[],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Enum&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;row&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;|&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# [&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   %{&quot;age&quot; =&amp;gt; &quot;21&quot;, &quot;name&quot; =&amp;gt; &quot;Alex&quot;},&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   %{&quot;age&quot; =&amp;gt; &quot;8&quot;, &quot;name&quot; =&amp;gt; &quot;Billie&quot;},&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   %{&quot;age&quot; =&amp;gt; &quot;32&quot;, &quot;name&quot; =&amp;gt; &quot;Charlie&quot;}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Kernel.elem/2&lt;/code&gt; at the end is there to grab the resulting
enumerable and ignore the accumulator.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Production treatment of scripts</title>
   <link href="https://jacobswanner.com/development/2018/production-treatment-of-scripts/"/>
   <updated>2018-04-20T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2018/production-treatment-of-scripts</id>
   <content type="html">&lt;h2 id=&quot;applying-production-code-treatment-to-utilityscripts&quot;&gt;Applying production code treatment to utility scripts&lt;/h2&gt;

&lt;p&gt;Those single-file, single-purpose scripts that you might occasionally create are still worthy of the treatment you give production applications. Specifically, the use of explicit dependency declarations and behavior-driven development, and we can do this without adding any additional files.&lt;/p&gt;

&lt;h3 id=&quot;background&quot;&gt;Background&lt;/h3&gt;

&lt;p&gt;A few months back, I was tasked with taking some Microsoft Word DOCX files and incorporating their contents into an internationalized, front-end application. Each DOCX file contained the verbiage to use for a particular language, and the end goal was to populate JavaScript locale files with the contents.
I found a RubyGem - appropriately named “docx” - to parse DOCX files, and after fumbling around in IRB for a while, I found a sequence of commands that produced the output I desired. I then repeated this sequence of commands for all the files and incorporated the results into the locale files, which completed the task at hand.
More recently, I was tasked with updating those same locale files from a new set of files, and I immediately regretted that I had not created a better system for handling this task the previous time. I was resolved to write a script which handled the bulk of this largely repetitive workload.&lt;/p&gt;

&lt;h3 id=&quot;utility-scripts&quot;&gt;Utility Scripts&lt;/h3&gt;

&lt;p&gt;While the processing of these DOCX files is certainly not a responsibility of the application I was working on - instead it’s more of a consequence of how we receive these data from our client - building a utility script to automate as much as possible is still a worthwhile endeavor. When writing these kinds of utility scripts, I often turn to Ruby, as it’s a language I know well and it’s well suited for this type of task.
Historically, I’ve had a couple gripes with these scripts: first, I tend to develop them by running them over and over, with small changes between each invocation. Second, it can be tricky to ensure I have the correct version of a dependency installed when I want to use the script months, or years, after it was created.
While our applications could potentially suffer from similar problems, they are mitigated through the practice of behavior-driven development for the former problem and dependency management tools for the latter. Why not apply the same techniques and tools when building single-file utility scripts?&lt;/p&gt;

&lt;h3 id=&quot;dependency-management&quot;&gt;Dependency Management&lt;/h3&gt;

&lt;p&gt;For dependency management in Ruby, we generally use Bundler, where our dependency declarations are all put into one file - typically named Gemfile. For a single-file script, having a separate file for its dependencies seems awkward. Luckily, Bundler has a trick up its sleeve that fits our needs perfectly: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundler/inline&lt;/code&gt;. It provides a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gemfile&lt;/code&gt; method, where we can declare our dependencies using the same interface as Gemfiles.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;bundler/inline&apos;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;gemfile&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;rspec&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;3.7&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;require: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that we’re able to declare the dependencies for our scripts, we no longer need to worry about their durability when we come back to them months, or years, later.&lt;/p&gt;

&lt;h3 id=&quot;behavior-driven-development-bdd&quot;&gt;Behavior-Driven Development (BDD)&lt;/h3&gt;

&lt;p&gt;The same benefits we receive from using BDD while building our applications can be applied to building scripts. A suite of RSpec examples is usually contained in files that are separate from those of the implementation, but again, that approach is awkward for a single-file script. While I haven’t come across a part of RSpec purpose-built for our use case, we can take advantage of RSpec’s runner to differentiate between how our script file is being used. That is, we’ll inspect the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$PROGRAM_NAME&lt;/code&gt; global (also aliased as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$0&lt;/code&gt;) and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__FILE__&lt;/code&gt; constant; if they are the same then the script itself is being executed, otherwise it’s being loaded from another program - RSpec in our case. That will allow us to have our script code and our RSpec examples all in the same file, and the examples will only be evaluated when the script is loaded by RSpec’s runner.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# script logic&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;$PROGRAM_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;__FILE__&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# the script itself is being executed&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;rspec&apos;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;the script&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;is expected to do something&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;final-script&quot;&gt;Final Script&lt;/h3&gt;

&lt;p&gt;Now we just need to put it all together into an actual script. For the sake of an example, we’ll use a simplified recreation of Unix’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wc&lt;/code&gt; utility, which counts lines, words and characters of the text passed in through standard input (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;STDIN&lt;/code&gt;):&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#! /usr/bin/env ruby&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;bundler/inline&apos;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;gemfile&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;rspec&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;3.7&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;require: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Program&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@input&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;%8d%8d%8d&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;characters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;characters&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;lines&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/\n/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;words&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/\s+/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vg&quot;&gt;$PROGRAM_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;__FILE__&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;STDIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;rspec&apos;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Program&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;described_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;line 1&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;line 2&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;line 3&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;       3       6      21&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;characters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;words&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With that, we can run our specs:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rspec wc.rb
....

Finished &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;0.00348 seconds &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;files took 0.19061 seconds to load&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
4 examples, 0 failures
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And, we can run the script itself:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;chmod&lt;/span&gt; +x wc.rb
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;hello, world&quot;&lt;/span&gt; | ./wc.rb
       1       2      13
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;line 1&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;line 2&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | ./wc.rb
       2       4      14
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;exit-0&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;exit 0&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;Hopefully, you’ll be able to use these tricks when writing your next utility script. With them, you’ll be able to take advantage of BDD while developing the script, and you can be confident about its use of dependencies long after it was written.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Rake: Task Arguments</title>
   <link href="https://jacobswanner.com/development/2017/rake-task-arguments/"/>
   <updated>2017-06-06T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2017/rake-task-arguments</id>
   <content type="html">&lt;p&gt;There are times when we want to pass variable data to our tasks; whether it’s
to act as a switch between different behaviors, or if it’s to provide needed
input for our task to run properly. Whatever the case, it is a useful thing to
know about when creating Rake tasks.&lt;/p&gt;

&lt;p&gt;This is the fourth post in a series on Rake and I believe this post is the
missing piece to complete the series. The topics of the previous posts include:
&lt;a href=&quot;/development/2013/rake-global-tasks/&quot;&gt;an introduction to the Rakefile format&lt;/a&gt;, &lt;a href=&quot;/development/2013/rake-file-tasks/&quot;&gt;file
tasks&lt;/a&gt;, and &lt;a href=&quot;/development/2014/rake-rule-tasks/&quot;&gt;rule tasks&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-env-workaround&quot;&gt;The ENV-workaround&lt;/h2&gt;

&lt;p&gt;It’s quite common to use environment variables in order to pass variable data
to Rake tasks – and this is how Rails’ Rake tasks do it.&lt;/p&gt;

&lt;p&gt;Let’s start by declaring a task called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;first&lt;/code&gt; which will read the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VAR&lt;/code&gt;
environment variable:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:first&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;VAR in `first` is &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;VAR&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’re using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#inspect&lt;/code&gt; here so that the value of our argument is explicitly
clear.&lt;/p&gt;

&lt;p&gt;Now let’s look at running this task in a shell:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake first
VAR &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;first&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; is nil
&lt;span class=&quot;nv&quot;&gt;$ VAR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;a rake first
VAR &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;first&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; is &lt;span class=&quot;s2&quot;&gt;&quot;a&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see in the first invocation, if the environment variable is not set,
then the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ENV&lt;/code&gt; object will return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; for our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VAR&lt;/code&gt; name. In the second
invocation, we’re using our shell’s facility to set an environment variable
while running a program, and that value is available to us while our task is
running.&lt;/p&gt;

&lt;p&gt;None of this is Rake-specific; it’s just Ruby running on a &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix-like&quot;&gt;Unix-like&lt;/a&gt;
system. That said, Rake does provide another way of setting environment
variables:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake first &lt;span class=&quot;nv&quot;&gt;VAR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;b
VAR &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;first&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; is &lt;span class=&quot;s2&quot;&gt;&quot;b&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, Rake will add options in the &lt;em&gt;VAR=VALUE&lt;/em&gt; format to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ENV&lt;/code&gt;
object.&lt;/p&gt;

&lt;h2 id=&quot;proper-task-arguments&quot;&gt;Proper Task Arguments&lt;/h2&gt;

&lt;p&gt;The example above shows a common  approach you will see for how to supply
variable data to Rake tasks, but Rake actually has real support for task
arguments.&lt;/p&gt;

&lt;p&gt;You declare task arguments with an Array as the second parameter to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task&lt;/code&gt;
method, and the values are accessible via the second parameter given to our
action block:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:second&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;var in `second` is &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When invoking a task, parameters are placed inside of square brackets after the
name of the task:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake second[c]
var &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;second&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; is &lt;span class=&quot;s2&quot;&gt;&quot;c&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Arguments are not required, your task will need to handle potential &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;
values:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake second
var &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;second&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; is nil
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But again, Rake provides a handy way of setting default values for our task
arguments, by called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#with_defaults&lt;/code&gt; on our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;args&lt;/code&gt; object:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:third&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_defaults&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;var: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;default&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;var in `third` is &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now when our task is invoked, we no longer need to worry about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; argument
values:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake third
var &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;third&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; is &lt;span class=&quot;s2&quot;&gt;&quot;default&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake third[d]
var &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;third&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; is &lt;span class=&quot;s2&quot;&gt;&quot;d&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;arguments--prerequisites&quot;&gt;Arguments &amp;amp; Prerequisites&lt;/h2&gt;

&lt;p&gt;You might be wondering to yourself: how do you declare a task that has
arguments and prerequisites? Well, you pass a Hash as the second parameter to
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task&lt;/code&gt; method; the key of the Hash contains your task’s arguments and the
value contains the prerequisites.&lt;/p&gt;

&lt;p&gt;Let’s declare a task called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fourth&lt;/code&gt; that has an argument called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;var&lt;/code&gt; and
depends on our task called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;third&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:fourth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:third&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_defaults&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;var: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;fallback&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;var in `fourth` is &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Parameters given to your task will be passed to its prerequisites as well:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake fourth
var &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;third&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; is &lt;span class=&quot;s2&quot;&gt;&quot;default&quot;&lt;/span&gt;
var &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;fourth&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; is &lt;span class=&quot;s2&quot;&gt;&quot;fallback&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake fourth[e]
var &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;third&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; is &lt;span class=&quot;s2&quot;&gt;&quot;e&quot;&lt;/span&gt;
var &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;fourth&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; is &lt;span class=&quot;s2&quot;&gt;&quot;e&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the above invocations, the first line of output comes from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;third&lt;/code&gt; task,
and the second line comes from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fourth&lt;/code&gt; task.&lt;/p&gt;

&lt;h2 id=&quot;useful-example&quot;&gt;Useful Example&lt;/h2&gt;

&lt;p&gt;Each post in this series has tried to include a useful example of a task using
the aspect of Rake described in the post. But, for this post, I’m going to
reference back to the &lt;a href=&quot;/development/2013/rake-global-tasks/#hopefully-useful-example&quot;&gt;example in the first post&lt;/a&gt;, as it used
task arguments as well.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>London</title>
   <link href="https://jacobswanner.com/travel/2016/london/"/>
   <updated>2016-11-19T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/london</id>
   <content type="html">&lt;p&gt;I spent the last week of this European trip in London. It was my second time in
London, but my previous stay there had been very brief, only a couple days. So,
I was certainly excited to see more of the city, and it did not disappoint.&lt;/p&gt;

&lt;p&gt;On Saturday – the day after arriving – I joined 2 free walking tours: one of
street art in East London and another of the City of London. Both were great,
very different from each other, and would recommend both. On Sunday, I booked a
bike tour, from the same company that I had used in Berlin, and it turns out
they run a much smaller operation in London. Of the tours I did in London, the
bike tour definitely covered more of the touristy spots, which is probably why
it was the tour I enjoyed the least, even though it was a fine tour.&lt;/p&gt;

&lt;p&gt;A friend, and former coworker, Eric lives in London. I hadn’t seen him in a
number of years, so it was cool to be able to catch up with him. His company
rented desk space from a  WeWork location in East London, quite close to where
I was staying, so I was able to meet up with him and his coworkers a couple
times during my stay.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Edinburgh</title>
   <link href="https://jacobswanner.com/travel/2016/edinburgh/"/>
   <updated>2016-11-06T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/edinburgh</id>
   <content type="html">&lt;p&gt;After leaving France, I took a train – through the chunnel – to London, from
there I took another train to Edinburgh, Scotland. I almost missed the Eurostar
train in Lille – the one that took me to London – because it took me way
longer to find the car rental return location than I thought it would. The
tracks that Virgin Trains East Coast uses – which I took between London &amp;amp;
Edinburgh – are not what I call smooth, the carriage jostles around a lot. I
was constantly worried about stuff falling over or spilling, but the service in
first class was probably the best I’ve experienced – first class on a train is
not the same kind of difference as on a plane.&lt;/p&gt;

&lt;p&gt;It was my first time in Scotland, and I loved the beauty of the country. I
don’t think Scotland is usually associated with good food, but I had some
lovely meals and drinks while I was there. Edinburgh itself seemed really cool,
even though it was probably the dirtiest of all the places I visited during
this trip – I can’t believe how much literal shit I saw on the streets &amp;amp;
sidewalks. I hiked up Arthur’s Seat, which provided great views of Edinburgh
and the surrounding area. But, I think my favorite parts of my time in Scotland
would be the two tours I took that got me out in the Scottish countryside.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Wissant</title>
   <link href="https://jacobswanner.com/travel/2016/wissant/"/>
   <updated>2016-11-02T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/wissant</id>
   <content type="html">&lt;p&gt;After leaving Amsterdam, I spent a week in northern France. This week was the
only week of pure vacation during my time in Europe, actually the only week of
vacation during all of my nomadic travels thus far.&lt;/p&gt;

&lt;p&gt;I was in the area for the wedding of some friends (Guylain &amp;amp; Amandine). My mom
and brother traveled to France for the wedding as well. Guylain’s sister,
Valérie, rented a large house in the coastal village of Wissant for her
extended family to stay in, and my family members and I were lucky enough to be
able to stay there as well.&lt;/p&gt;

&lt;p&gt;While there, in addition to attending the wedding and associated celebrations,
we also hiked up one of the nearby coastal capes, which provided a spectacular
view. We also visited some of the nearby cities (Boulogne &amp;amp; Calais) and an
aquarium.&lt;/p&gt;

&lt;p&gt;I spent the last day of that week in Pontruet, staying other friends in the
same extended family. I always enjoy visiting with all these friends in France
– it’s like visiting with relatives – which probably explains why I do it so
often.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Berlin</title>
   <link href="https://jacobswanner.com/travel/2016/berlin/"/>
   <updated>2016-11-02T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/berlin</id>
   <content type="html">&lt;p&gt;After Copenhagen, I went to Berlin, Germany. I kind of can’t believe that had
only been my third time there, I feel like I’ve spent so much time there. Such
a great city, with so much to do, and it’s cheap (&lt;em&gt;way&lt;/em&gt; cheaper than Stockholm
&amp;amp; Copenhagen).&lt;/p&gt;

&lt;p&gt;On my previous visits to the city, I never did any kind of formal tour, on this
visit I did two: a &lt;a href=&quot;http://originalberlintours.com/tours/the-free-original-berlin-alternative-tour/&quot;&gt;free walking tour&lt;/a&gt; of the street art in Kreuzberg
and a &lt;a href=&quot;https://www.fattiretours.com/berlin/tours/modern-tour&quot;&gt;bike tour&lt;/a&gt; outside of the typical tourist places. Both were
great, would recommend them to any one visiting the city.&lt;/p&gt;

&lt;p&gt;Kreuzberg has got to be the most hipster place I’ve ever been, I love it none
the less.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Amsterdam</title>
   <link href="https://jacobswanner.com/travel/2016/amsterdam/"/>
   <updated>2016-11-02T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/amsterdam</id>
   <content type="html">&lt;p&gt;I spent the first week of July in Amsterdam, Netherlands. While there, I
continued the bike tour trend that I started in Berlin. First, I joined a &lt;a href=&quot;http://www.yellowbike.nl/stoked/en/product/big-city-bike-tour/&quot;&gt;city
bike tour&lt;/a&gt; then a couple days later a &lt;a href=&quot;http://www.webikeamsterdam.com/countryside-tour.html&quot;&gt;countryside bike
tour&lt;/a&gt;. The city bike tour was fine, but I really enjoyed –
and recommend – the countryside bike tour.&lt;/p&gt;

&lt;p&gt;I was in Amsterdam for the 4th of July. I spent the day on the aforementioned
countryside bike tour,visiting the Dutch Resistance Museum, and then having a
dinner at a &lt;a href=&quot;http://www.moeders.com/en/home&quot;&gt;restaurant known for serving traditional Dutch cuisine&lt;/a&gt;.
I know, I had a very patriotic-American day in Amsterdam.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Copenhagen</title>
   <link href="https://jacobswanner.com/travel/2016/copenhagen/"/>
   <updated>2016-11-01T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/copenhagen</id>
   <content type="html">&lt;p&gt;After Stockholm, I spent a week in Copenhagen, Denmark. This was the third time
I had been to Copenhagen, and much like my previous visits to the city: I loved
it, it’s certainly one of my favorite cities in Europe.&lt;/p&gt;

&lt;p&gt;This time around, I visited places I hadn’t in the past: Kastellet (or The
Citadel), Freetown Christiania, and the National Museum of Denmark. I really
enjoyed Copenhagen Street Food on PapirØen (Paper Island), so much so that I
went back a second time.&lt;/p&gt;

&lt;p&gt;On my last night there, I got caught out in the rain while out getting dinner.
This was just continuing a trend that started in Chicago, and also happened to
be in Stockholm.&lt;/p&gt;

&lt;p&gt;My departing train from Copenhagen was 7 minutes late, and I only had a 15
minute connection scheduled in Hamburg, Germany, which made me a bit nervous,
but ended up being fine. I must have been in an engine carriage, because it was
much louder in the carriage than I’m accustomed to for European trains. A
positive thing to say about that train ride: it was really cool when the train
pulled into a ferry, and it took us from Denmark to Germany.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Stockholm</title>
   <link href="https://jacobswanner.com/travel/2016/stockholm/"/>
   <updated>2016-10-21T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/stockholm</id>
   <content type="html">&lt;p&gt;Over the summer, I spent 7 weeks traveling around Europe, visiting 7 different
places, 1 week in each place. My first stop in Europe was Stockholm, Sweden. On
2 different occasions, I have briefly visited Malmo, Sweden, but this was my
first time in Stockholm.&lt;/p&gt;

&lt;p&gt;While in Stockholm, I had the chance to catch up with a friend from middle
school, whom I hadn’t seen since middle school. While it was quite crazy to see
him again, I really enjoyed hanging out with him.&lt;/p&gt;

&lt;p&gt;During my time there, I learned of a couple Swedish cultural things that I
didn’t know before going there. The first one I discovered while trying to
figure out how to wash my clothes. I knew ahead of time that my &lt;a href=&quot;https://www.airbnb.com/rooms/9954618&quot;&gt;Airbnb
rental&lt;/a&gt; did not include laundry facilities, so I assumed that there
would be a laundromat nearby, but when it came time for me to clean my clothes
I could not one. This led me to search the internet how residents of Stockholm
wash their clothes, turns out apartment buildings there have shared laundry
facilities in the basement, but my Airbnb host did not provide me with the key
so that I could use those machines. From a travel forum frequented by Brits and
Americans I learned about the &lt;em&gt;only&lt;/em&gt; laundromat in all of Stockholm, and it was
on the other side of town from where I was staying.&lt;/p&gt;

&lt;p&gt;Another thing I did not know about was that Sweden has a civil defense siren
system, nor did I know that one day a year at 3pm they test that siren system
nation-wide, and I just happened to be there that particular day of the year.
That was quite a shock to me when I heard a sound I had always associated with
an air raid siren, and I think I’ve really only heard it in movies, prior to
that day.&lt;/p&gt;

&lt;p&gt;The last thing that I can think of that I learned while in Stockholm, was that
when you order pizza there, it is served with &lt;a href=&quot;https://sv.wikipedia.org/wiki/Pizzasallad&quot;&gt;pizzasallad&lt;/a&gt;, which is similar
to a mild sauerkraut.&lt;/p&gt;

&lt;p&gt;I left Stockholm by train, which gave me the opportunity to see lots of the
Swedish countryside. It was quite beautiful, with lots of birch trees and red
barns.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Video Player Debugging Story</title>
   <link href="https://jacobswanner.com/development/2016/video-player-debugging-story/"/>
   <updated>2016-10-14T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2016/video-player-debugging-story</id>
   <content type="html">&lt;p&gt;This is the story of when &lt;a href=&quot;http://madewithenvy.com/ecosystem/articles/2015/meet-envy-dray-lacy/&quot;&gt;Dray&lt;/a&gt;, &lt;a href=&quot;http://madewithenvy.com/ecosystem/articles/2015/meet-envy-nate-bibler/&quot;&gt;Nate&lt;/a&gt;, and I spent the better
part of two days trying to figure out a bug. Hopefully, you won’t run into this
same bug with your applications, but if you do perhaps this can be of some
help.&lt;/p&gt;

&lt;p&gt;Shortly after the release of iOS 10, we heard users of one of our web
applications were no longer able to play videos. We were quickly able to
reproduce the issue, and observed that videos were not working with iOS 10, but
were working as expected with iOS 9. This is when the journey to find the root
of the problem began, what we discovered was more bizarre than expected.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/development/assets/video-player-debugging-story/erred-video.png&quot; alt=&quot;Erred Video&quot; /&gt;&lt;/p&gt;

&lt;p&gt;To back up briefly, I should explain how these videos are served, as they are
not just requested using a publicly accessible URL. The videos are stored on
&lt;a href=&quot;https://aws.amazon.com/s3/&quot;&gt;Amazon S3&lt;/a&gt; and delivered by
&lt;a href=&quot;https://aws.amazon.com/cloudfront/&quot;&gt;CloudFront&lt;/a&gt;. To restrict video access, the
source URL given to the video player is a URL to our application, where
authorized users are redirected to a short-lived, signed CloudFront URL.&lt;/p&gt;

&lt;p&gt;The first step we took to find the problem was to check if any errors were
reported to the browser’s JavaScript console. In order to do so using the tools
Apple provides, it means connecting an iOS device to a computer and then use
the developer tools of Safari on the computer. Upon doing so, we noticed
messages like the following in the console (which didn’t help us very much):&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;VIDEOJS:
&quot;ERROR:&quot;
&quot;(CODE:4 MEDIA_ERR_SRC_NOT_SUPPORTED)&quot;
&quot;The media could not be loaded, either because the server or network failed or because the format is not supported.&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next step we took was to look at the network requests being sent from the
phone’s browser. Unfortunately, that didn’t help us much either, because Safari
doesn’t show request headers, response headers, nor response status codes for
video requests.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/development/assets/video-player-debugging-story/video-request.png&quot; alt=&quot;Video Request&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At this point, not knowing where to look for the problem, a couple of my
coworkers started making ever increasingly complex test pages, trying to find
the specific situation that caused the problem. We spent a lot of time thinking
the problem was in the redirection, perhaps when combined with HTTPS requests,
but were never able to actually pin down the problem.&lt;/p&gt;

&lt;p&gt;After not being able to create a standalone test page that reproduced the issue
in iOS 10 devices, we decided to look elsewhere for the problem. We still
really wanted to see the details of the requests for the video files, but with
Safari’s developer tools not providing those details, something else was
needed. We wanted to use an HTTP proxy, but there were a couple problems with
doing that: the phone’s network traffic would need to flow through the computer
running the HTTP proxy, and we were dealing with HTTP&lt;strong&gt;S&lt;/strong&gt; requests (which
means the requests were encrypted).&lt;/p&gt;

&lt;p&gt;To solve the first of those problems, my phone needed to use my computer as its
wireless access point; which brings up another problem: a Mac can use its WiFi
radio to connect to a wireless network or to create a wireless network, not
both at the same time, but my computer would still need access to the Internet.
Luckily, I own a Thunderbolt Ethernet Adapter and after finally finding an
Ethernet port in our office, the first problem was solved: my computer would
connect to the Internet via Ethernet and then create a wireless network for my
phone to use.&lt;/p&gt;

&lt;p&gt;As for our second HTTP proxy problem (reading encrypted HTTPS traffic), we were
nicely surprised to learn that the HTTP Proxy we were wanting to use already
had a solution to that. We were using &lt;a href=&quot;https://www.charlesproxy.com/&quot;&gt;Charles Web Debugging
Proxy&lt;/a&gt;, and it includes instructions on how to
capture and display HTTPS traffic, which mostly revolves around installing a
root SSL certificate on the computer and on the phone. This is certainly not
something you’d want to do under normal circumstances, as we were essentially
performing a &lt;a href=&quot;https://en.wikipedia.org/wiki/Man-in-the-middle_attack&quot;&gt;Man-in-the-middle
attack&lt;/a&gt; on ourselves.&lt;/p&gt;

&lt;p&gt;After getting all of that set up, it didn’t take us long to narrow in on the
problem. The first thing we noticed was that the request to our application for
the video, which we expected to respond with a redirect to CloudFront, was
responding with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;401 Unauthorized&lt;/code&gt; status. The next thing we noticed was that
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Cookie&lt;/code&gt; HTTP header in the request didn’t look right, it contained much
less data than all the other requests to our application. After that, one of my
coworkers discovered a &lt;a href=&quot;https://bugs.webkit.org/show_bug.cgi?format=multiple&amp;amp;id=161780&quot;&gt;bug had been reported with
WebKit&lt;/a&gt;, the
underlying engine in Safari and many other browsers.&lt;/p&gt;

&lt;p&gt;So, the problem ended up being that the browser was not sending the cookies our
application was relying on when making requests for media elements.&lt;/p&gt;

&lt;p&gt;If your application has a similar problem, the solution will be application
specific: wait for Safari to be fixed, remove authentication/authorization from
those requests, or use a different authorization scheme. As of this writing,
Safari on iOS 10 has still not been fixed.&lt;/p&gt;

&lt;h2 id=&quot;hindsight-is-2020&quot;&gt;Hindsight is 20/20&lt;/h2&gt;

&lt;p&gt;Looking back, there were some things that could have helped us narrow in on the
problem sooner. In production, we direct all of our log messages to
&lt;a href=&quot;https://logentries.com/&quot;&gt;Logentries&lt;/a&gt;, and had we looked more closely we would
have seen the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;401 Unauthorized&lt;/code&gt; responses for the video requests. That would
not have told us &lt;em&gt;why&lt;/em&gt; our application was responding that way, but at least it
would have narrowed our focus.&lt;/p&gt;

&lt;p&gt;What would have been of most help is if Safari showed request and response
headers for video requests. It shows these details for other request types, and
Google Chrome shows these details for video requests. If that data was
presented in the developer tools, we would not have needed to use an HTTP
proxy.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Atlanta</title>
   <link href="https://jacobswanner.com/travel/2016/atlanta/"/>
   <updated>2016-09-27T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/atlanta</id>
   <content type="html">&lt;p&gt;On 4 June, things came full circle, geographically speaking; by returning to
Atlanta my drive around North America formed a complete loop. I stayed in
Atlanta until 11 June, at which time I flew to Europe, where I stayed for 7
weeks. During this time in Atlanta, I also met up for a friend from college,
Rachel, a couple times. Atlanta has a lot of really great restaurants, bars,
and breweries – I think a lot of people underestimate it in this respect.&lt;/p&gt;

&lt;p&gt;While there, I stayed with old friends (Kevin &amp;amp; Robert), but if that wasn’t
generous enough of them, they also took care of my car while I was in Europe.
They had told me before that they were thinking of purchasing a Tesla, and I
was hoping by leaving it with them that they’d get to experience what it’s like
having one for an extended period of time, but I don’t think they drove it all
that much.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Washington D.C.</title>
   <link href="https://jacobswanner.com/travel/2016/washington-dc/"/>
   <updated>2016-09-11T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/washington-dc</id>
   <content type="html">&lt;p&gt;After leaving Boston, I spent the following week (28 May - 4 June) in the
Washington D.C.  area, more specifically, I stayed in Arlington, VA. I hadn’t
intentionally planned to be in D.C. for Memorial Day weekend, just how it
turned out. But, it was nice having Monday off, which meant I had an extra day
to go to museums and such. Speaking of museums, while I was there I went to a
couple of old favorites: National Air &amp;amp; Space Museum and the National Museum of
Natural History; along with a couple I don’t remember going to before:
Smithsonian Arts &amp;amp; Industries Building and the Smithsonian Castle.&lt;/p&gt;

&lt;p&gt;While there, I had the pleasure of spending a couple evenings with Todd,
Marianna &amp;amp; their children. I also got to hang out with Ashley a few times, one
of those times she likes to say that we saved a man’s life. I would say she
tended to an unconscious man while I called 911, and the police arrived in
under a minute.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Montreal</title>
   <link href="https://jacobswanner.com/travel/2016/montreal/"/>
   <updated>2016-09-11T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/montreal</id>
   <content type="html">&lt;p&gt;Another in what should be a long line of entries written months after the fact.
I was in Montreal from 15 to 21 May. It was not my first time there, but I wish
I would have had more time to explore the city, instead I spent a great deal of
time working during my stay there. I was able to visit a handful of the many
fine restaurants that city has to offer. I really like Montreal, and hope to
spend more time there in the future.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Boston</title>
   <link href="https://jacobswanner.com/travel/2016/boston/"/>
   <updated>2016-09-11T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/boston</id>
   <content type="html">&lt;p&gt;After leaving Montreal, I went to Boston, where I stayed in Cambridge and
Charlestown. I got to spend a day with Karine and some of her friends, which
was great – always nice to catch up with old friends. I was in Boston from 21
to 28 May. I did a great deal of walking around the city at night, not
necessarily to go anywhere, just walk and see the city. It had been a while
since I had it to that extent, and Boston was a great city to walk around.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Chicago</title>
   <link href="https://jacobswanner.com/travel/2016/chicago/"/>
   <updated>2016-09-03T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/chicago</id>
   <content type="html">&lt;p&gt;Okay, I’m writing this &lt;em&gt;well&lt;/em&gt; after the fact, I’ve got a lot of catching up to
do, as far as entries about where I’ve been. I was in Chicago from the 7th to
the 14th of May. I was lucky enough to be able to meet up with friends Mike &amp;amp;
Raquel and Pete &amp;amp; Laura a few times, it’s always great seeing old friends, them
especially. I was out with all of them on my last night in town, and at the end
of the night, on the way to the Metra station, Mike, Raquel and myself all got
completely soaked in the rain. It turns out that wasn’t the last time that I
was rained on during my last night of one of my stops.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Kansas City</title>
   <link href="https://jacobswanner.com/travel/2016/kansas-city/"/>
   <updated>2016-06-18T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/kansas-city</id>
   <content type="html">&lt;p&gt;Kansas City was not a city I was particularly excited about visiting (1 - 7
May).  I chose to spend a week there because I wanted to break up the drive
between Denver and Chicago, not wanting to drive that much in one weekend; it
was a city I was unfamiliar with, and it was conveniently located along the
path I was taking.&lt;/p&gt;

&lt;p&gt;I stayed on the Kansas [state] side of the city, but only a block away from the
state line, and so spent time on both sides throughout my stay. It’s certainly
a BBQ town, with that subject coming up in many of the conversations I had
while I was there.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Denver</title>
   <link href="https://jacobswanner.com/travel/2016/denver/"/>
   <updated>2016-06-18T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/denver</id>
   <content type="html">&lt;p&gt;I spent the last week of April in Denver, CO (24 April - 1 May). The drive to
Denver was quite amazing, driving through the Rockies of Utah and Colorado.
The mountain tops were all covered in snow, and even drove past a number of ski
resorts still open for the season (although I imagine with a reduced selection
of runs open). The drive out was also very pretty, with seemingly endless
snow-covered prairies.&lt;/p&gt;

&lt;p&gt;Unfortunately, during the week I was in Denver I was working a lot, and so
didn’t get to see as much of the area as I would have liked. I did manage to
have dinner in Boulder on my last night, as well as visiting a number of
restaurants and breweries in the area I was staying. I really enjoyed the
Airbnb that I was staying in, which was on the north side of Sloan Lake, with a
lovely view of the lake and the park that surrounds it. There was quite the
change in weather while I was there: starting out warm and sunny when I
arrived, then being blanketed in snow later in the week, and ending with it
being cold and wet.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Boise</title>
   <link href="https://jacobswanner.com/travel/2016/boise/"/>
   <updated>2016-06-18T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/boise</id>
   <content type="html">&lt;p&gt;From 17 to 23 April, I stayed in Boise, ID; this was my second visit to Boise,
the first being a quick stop while on a previous drive across the country. From
that first visit, I learned that it’s actually a cute, little city, just
happens to be kind of in the middle of nowhere.&lt;/p&gt;

&lt;p&gt;After talking to a handful of people in Boise about their city, I get the
feeling that, while they enjoy their city, they are in no hurry to spread the
word about where they live, and would prefer to keep it for themselves. While
I’m not trying to say that Boise is the greatest place on Earth that no one
knows about, I would say that I did come to have an appreciation for what it
has to offer.&lt;/p&gt;

&lt;p&gt;I have no idea what those offerings might be in terms of cultural activities;
it does have an array of outdoor options, an appreciation for local foods (more
than just potatoes), a health-conscious population, in a small city package.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Fort Lewis</title>
   <link href="https://jacobswanner.com/travel/2016/fort-lewis/"/>
   <updated>2016-06-17T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/fort-lewis</id>
   <content type="html">&lt;p&gt;I managed to spend a few extra days with my friends Brad &amp;amp; David, by
sacrificing days in beforehand in Portland and later in Boise, and I stayed
with them at their home on Fort Lewis, WA (8 - 17 April). While with them, we
went to a Mariners baseball game and a Sounders soccer match, both of which
were a great deal of fun, the last professional sporting event I had been to
prior to that was probably the basketball games I went to for company events.&lt;/p&gt;

&lt;p&gt;We took a ferry over to Vashon Island, where we had brunch and visited a
[plant] nursery – where Brad purchased a crow statue, I believe he named it
Henry. The trip to Vashon Island was a lovely experience, the ferry rides while
very short, had great views.&lt;/p&gt;

&lt;p&gt;I’ve really enjoyed the time I’ve spent in the Pugent Sound area; in addition
to this trip, I’ve spent 2 months in Olympia and another month just north of
Seattle. Much like Vancouver, the area has a mix of city, mountains, and water,
which provides the area with a wide variety of activitites. Combine that with
an environmentally-conscious population, and it certainly makes for an area
where I can see myself wanting to spend a lot more time.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Vancouver</title>
   <link href="https://jacobswanner.com/travel/2016/vancouver/"/>
   <updated>2016-05-07T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/vancouver</id>
   <content type="html">&lt;p&gt;I went to Vancouver, BC, Canada for my first time (1 - 8 April), and it was
certainly one of the places that I have enjoyed most during this journey. I
stayed in Yaletown, which was a very nice area to stay, with plenty of bars and
restaurants nearby.  It’s also along False Creek, with Grandville Island a
short ferry ride away.  It’s a beautiful city, with a mix of: skyline, water,
and mountains.&lt;/p&gt;

&lt;p&gt;I really enjoyed Grandville Island, which I visited 3 times; twice to get
provisions for a picnic, that I would have shortly there after. Unfortunately,
I only spent a few hours in Stanley Park, next time I’m there I will be sure to
spend more time there.&lt;/p&gt;

&lt;p&gt;I overheard a couple guys from Toronto describing Vancouver to some friends as:
San Francisco Bay area mixed with Canada; that seemed true enough to me.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Portland</title>
   <link href="https://jacobswanner.com/travel/2016/portland/"/>
   <updated>2016-05-01T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/portland</id>
   <content type="html">&lt;p&gt;I spent the end of March in Portland, OR (27 March - 1 April), where I met up
with some coworkers for EmberConf. I’ve been to Portland a number of times
before, but every trip there has involved a conference. I think it’s a great
city to hold a conference: public transportation will take you just about
anywhere you’d want to go (even to and from the airport), tremendous number of
wonderful bars and restaurants, and a conveniently located convention center.
Really the only downside is that getting there, especially from the East Coast,
is potentially not very direct; that’s a trade-off I’m usually willing to make.&lt;/p&gt;

&lt;p&gt;Portland was a bit of a milestone for this journey. The route and the timing
leading up to it were planned to get me there in time for the conference. So,
it definitely felt good to have successfully accomplished that goal.&lt;/p&gt;

&lt;p&gt;My last full day in Portland (31 March) was also the day that Tesla Motors
revealed their next vehicle, the Model 3. That morning they began taking
reservations for orders for that new vehicle, where people – like myself –
gave money for a reservation for a car they had never seen. I believe in an
attempt to cause lines of people for news agencies to cover, not unlike lines
that form outside Apple stores for people wanting to buy iPhones, reservations
were only taken in person at Tesla stores, until the online reservation system
became available that night. I went to their store southwest of Portland, in
order to join the crowd waiting there to purchase a reservation. It was
certainly a fun experience, talking with the people waiting in line around me,
and it was great to see how many people were excited about an electric vehicle.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Bay Area</title>
   <link href="https://jacobswanner.com/travel/2016/bay-area/"/>
   <updated>2016-05-01T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/bay-area</id>
   <content type="html">&lt;p&gt;I spent two weeks in Albany, CA (13-27 March), staying with Jes and Sadie; I
only got to see Doug (Jes’s dad) for a day before he left for another of his
epic cruising adventures. Having lived there for 4 months, along with many
other visits, I’m quite familiar with the area, but did manage to see many new
things during this stay.&lt;/p&gt;

&lt;p&gt;Spending the afternoon in Tomales Bay was quite the treat, I look forward to
returning to that area in the future. We went to some new wineries in Napa
valley, that area is always a fun place to visit. Also went to some dining
establishments for the first time.&lt;/p&gt;

&lt;p&gt;Experiencing new things is great, but there are also times you want what you
are familiar with, and did manage to taken in some of those as well: Acme Bread
Co, Lava Vine Winery, Suppenküche, and Zachary’s Pizza.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Silver Lake</title>
   <link href="https://jacobswanner.com/travel/2016/silver-lake/"/>
   <updated>2016-04-23T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/silver-lake</id>
   <content type="html">&lt;p&gt;I spent a week in early March (7-13) staying with friends, Jessie &amp;amp; Tim, in
their house in the Silver Lake neighborhood of Los Angeles, CA. I’ve been to LA
a handful of times before, but it’s always involves Jessie &amp;amp; Tim, so I don’t
really know LA disconnected from them. I’m certainly not complaining about
this, I always have fun when I’m with them, and being in a city with someone
who lives there provides a different experience than just visiting on your own.&lt;/p&gt;

&lt;p&gt;We had some great meals, went to the movie theater to watch The Witch, and went
to the Getty museum, which was my first time and it was quite nice.  Another LA
first for me (and Jessie) was going to Grand Central Market, which I really
enjoyed, and would certainly revisit on subsequent trips.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Topanga</title>
   <link href="https://jacobswanner.com/travel/2016/topanga/"/>
   <updated>2016-04-21T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/topanga</id>
   <content type="html">&lt;p&gt;I was originally planning on spending the weekend of 5-7 March with my brother
in Rancho Cucamonga, CA, but due to conflicting schedules, I made a last minute
change and booked a wonderful little &lt;a href=&quot;https://www.airbnb.com/rooms/696051&quot;&gt;AirBnb rental&lt;/a&gt; in Topanga canyon.
The rental was a tiny house that was part of a little compound with a couple
other houses and a mini farm. Unfortunately, I was there at the wrong time, so
didn’t get to try the homemade goat cheese, but I did get fresh eggs.&lt;/p&gt;

&lt;p&gt;I spent a day hiking around the Topanga canyon area, including going up to
Eagle’s Rock (highly recommended) and Topanga Lookout (enjoyed the views from
the drive up there more than the views from the lookout itself).&lt;/p&gt;

&lt;p&gt;There’s all of about 4 restaurants in Topanga canyon, and apparently they are
known for having bad service; luckily I only experienced that kind of service
in one of the three restaurants I visited while I was there. I would certainly
recommend Topanga canyon as a fun weekend getaway.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Santa Barbara</title>
   <link href="https://jacobswanner.com/travel/2016/santa-barbara/"/>
   <updated>2016-04-21T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/santa-barbara</id>
   <content type="html">&lt;p&gt;I spent the first several days of March (1st - 5th) in Santa Barbara, CA. This
was my first time in Santa Barbara, and I really enjoyed it.&lt;/p&gt;

&lt;p&gt;I paid a crazy premium for an &lt;a href=&quot;https://www.airbnb.com/rooms/3930877&quot;&gt;AirBnb rental&lt;/a&gt; in the hearth of the
city, and while I felt like it was overpriced, I am glad that I stayed
downtown. I enjoyed a number of restaurants there, and found a bar (The Pickle
Room) where I ended most nights.&lt;/p&gt;

&lt;p&gt;On my last day in the area, I visited a handful of wineries in the area, and
really enjoyed the little town of Los Olivos.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Indio</title>
   <link href="https://jacobswanner.com/travel/2016/indio/"/>
   <updated>2016-04-18T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/indio</id>
   <content type="html">&lt;p&gt;After leaving Santa Fe, I stopped for a few days (28 February - 1 March) in
Indio, CA. There were a few reasons for stopping here: the place I wanted to
stay in Santa Barbara wasn’t available until 1 March, I wanted to see Joshua
Tree National Park, and I wanted shorter distances to drive each day.&lt;/p&gt;

&lt;p&gt;Joshua Tree was incredibly beautiful, I’m so glad I spent a day there, and
would love to go back and spend more time there. Indio seemed nice, for a
suburban area in Southern California.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Turning Point</title>
   <link href="https://jacobswanner.com/travel/2016/turning-point/"/>
   <updated>2016-04-17T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/turning-point</id>
   <content type="html">&lt;p&gt;Today marks a turning point in this journey: I’ve started driving east. Up
until this point, I’ve generally been heading west and north, but that’s no
longer the case. For this next leg of the journey it’ll be heading east and
south.&lt;/p&gt;

&lt;p&gt;It’s a little awkward to have an entry about this turning point right now, as
I’m still quite behind on the entries that I’ve been meaning to write about. So
having an entry about leaving the Western Washington and driving to Boise,
Idaho seems out of place, since I haven’t yet written about visiting various
places in California, Portland, Vancouver and the Puget Sound area. But, it
seemed important enough that I should write about it today, despite the weird
sequence of entries it would cause.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Santa Fe</title>
   <link href="https://jacobswanner.com/travel/2016/santa-fe/"/>
   <updated>2016-04-08T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/santa-fe</id>
   <content type="html">&lt;p&gt;I’m continuing to try to catch up on entries I’ve been meaning to write, so to
that end…&lt;/p&gt;

&lt;p&gt;I was in Santa Fe, NM from the 21st to the 27th of February. It was my first
time in Santa Fe, and I really enjoyed it. I hiked on 3 different occasions, at
2 different locations, and the scenery was really quite beautiful. They like to
say they have their own cuisine in New Mexico, although it mostly seems like
Mexican with some tweaks. There are a number of chilies (as in peppers) that
fall under the name of &lt;a href=&quot;https://en.wikipedia.org/wiki/New_Mexico_chile&quot;&gt;New Mexico chile&lt;/a&gt;, but all it really comes down
to is if you’d like red chile sauce or green chile sauce added to your food.
And both come from the same kind of chile, it’s just a matter of if the sauce
was made with fresh or dried chiles.&lt;/p&gt;

&lt;p&gt;My AirBnb hosts, Eric and Ishwari, were incredibly nice, and their &lt;a href=&quot;https://www.airbnb.com/rooms/4183036&quot;&gt;“casita”
that I stayed in was quite delightful&lt;/a&gt;. I would certainly return to
Santa Fe again, and stay in the same place as well.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Photo Collection</title>
   <link href="https://jacobswanner.com/travel/2016/photo-collection/"/>
   <updated>2016-04-01T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/photo-collection</id>
   <content type="html">&lt;p&gt;I have been doing a very poor job of keeping this journal current. I haven’t
written a new entry in about a month and a half. So today, while I sit in my
car in Centralia, WA as my car charges, I will try to catch up with entries for
the places I’ve been since that last entry.&lt;/p&gt;

&lt;p&gt;I have been much better at keeping the &lt;a href=&quot;https://www.google.com/maps/d/viewer?mid=zvEe98VSnsBA.kqNPdFY2CvDI&quot;&gt;journey map&lt;/a&gt;, that I
&lt;a href=&quot;/travel/2016/journey-map/&quot;&gt;wrote about previously&lt;/a&gt;, up to date with where I’ve been.
So, if you are curious about of my current location, that’s probably the best
thing to check.&lt;/p&gt;

&lt;p&gt;I’ve also been creating albums on Flickr, which contain photos that I’ve been
taking along the way. Those albums are &lt;a href=&quot;https://www.flickr.com/photos/jacobswanner/collections/72157664446762960/&quot;&gt;grouped into a collection for this
journey&lt;/a&gt;, if you are curious to see those. I’ve been doing a
better job of uploading new photos as I go than I’ve been about writing about
my experiences here, but currently there are still many photos that I have not
yet uploaded.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Austin</title>
   <link href="https://jacobswanner.com/travel/2016/austin/"/>
   <updated>2016-04-01T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/austin</id>
   <content type="html">&lt;p&gt;I was in Austin, TX from the 14th to the 20th of February. That was not my
first time in, and I always really enjoy the city when I’m there. During that
stay, unfortunately, I did not get out and do too much in the city. For
instance, I didn’t attend any live music shows, which I probably should have
done.&lt;/p&gt;

&lt;p&gt;I did go to a number of nice restaurants and bars, I also went to Franklin’s
Barbecue to take in that experience. This is probably heresy to say: I enjoyed
the experience of waiting in line more than I enjoyed the food. The food was
good, don’t get me wrong, but perhaps my expectations were too high. Given I
was with the right group of people, I would certainly do it again.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>New Orleans</title>
   <link href="https://jacobswanner.com/travel/2016/new-orleans/"/>
   <updated>2016-02-14T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/new-orleans</id>
   <content type="html">&lt;p&gt;This morning I left New Orleans; I was only there a few nights, I spent
the first part of the week visiting my father in Knoxville, TN.
Knoxville was cold, too cold, there were snow flurries the first couple
days I was there, so the milder temperatures of New Orleans was a
welcome change.&lt;/p&gt;

&lt;p&gt;New Orleans ticks a number of the boxes for things that I think help
make for a great city: decent public transportation, well located green
spaces, and good places for food &amp;amp; drink. It also has the added bonus of
having a great music scene and culture all its own. I’m not sure if the
wealth gap is wider in New Orleans or not, but it is something that’s on
my mind whenever I’m there, and that makes me sad.&lt;/p&gt;

&lt;p&gt;I do love that city though, while I was standing in d.b.a. on Frenchmen
St listening to a band perform, I was so incredibly happy to be in New
Orleans.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Journey Map</title>
   <link href="https://jacobswanner.com/travel/2016/journey-map/"/>
   <updated>2016-02-13T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/journey-map</id>
   <content type="html">&lt;p&gt;I’ve created a &lt;a href=&quot;https://felt.com/map/Nomadic-Journey-2016-1Q9Botq0cQLyxnAnRz0EhgA&quot;&gt;map&lt;/a&gt; of my journey, which you can also see below, but for
optimal viewing probably best to view full screen. Attached to the map are some
photos I’ve taken along the way.&lt;/p&gt;

&lt;iframe width=&quot;100%&quot; height=&quot;480&quot; frameborder=&quot;0&quot; title=&quot;Journey Map&quot; src=&quot;https://felt.com/embed/map/Nomadic-Journey-2016-1Q9Botq0cQLyxnAnRz0EhgA?lat=39.41839251463669&amp;amp;lon=-96.55744999999999&amp;amp;zoom=4&quot;&gt;&lt;/iframe&gt;

</content>
 </entry>
 
 <entry>
   <title>Atlanta</title>
   <link href="https://jacobswanner.com/travel/2016/atlanta/"/>
   <updated>2016-02-13T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/atlanta</id>
   <content type="html">&lt;p&gt;I spent the first week of my travels in Atlanta, Georgia, in fact the
&lt;a href=&quot;/travel/2016/nomadic-journey/&quot;&gt;previous post&lt;/a&gt; was written on my first night in Atlanta.
I had a great time for the week that I was there: I got to visit good
friends, had some lovely meals, and really enjoyed the &lt;a href=&quot;https://www.airbnb.com/rooms/1281088&quot;&gt;rental
apartment&lt;/a&gt; where I stayed.&lt;/p&gt;

&lt;p&gt;I’m not doing such a good job of keeping this journal current, as I left
Atlanta back on 8 February, hopefully that’s not a trend that will
continue.&lt;/p&gt;

&lt;p&gt;I ended up staying in Atlanta a day longer than I originally planned,
and the reason for that basically comes down to when I was planning I
wasn’t thinking about the Super Bowl. So, I stayed an extra night in
order to be with old friends during the game, which was definitely worth
it.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Nomadic Journey</title>
   <link href="https://jacobswanner.com/travel/2016/nomadic-journey/"/>
   <updated>2016-02-01T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/travel/2016/nomadic-journey</id>
   <content type="html">&lt;p&gt;This morning I got in my car and drove away from Orlando; this was the
first time since August 2000 that I’ve left Orlando with no idea of when
I’ll be back and if I’ll ever live there again. I’ve moved out of my
apartment, but instead of finding another permanent residence, I’m going
to be nomadic for a while, living out of Airbnb rentals and the like. I
don’t have a set end date for when this nomadic journey will end,
instead I’m just planning on traveling around until I get tired of what
I’m doing and come up with a better plan.&lt;/p&gt;

&lt;p&gt;My strategy as I move around is to only drive a day or two between
locations, then stay in each location for a week or two.  As for where
I’ll be going during these travels: since it’s currently winter, I’m
starting by going west along the southern part of the country, avoiding
the colder northern states. After reaching California, then I’ll head
north along the Pacific coast, and most likely continuing in that
direction until I reach Vancouver. By which time it’ll be spring, and
I’ll probably start heading east along the northern states.&lt;/p&gt;

&lt;p&gt;None of these plans are really set in stone, and those ideas I have for
what I’ll be doing further in the future are much less defined. If you
have any suggestions for where I should go, I would love for you to
reach out and let me know.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>RailsDiff Rewrite</title>
   <link href="https://jacobswanner.com/development/2015/rails-diff-rewrite/"/>
   <updated>2015-02-27T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2015/rails-diff-rewrite</id>
   <content type="html">&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/railsdiff/railsdiff&quot;&gt;RailsDiff&lt;/a&gt; is now an &lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember&lt;/a&gt; app, built using
&lt;a href=&quot;http://www.ember-cli.com/&quot;&gt;Ember CLI&lt;/a&gt;, and it gets its data from a new
&lt;a href=&quot;https://github.com/railsdiff/api&quot;&gt;API&lt;/a&gt; built using &lt;a href=&quot;http://www.sinatrarb.com/&quot;&gt;Sinatra&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Yesterday morning I released a complete rewrite of
&lt;a href=&quot;http://railsdiff.org/&quot;&gt;RailsDiff&lt;/a&gt;, which just so happened to be exactly 31 months
since I first launched the site. This new version uses a completely
different architecture from the previous; this post is to describe some
of the motivations behind the changes, and how those changes were made.&lt;/p&gt;

&lt;h3 id=&quot;wait-whats-the-point-of-railsdiff&quot;&gt;Wait, what’s the point of RailsDiff?&lt;/h3&gt;

&lt;p&gt;As of yesterday, one out of my six colleagues that predominantly work
with &lt;a href=&quot;https://www.ruby-lang.org/en/&quot;&gt;Ruby&lt;/a&gt; and &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;Rails&lt;/a&gt; still didn’t know the purpose of
RailsDiff. I’ve obviously done a good job getting the word out.&lt;/p&gt;

&lt;p&gt;When you are going to upgrade a Rails application, RailsDiff is there to
help you. It shows you what has changed in the default configurations
between the version you are currently using and that to which you want
to upgrade. The post where &lt;a href=&quot;/development/2013/announcing-rails-diff-finally/&quot;&gt;RailsDiff was announced&lt;/a&gt;
goes into a bit more detail.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;RailsDiff is about what you should change about your application’s
configuration when upgrading Rails versions, not about what Rails has
changed internally.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;motivation-for-the-change&quot;&gt;Motivation for the change&lt;/h2&gt;

&lt;p&gt;When I started this rewrite, my goal was not to use the latest, shiny
tools available; instead it was to solve some real problems that I was
having. And, in order to explain those problems, I believe a short
review of how the app/site was built previously is in order.&lt;/p&gt;

&lt;p&gt;The old implementation was a &lt;a href=&quot;http://en.wikipedia.org/wiki/Static_web_page&quot;&gt;static site&lt;/a&gt; hosted on
&lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt;. I had good reasons to build the site that
way at the time. GitHub Pages is free, and I didn’t need an application
to generate diffs on-demand because once a diff is generated it won’t
change.&lt;/p&gt;

&lt;p&gt;In order to have a static site, something needs to generate HTML files,
and for that I turned to &lt;a href=&quot;https://github.com/ruby/rake&quot;&gt;Rake&lt;/a&gt;. I actually made extensive use of
Rake for RailsDiff, I used it to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Generate a new Rails app with each new release of Rails&lt;/li&gt;
  &lt;li&gt;Generate a diff between each new app and all those that came before it&lt;/li&gt;
  &lt;li&gt;Generate HTML files for each new diff&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And, I was quite happy with that implementation. I really liked the
process of updating the site when a new version of Rails was released,
which usually took about a minute to do:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rake&lt;/code&gt; to generate all the new files&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git add -A&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git commit&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git push origin gh-pages&lt;/code&gt; to deploy the site&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, after 2.5 years and many releases of Rails this approach did have
its downsides – most notably in disk space. It was approaching 5GB of
generated, static files and growing exponentially faster with each new
releases of Rails. Which caused me to be reluctant to add new features
to the site, because that would mean more HTML files for each release,
and even faster growth of disk space usage. I was also worried about the
impact on collaborators, if step 1 was giving up 5GB+ of their hard
drive space.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/development/assets/rails-diff-rewrite/before.png&quot; alt=&quot;Before&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;better-stronger-faster&quot;&gt;Better, stronger, faster&lt;/h2&gt;

&lt;p&gt;Something needed to change, and the place I decided to start was with
the HTML files, as they were taking up the majority of the space. That
meant dynamically rendering the diffs as HTML, but I also wanted to keep
it a static site for its ease of hosting and speedy responses; using a
client-side JavaScript application to do the rendering seemed to meet
all the criteria. I chose &lt;a href=&quot;http://emberjs.com/&quot;&gt;Ember&lt;/a&gt; mostly because of all of the
JavaScript frameworks currently available it’s the one I’m most familiar
with, and the one we at Envy have the most experience with.&lt;/p&gt;

&lt;p&gt;The first pass at the rewrite still had the diffs generated with Rake,
which I put into the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/public&lt;/code&gt; directory of the &lt;a href=&quot;http://www.ember-cli.com/&quot;&gt;Ember CLI&lt;/a&gt;
app; this had the unfortunate side effect of all those diff files being
copied to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dist&lt;/code&gt; directory on build, which slowed down the build
process, and meant I wasn’t saving as much disk space. I eventually
worked around this downside by moving the diffs out of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/public&lt;/code&gt;
directory and instead modifying the build process to copy the files
over, which meant for development builds I could just copy a subset of
the diff files; this too was less than ideal, but at least kept
development build faster.&lt;/p&gt;

&lt;p&gt;At that point I had a working application, but I needed to figure out
the deployment strategy. Having enjoyed my experience with GitHub Pages
up to that point, I wanted to continue to use it. Unfortunately it’s not
a great host for Ember applications unless you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HashLocation&lt;/code&gt;
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;location: &apos;hash&apos;&lt;/code&gt; in the router), which I preferred to avoid. The next
option was to deploy to &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt; using the &lt;a href=&quot;https://github.com/tonycoco/heroku-buildpack-ember-cli&quot;&gt;buildpack suggested
by Ember CLI&lt;/a&gt;. But, this didn’t actually work for me,
because all of the diff files made the resulting application slug
&lt;a href=&quot;https://devcenter.heroku.com/articles/slug-compiler#slug-size&quot;&gt;larger than Heroku allowed limit&lt;/a&gt;, which led to me
&lt;a href=&quot;https://github.com/railsdiff/heroku-buildpack-ember-static&quot;&gt;modifying that buildpack to host pre-built Ember
apps&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After updating the UI, adding support for legacy URLs, and some other
general polishing of the application, I was ready to release it. I was
still a bit worried about the disk usage issue, as generating the diff
files still had an exponential growth curve. That’s when a couple of my
colleagues (Dray &amp;amp; Nate) convinced me that I needed to make an API app
to generate the diff files on-demand; the reason being that only
generating a new Rails app with each new release, and not the
differences between all the releases, leads to a linear growth curve.&lt;/p&gt;

&lt;h3 id=&quot;result&quot;&gt;Result&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/development/assets/rails-diff-rewrite/after.png&quot; alt=&quot;After&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And, that’s where we are today. There are now two apps to be maintained:
&lt;a href=&quot;https://github.com/railsdiff/railsdiff&quot;&gt;one for UI &amp;amp; behavior&lt;/a&gt;, and &lt;a href=&quot;https://github.com/railsdiff/api&quot;&gt;the other for
data&lt;/a&gt;. Each with their own deployment schemes, their own
narrow focus, and their own optimizations. It’s been a lot of effort and
in the end, I’m very happy with the result. Hopefully, you will enjoy
these changes as well.&lt;/p&gt;

&lt;p&gt;If you see a problem with these changes or anything else that can be
improved, &lt;a href=&quot;https://github.com/railsdiff/railsdiff/issues&quot;&gt;please let us know&lt;/a&gt;.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Rake: Rule Tasks</title>
   <link href="https://jacobswanner.com/development/2014/rake-rule-tasks/"/>
   <updated>2014-03-17T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2014/rake-rule-tasks</id>
   <content type="html">&lt;p&gt;This is the third post in a series on Rake, see previous posts for &lt;a href=&quot;/development/2013/rake-global-tasks/&quot;&gt;an
introduction of the Rakefile format along with global tasks
&lt;/a&gt;, and &lt;a href=&quot;/development/2013/rake-file-tasks/&quot;&gt;task dependencies along with file
tasks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;At one point, I thought about writing about something else besides Rake
(Rails 4.1 perhaps?). But, with the &lt;a href=&quot;http://ruby5.envylabs.com/episodes/478-episode-442-february-21st-2014/stories/3854-jim-weirich-passed-away&quot;&gt;recent passing of Jim
Weirich&lt;/a&gt;, I felt it better to continue showcasing
one of his many contributions to the Ruby community.&lt;/p&gt;

&lt;p&gt;So, to that end, in this post we’re going to look at another capability
of Rake: rule tasks. We’ll cover how create them, how they work, and
then we’ll expand on the example from the previous post to make it
usable for more of our configuration files.&lt;/p&gt;

&lt;p&gt;We’ll start off with this:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/database.yml&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/database.yml.example&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prerequisites&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And, end up with this:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.yml&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.yml.example&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Which is not only less code, but as you’ll see, more useful.&lt;/p&gt;

&lt;h2 id=&quot;rule-tasks&quot;&gt;Rule Tasks&lt;/h2&gt;

&lt;p&gt;Rule tasks, also known as synthesized tasks, have the same
characteristics as all other kinds of tasks: they have a name, they can
have zero or more actions, they can have prerequisites, and if Rake
determines the task needs to be run it will only be run once.&lt;/p&gt;

&lt;p&gt;What makes rule tasks different is that you don’t actually give them a
name – I know, I just said that rule tasks have names, just bear with
me – instead when you declare the task you give it a pattern in place
of a name.&lt;/p&gt;

&lt;h3 id=&quot;task-declaration&quot;&gt;Task Declaration&lt;/h3&gt;

&lt;p&gt;If that made no sense, hopefully looking at some code will clear things
up. First, we declare the rule task, and for that we use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rule&lt;/code&gt;
method:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/foo/&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;called task named: %s&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the above example, we used a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Regexp&lt;/code&gt; pattern to create a rule task
that will match any task name with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foo&lt;/code&gt; in it, and it’s action will
report the task’s name. Let’s see it in action:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake foobar
called task named: foobar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see above, once executed, the task’s name was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foobar&lt;/code&gt;, as
that was the name given to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rake&lt;/code&gt; command, but the rule’s pattern is
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/foo/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A common use for rule tasks is when dealing with files, especially when
we don’t necessarily know what the file’s name will be, but we know what
to do based on part of the file’s name, like its extension:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/\.txt$/&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;creating file: %s&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;touch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the above example, we used a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Regexp&lt;/code&gt; pattern to create a rule task
that will match any task name ending in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.txt&lt;/code&gt;, and it’s action will
create a file with that name. Let’s see how this task works in action:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake hello.txt
creating file: hello.txt
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;hello.txt
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls
&lt;/span&gt;hello.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This approach of matching based on the end of the task’s name is so
common in Rake, we actually don’t need to use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Regexp&lt;/code&gt; for it, as just a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;String&lt;/code&gt; of what the end of the task’s name will be will suffice:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.txt&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;creating file: %s&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;touch&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake world.txt
creating file: world.txt
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;world.txt
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls
&lt;/span&gt;hello.txt world.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h3&gt;

&lt;p&gt;As with any other kind of Rake task, rule tasks can have dependencies.
These dependency tasks can be either regular, file, or other rule tasks.
And, they are declared using the same &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash&lt;/code&gt; syntax we’ve seen before:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.dependency&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;called task: %s&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.task&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.dependency&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;called task: %s&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake rule.task
called task: rule.dependency
called task: rule.task
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;rules-for-files&quot;&gt;Rules for Files&lt;/h3&gt;

&lt;p&gt;Rule tasks don’t need to be about files, as some of the examples above
have shown, but if there is a file with the same name as the task’s
name, then that task will have the characteristics of a file task.
&lt;a href=&quot;/development/2013/rake-file-tasks/&quot;&gt;There’s an entire post in this series about file tasks&lt;/a&gt;, if
you need a reminder of their characteristics and how they are used. But,
in a gist, it means: the task will only be executed if the file does not
exist, or unless it has a file task dependency with a newer timestamp
than itself.  Also like file tasks, if the dependency is a rule task
matching existing files, you do not need an explicit declaration for the
dependency task itself.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.txt&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.template&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prerequisites&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For rule tasks, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Task&lt;/code&gt; object has an additional &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;source&lt;/code&gt; method
which, I believe, can improve the readability of our task declaration:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.txt&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.template&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s see this task in action:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls
&lt;/span&gt;file.template               &lt;span class=&quot;c&quot;&gt;# file.txt does not exist&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake file.txt
&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;file.template file.txt   &lt;span class=&quot;c&quot;&gt;# output from running task&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls
&lt;/span&gt;file.template file.txt      &lt;span class=&quot;c&quot;&gt;# new file has been created&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake file.txt
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;                          &lt;span class=&quot;c&quot;&gt;# attempting task again, produces no output&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;useful-example&quot;&gt;Useful Example&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;/development/2013/rake-file-tasks/&quot;&gt;In the prevous post of this series&lt;/a&gt;, we used a file task
to copy example configuration files to their desired location:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/database.yml&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/database.yml.example&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prerequisites&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake config/database.yml
&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;database.yml.example database.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And, while this certainly works, things start to get a bit unruly once
we want to apply this technique to a number of files:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/database.yml&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/database.yml.example&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prerequisites&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/newrelic.yml&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/newrelic.yml.example&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prerequisites&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/sidekiq.yml&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/sidekiq.yml.example&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prerequisites&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is a great example of where a rule task really shines. All we need
to do is create a single task with the correct patterns:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;rule&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.yml&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;.yml.example&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And, we can apply it to any number of files:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake config/database.yml
&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;database.yml.example database.yml
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake config/newrelic.yml
&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;newrelic.yml.example newrelic.yml
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake config/sidekiq.yml
&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;sidekiq.yml.example sidekiq.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
 </entry>
 
 <entry>
   <title>Rake: File Tasks</title>
   <link href="https://jacobswanner.com/development/2013/rake-file-tasks/"/>
   <updated>2013-11-25T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2013/rake-file-tasks</id>
   <content type="html">&lt;p&gt;This is the second in a series on Rake, &lt;a href=&quot;/development/2013/rake-global-tasks/&quot;&gt;see previous post for
introduction on the Rakefile format and about global tasks with
Rake&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this post we’re going to look at another capability of Rake: file
tasks. We’ll cover how create them, how they work, and then create a
useful example. But, before we get into file tasks, we need to have a
better understanding of another aspect of the Rakefile format:
prerequisites.&lt;/p&gt;

&lt;h2 id=&quot;task-prerequisites&quot;&gt;Task Prerequisites&lt;/h2&gt;

&lt;p&gt;Any Rake task can optionally have one, or more, prerequisite tasks –
also referred to as dependencies. As with any other Rake task, a
prerequisite task is only executed if it is needed, and if it is
executed it is only ever done so once.&lt;/p&gt;

&lt;p&gt;Let’s start by declaring a couple tasks called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;one&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;two&lt;/code&gt; in our
Rakefile:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;one&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;one&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;two&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;two&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can run the tasks in a shell, as we’ve seen before:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake one
one
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake two
two
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now let’s declare &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;one&lt;/code&gt; as a prerequisite for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;two&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;one&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;one&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;two&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;one&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;two&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, we haven’t changed how &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;one&lt;/code&gt; was defined at all. But,
for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;two&lt;/code&gt;, we added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&amp;gt; [&apos;one&apos;]&lt;/code&gt; after the task name: this is how you
declare a task’s prerequisites. At first this format may seem foreign,
but keep in mind, this is just Ruby code; let’s see how our Rakefile
would look like if we added in all of Ruby’s optional syntax:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;one&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;one&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;two&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;one&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]})&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;two&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, in both cases, we’re just passing 1 argument and a block
to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task&lt;/code&gt; method. For &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;one&lt;/code&gt;, we pass in just the task name, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;one&apos;&lt;/code&gt;;
for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;two&lt;/code&gt;, we’re passing in a hash, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{&apos;two&apos; =&amp;gt; [&apos;one&apos;]}&lt;/code&gt;, the hash key
is the task name &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&apos;two&apos;&lt;/code&gt; and the hash value is an array of prerequisites
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[&apos;one&apos;]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aside&lt;/strong&gt;: If your task only has one prerequisite, the hash value doesn’t
need to be an array:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;two&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;one&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;two&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s see what happens when we run each of those tasks now:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake one
one
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake two
one
two
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see above, when we ran &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;two&lt;/code&gt;, we get the output from both the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;one&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;two&lt;/code&gt; tasks. Now that we have a foundation for prerequisite
tasks to build on, let’s look at file tasks.&lt;/p&gt;

&lt;h2 id=&quot;file-tasks&quot;&gt;File Tasks&lt;/h2&gt;

&lt;p&gt;Thus far, all of the tasks we’ve created have used Rake’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task&lt;/code&gt; method
to declare the task, but for file tasks Rake has a special method:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;file&lt;/code&gt;. File tasks in Rake are very similar to normal tasks: they have a
name, they can have zero or more actions, they can have prerequisites,
and if Rake determines the task needs to be run it will only be run
once. Now, the twist is that those things get modified to be file
related: the name of the task is the same as the file’s name, Rake
determines that a file task needs to be run if the file doesn’t exist or
if any of the prerequisite file tasks are newer.&lt;/p&gt;

&lt;p&gt;That’s a bit to wrap your head around, so let’s look at some examples:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;foo.txt&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;touch&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;foo.txt&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Even though file tasks are meant for dealing with files, you are still
responsible for creating the file in the task’s action if the file
doesn’t exist.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aside&lt;/strong&gt;: Rake includes a modified version of the
&lt;a href=&quot;http://ruby-doc.org/stdlib-2.0.0/libdoc/fileutils/rdoc/FileUtils.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileUtils&lt;/code&gt;&lt;/a&gt; module so that you have access to its methods
in your task actions, which is where that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;touch&lt;/code&gt; method above is from.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aside&lt;/strong&gt;: &lt;a href=&quot;http://ruby-doc.org/stdlib-2.0.0/libdoc/fileutils/rdoc/FileUtils.html#method-c-touch&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileUtils.touch&lt;/code&gt;&lt;/a&gt; works like the &lt;a href=&quot;http://en.wikipedia.org/wiki/Touch_(Unix)&quot;&gt;Unix
touch&lt;/a&gt; program: updates a file’s timestamps and creates
nonexistent files.&lt;/p&gt;

&lt;p&gt;And, now when we run that task:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake foo.txt
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;foo.txt   &lt;span class=&quot;c&quot;&gt;# output from our file task when it&apos;s run&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt;            &lt;span class=&quot;c&quot;&gt;# showing file was created&lt;/span&gt;
foo.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Earlier, I mentioned that Rake will not run a file task if the file
exists; so let’s see what happens when I delete the file and then run
the task twice:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rm &lt;/span&gt;foo.txt    &lt;span class=&quot;c&quot;&gt;# deleting file&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake foo.txt  &lt;span class=&quot;c&quot;&gt;# running file task&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;foo.txt   &lt;span class=&quot;c&quot;&gt;# output from our task&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake foo.txt  &lt;span class=&quot;c&quot;&gt;# running file task again, but no output&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt;            &lt;span class=&quot;c&quot;&gt;# showing file was created&lt;/span&gt;
foo.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we can see, the first time we ran the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foo.txt&lt;/code&gt; task we see the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;touch foo.txt&lt;/code&gt; output from the file being created, but the second time
we ran the task we get no such output. But, things behave a bit
different if we add a prerequisite to our file task:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;foo.txt&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;bar.txt&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;touch&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;foo.txt&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Aside&lt;/strong&gt;: If the prerequisite for a file task is another file, you do
not need to create an explicit file task for the prerequisite, just
using the name of the file is enough.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt;              &lt;span class=&quot;c&quot;&gt;# showing foo.txt does not exist&lt;/span&gt;
bar.txt
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake foo.txt    &lt;span class=&quot;c&quot;&gt;# running file task&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;foo.txt     &lt;span class=&quot;c&quot;&gt;# output from file task&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake foo.txt    &lt;span class=&quot;c&quot;&gt;# running file task again, but no output&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt;              &lt;span class=&quot;c&quot;&gt;# showing file was created&lt;/span&gt;
bar.txt foo.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So far, things don’t seem much different: our file task creates the file
if it doesn’t exist, and if we run the task again nothing happens.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;bar.txt   &lt;span class=&quot;c&quot;&gt;# update timestamp of prerequisite file&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake foo.txt    &lt;span class=&quot;c&quot;&gt;# running file task again&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;foo.txt     &lt;span class=&quot;c&quot;&gt;# output! the file was updated!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because the timestamp for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bar.txt&lt;/code&gt; file was newer than that of the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foo.txt&lt;/code&gt; file, Rake executes the actions for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foo.txt&lt;/code&gt; task.&lt;/p&gt;

&lt;h3 id=&quot;useful-example&quot;&gt;Useful Example&lt;/h3&gt;

&lt;p&gt;With this series, I’m trying to show you a feature of Rake, then show a
useful example of using that feature, hoping that it’ll spark an idea
for how you can use Rake in your normal development process; this post
is no exception.&lt;/p&gt;

&lt;p&gt;In our Rails applications, we typically have a number of configuration
files that are critical for the application to run correctly. But,
because these files contain either sensitive information or settings
specific to where it’s being run, we do not put these files in source
control; instead we usually add an “example” file with dummy data, so
those who begin working on our application later know what needs to be
set. Well, we can use Rake to simplify the creation of our configuration
files from these “example” files.&lt;/p&gt;

&lt;p&gt;So, let’s say we want to create the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/database.yml&lt;/code&gt; file from the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/database.yml.example&lt;/code&gt; file:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/database.yml&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/database.yml.example&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/database.yml.example&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/database.yml&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Aside&lt;/strong&gt;: Here we are using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FileUtils&lt;/code&gt;’s &lt;a href=&quot;http://ruby-doc.org/stdlib-2.0.0/libdoc/fileutils/rdoc/FileUtils.html#method-c-cp&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cp&lt;/code&gt;&lt;/a&gt; (short
for: copy) method.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;config/                          &lt;span class=&quot;c&quot;&gt;# showing database.yml does not exist&lt;/span&gt;
database.yml.example
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake config/database.yml            &lt;span class=&quot;c&quot;&gt;# running file task&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;database.yml.example database.yml  &lt;span class=&quot;c&quot;&gt;# output from file task&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;config/                          &lt;span class=&quot;c&quot;&gt;# showing file was created&lt;/span&gt;
database.yml database.yml.example
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Okay, so our task is working properly, and copying the example file as
expected. I’m not a huge fan of our task definition as it stands:
there’s too much repetition, and we can clean that up. When creating a
task, the block that you pass to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task&lt;/code&gt; method can also take an
argument, which will be the task itself. We can use this task argument
to &lt;a href=&quot;http://en.wikipedia.org/wiki/Don&apos;t_repeat_yourself&quot;&gt;DRY&lt;/a&gt; up our task definition:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/database.yml&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;config/database.yml.example&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prerequisites&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That looks much better, and it still behaves the same. With this task in
place, anyone who joins the project can run the task and will then have a
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/database.yml&lt;/code&gt; to use. If they happen to run it again, nothing
will happen; until someone updates the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/database.yml.example&lt;/code&gt;
file, at which point you can then run this task again and get the latest
changes.&lt;/p&gt;

&lt;p&gt;That means you can think of these “example” files as templates
for the actual files we need. Granted, it would be nice if the task
didn’t just overwrite our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config/database.yml&lt;/code&gt; with the contents of the
example file and instead allowed it to merge the two files together; in
future posts in this series we’ll be looking at expanding this task to
do just that!&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Rake: Global Tasks</title>
   <link href="https://jacobswanner.com/development/2013/rake-global-tasks/"/>
   <updated>2013-09-23T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2013/rake-global-tasks</id>
   <content type="html">&lt;p&gt;I’m hoping this to be the first post in a series about Rake, hopefully demonstrating some of the lesser known capabilities of the tool. But, seeing as this is the first in the series, I should probably give a little background about Rake itself.&lt;/p&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;If you checkout the &lt;a href=&quot;https://github.com/ruby/rake&quot;&gt;GitHub repository&lt;/a&gt; for Rake, you will see it describes Rake as:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A make-like build utility for Ruby.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And, unless you know what Make is, that description is probably not all that helpful. The &lt;a href=&quot;http://web.archive.org/web/20140103051357/http://rubyrake.org/tutorial/index.html&quot;&gt;Rake tutorial&lt;/a&gt; describes Rake as:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A build tool, written in Ruby, using Ruby as a build language.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Okay, so now we’ve seen the “build” term a lot, but again, if you are not familiar with Make, you are probably not too familiar with what a build tool/utility is. I believe the &lt;a href=&quot;http://en.wikipedia.org/wiki/Rake_(software)&quot;&gt;Wikipedia article for Rake&lt;/a&gt; does a better job summarizing it:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A software task management tool. It allows you to specify tasks and describe dependencies as well as to group tasks in a namespace.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But, now we’ve replaced one vague term, build tool, with another: task management tool. Because of that, I think we need a more helpful description; while not as succinct as those given above, here’s how I like to describe Rake:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Rake lets you define tasks&lt;/li&gt;
  &lt;li&gt;Tasks can depend on other tasks&lt;/li&gt;
  &lt;li&gt;Tasks are only run if needed&lt;/li&gt;
  &lt;li&gt;Tasks are only run once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, we still need a definition for tasks. Since you define your tasks in Ruby, your tasks can do anything that you can do in Ruby. Which means you can do pretty much anything you want in your tasks – programmatically speaking.&lt;/p&gt;

&lt;h2 id=&quot;rakefile-format&quot;&gt;Rakefile Format&lt;/h2&gt;

&lt;p&gt;We’ll go more in-depth with Rake’s domain-specific language (DSL) in future posts, but just to cover our bases, here’s a simple example:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;hello&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello, World&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’d put this in a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rakefile&lt;/code&gt;, and to explain what that means: the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task&lt;/code&gt; method is how you declare a task, you pass to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task&lt;/code&gt; method the name of the task (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;hello&quot;&lt;/code&gt; in our case), and you can give a task an action to run by giving a block to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;task&lt;/code&gt; method. Now whenever we run the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hello&lt;/code&gt; task, we’ll see the response of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hello, World&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake hello
Hello, World
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;global-tasks&quot;&gt;Global Tasks&lt;/h2&gt;

&lt;p&gt;Typically, Rake tasks are defined per project, by writing the task definitions in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rakefile&lt;/code&gt;, placed in the root directory of your project. But, that’s not the only place you can define Rake tasks; Rake does let you define global tasks, these global tasks can be run from any directory – even those that do not have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rakefile&lt;/code&gt; in their hierarchy.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;The first step is to make the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.rake&lt;/code&gt; directory where the task definition files will reside:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ mkdir ~/.rake
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Next create the file for the task definitions, the file’s name does not matter, but it must the have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.rake&lt;/code&gt; extension:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ touch ~/.rake/hello.rake
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Add tasks to newly created file just like you would in any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rakefile&lt;/code&gt;; I’ll use our above &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hello&lt;/code&gt; task as an example:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ echo -e &apos;task &quot;hello&quot; do\n  puts &quot;Hello, World&quot;\nend&apos; &amp;gt; ~/.rake/hello.rake
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Invoke global task, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-g&lt;/code&gt; flag is the important part:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ rake -g hello
 Hello, World
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;hopefully-useful-example&quot;&gt;(Hopefully) Useful Example&lt;/h3&gt;

&lt;p&gt;So, now that we all know about global Rake tasks, perhaps you’re wondering how you can use them in your development workflow. Well, I’ll give you an example I use all the time, it’s a big long, so I’ve &lt;a href=&quot;https://gist.github.com/jswanner/5293719&quot;&gt;packaged it up in a gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here’s a scenario where it can come in handy: suppose you are working in a topic branch of a Rails application, the topic branch has database migrations in it, you need to switch branches, but your app will not run properly in the other branch with the migrations present in the topic branch. What can you do in this scenario?&lt;/p&gt;

&lt;p&gt;Well, you need to determine the migrations specific to this topic branch, and roll those migrations back:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ VERSION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&amp;lt;version&amp;gt; rake db:migrate:down
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or, you can keep running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rake db:rollback&lt;/code&gt; until all the migrations have been undone, but this assumes all the migrations needing to be rolled back are the latest one; which might not be the case if you’ve merged in the base branch, or rebased the topic branch, at any point.&lt;/p&gt;

&lt;p&gt;Another option is to install the Rake task from the &lt;a href=&quot;https://gist.github.com/jswanner/5293719&quot;&gt;gist&lt;/a&gt;, and run:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;rake &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; rollback_branch_migrations[master]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here I’m assuming that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; is the branch you want to change to – wrapping it in square brackets like that (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;[master]&lt;/code&gt;) is how you pass arguments to a Rake task. This Rake task will handle determining the migrations specific to your topic branch, and roll those migrations back; that way you can switch branches and your database will be in the state the other branch expects.&lt;/p&gt;

&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;To make global Rake tasks:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Define tasks in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.rake/*.rake&lt;/code&gt; files&lt;/li&gt;
  &lt;li&gt;Run tasks with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-g&lt;/code&gt; flag: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rake -g task_name&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

</content>
 </entry>
 
 <entry>
   <title>Announcing RailsDiff (finally)</title>
   <link href="https://jacobswanner.com/development/2013/announcing-rails-diff-finally/"/>
   <updated>2013-07-29T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2013/announcing-rails-diff-finally</id>
   <content type="html">&lt;p&gt;When upgrading the version of Rails used in an application, it can be difficult to know precisely every detail that should be changed.&lt;/p&gt;

&lt;p&gt;Modifying the Rails gem version in your Gemfile and then running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle update rails&lt;/code&gt; seems to work: your tests still pass, application runs like normal, etc. So, you never think twice and go about continuing to develop your application. But, were there other changes that could/should have been made as well? For instance, maybe Rails has changed the default value for some configuration settings, or perhaps new configuration settings have been added since your application was generated.&lt;/p&gt;

&lt;p&gt;What the Rails application generator creates is specific to the version of Rails it was generated for. As new versions of Rails are released, what the application generator creates can change; comparing the output of different versions of the generator can give you some understanding of the changes happening in Rails.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;img src=&quot;/development/assets/announcing-rails-diff-finally/diff.png&quot; alt=&quot;Sample diff&quot; /&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Back when Rails 3.1.1 was released, I created a bunch of diffs from the generated code between 3.1.1 and all versions of 3.1.x that came before it. I then put the diffs in gists and &lt;a href=&quot;/development/2011/upgrading-to-rails-3-1-1/&quot;&gt;wrote a blog post about it&lt;/a&gt;. Those gists helped me while I was upgrading a number of applications, because I didn’t need to guess what I should change about my applications configurations, the diffs told me exactly what to change. And, it didn’t just help me, I heard a lot of great feedback from others that those diffs also helped along the way.&lt;/p&gt;

&lt;p&gt;Unfortunately, it was tedious and time consuming to create each of those diffs, and that was just creating a dozen of them. So, the thought of creating more of those with each subsequent release of Rails was quite daunting. Automation was definitely going to be needed to keep this going in the long run.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;RailsDiff is about what you should change about your application’s configuration when upgrading Rails versions, not about what Rails has changed internally.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To that end, I’ve created &lt;a href=&quot;http://railsdiff.org&quot;&gt;RailsDiff&lt;/a&gt;. With it, you can see what changes you would need to make to your application’s configuration when upgrading from your current version of Rails to the new version of your choosing.&lt;/p&gt;

&lt;p&gt;I say in the title that I’m finally announcing &lt;a href=&quot;http://railsdiff.org&quot;&gt;RailsDiff&lt;/a&gt;, and that’s because the site has been up and running for just over a year. Admittedly, I’m a little late with this announcement, but I hope it can help you the next time you need to upgrade a Rails application.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Optional Parameter Gotchas</title>
   <link href="https://jacobswanner.com/development/2012/optional-parameter-gotchas/"/>
   <updated>2012-11-09T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2012/optional-parameter-gotchas</id>
   <content type="html">&lt;p&gt;Assuming we have a class that looks like this:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:options&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What does the following code output?&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The output will be &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{}&lt;/code&gt;, right? Well, let’s check it out:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; nil&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What the…? &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;options&lt;/code&gt; was an optional parameter, and we set the default
value to be an empty hash, what gives? What went wrong? Well, let’s try
something a little different:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This time we get the default value we were expecting, but why didn’t it
work before? Well, with optional parameters, the default value is used if the
argument is omitted; but, if an explicit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; is passed, that will be
the parameter’s value. This behavior is not just for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash&lt;/code&gt; default
values, it applies to any default value.&lt;/p&gt;

&lt;p&gt;Okay, so knowing that, how do we get around this issue? Well, the
answer’s not too bad:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:options&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; {}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So, this time we still have an optional parameter; but, we’re declaring the
default value as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;, and when we set the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@options&lt;/code&gt; instance variable
we use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;||&lt;/code&gt; to make the value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{}&lt;/code&gt;, if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;options&lt;/code&gt; is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;. This may seem
like a small change, but can mean a big different in code correctness.
If in some other part of our class we call methods on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;options&lt;/code&gt; thinking
we’re guaranteed to have a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash&lt;/code&gt; – or Hash-like object – but we
in fact have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;, that could lead to some confusing errors.&lt;/p&gt;

&lt;p&gt;Okay, so maybe now you are thinking: ‘but, I would never explicitly pass
a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; like that.’ Well, you may not knowingly do so, but take a look
at the following:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# somewhere else params is defined as: params = {}&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this scenario, maybe you thought you were passing a nested &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Hash&lt;/code&gt; into
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Foo.new&lt;/code&gt;, but if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;params&lt;/code&gt; doesn’t have a value for the key &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:foo&lt;/code&gt;,
you’ve just passed a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Foo.new&lt;/code&gt;. This is just one example of
how a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; could end up being explicitly passed as an argument, but
it’s far from the only one.&lt;/p&gt;

&lt;p&gt;I think the rule of thumb for default parameters should be:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Always declare the default value of an optional parameter as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Inside the body of the method, set the default value you actually want&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And, that’s it really. I think that’s a pretty simple rule.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Ruby executable invocation</title>
   <link href="https://jacobswanner.com/development/2012/ruby-executable-invocation/"/>
   <updated>2012-07-22T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2012/ruby-executable-invocation</id>
   <content type="html">&lt;p&gt;Since the proliferation of &lt;a href=&quot;http://gembundler.com/&quot;&gt;Bundler&lt;/a&gt;, we’ve had multiple options for
how to invoke Ruby executables; each option has its own set of
advantages &amp;amp; disadvantages.  The easiest form of invocation is to use
the executable that is installed when the gem is installed; things like:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rake&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rspec&lt;/code&gt;.  But, this form of invocation suffers from
the problem of potentially loading a version of a gem that differs from
the version your project bundle requires; you know you’ve run into this
problem when you see a message like the following:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You have already activated &amp;lt;gem-name&amp;gt; &amp;lt;version-x&amp;gt; but your Gemfile
requires &amp;lt;gem-name&amp;gt; &amp;lt;version-y&amp;gt;. Consider using bundle exec.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;binstubs&quot;&gt;Binstubs&lt;/h2&gt;

&lt;p&gt;To get around the above problem, we often prefix our executables with
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle exec&lt;/code&gt;; and, while this works, I’ve often felt that the execution
time was noticeably slower.  But, Bundler provides another solution to this
problem: &lt;a href=&quot;http://gembundler.com/man/bundle-install.1.html#OPTIONS&quot;&gt;binstubs&lt;/a&gt;.  I don’t think this option is as well known as
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle exec&lt;/code&gt;, but this is how you create them:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--binstubs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle config bin bin
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Both of the above options will install all the executables that are
provided by your bundle in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bin&lt;/code&gt; directory, you can then invoke one
of the executables like this: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./bin/rspec&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;rspec-executable-benchmarks&quot;&gt;RSpec executable benchmarks&lt;/h2&gt;

&lt;p&gt;I was interested in benchmarking the various options, to see how they
actually stack up to each other; I also wanted to see how
&lt;a href=&quot;https://github.com/funny-falcon&quot;&gt;funny-falcon’s&lt;/a&gt; &lt;a href=&quot;https://gist.github.com/2593385&quot;&gt;performance patches&lt;/a&gt;
affected the execution time – which you’ll see in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.9.3-p194-perf&lt;/code&gt;
column.  I have a separate post with instructions on how to &lt;a href=&quot;/2012/07/21/ruby-1-9-3-p194-with-perf-patches.html&quot;&gt;install
these patches&lt;/a&gt;.  So, first off, I wanted to benchmark
executing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rspec&lt;/code&gt;&lt;sup id=&quot;fnref:rspec&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:rspec&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; – all the times are listed in seconds
&lt;sup id=&quot;fnref:seconds&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:seconds&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Command&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;1.9.3-p194&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;1.9.3-p194-perf&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rspec&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.27&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.22&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./bin/rspec&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.49&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.40&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle exec rspec&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.98&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.75&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;So, my plan going forward for executables like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rspec&lt;/code&gt;: use the regular
gem executable.  If I run into a version conflict, hopefully I can fix
the issue by upgrading the gem in the appropriate projects; if that is
not an option, then at that point I’ll switch to binstubs for the
effected projects.&lt;/p&gt;

&lt;h2 id=&quot;rails-executable-benchmarks&quot;&gt;Rails executable benchmarks&lt;/h2&gt;

&lt;p&gt;Just running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rspec&lt;/code&gt; does not necessarily load your whole Rails
application.  So, the following table shows invoking &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails runner &apos;&apos;&lt;/code&gt;
&lt;sup id=&quot;fnref:rails&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:rails&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;, to see what impact that has on run times.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Command&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;1.9.3-p194&lt;/th&gt;
      &lt;th style=&quot;text-align: right&quot;&gt;1.9.3-p194-perf&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./script/rails&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1.10&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.83&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1.27&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;0.95&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./bin/rails&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1.53&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1.11&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle exec rails&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;2.01&lt;/td&gt;
      &lt;td style=&quot;text-align: right&quot;&gt;1.47&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;I showed all the options for comparison’s sake, but I actually don’t
think there’s any reason not to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./script/rails&lt;/code&gt;; and, luckily my
&lt;a href=&quot;/2010/07/15/common-rails-command-shortcuts.html&quot;&gt;Rails command shortcuts&lt;/a&gt; take care of that for
me.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:rspec&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;No specs were actually run, the benchmarked command was &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rspec -h&lt;/code&gt;, just enough to load Ruby and RSpec.  Version 2.11.1 of RSpec was used. &lt;a href=&quot;#fnref:rspec&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:seconds&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Times were measured with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time&lt;/code&gt;, only displaying the “real” value, and are the average of 10 executions. &lt;a href=&quot;#fnref:seconds&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:rails&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Version 3.2.6 of Rails was used. &lt;a href=&quot;#fnref:rails&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>Ruby 1.9.3 with performance patches</title>
   <link href="https://jacobswanner.com/development/2012/ruby-1-9-3-p194-with-perf-patches/"/>
   <updated>2012-07-21T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2012/ruby-1-9-3-p194-with-perf-patches</id>
   <content type="html">&lt;p&gt;In my &lt;a href=&quot;/2012/07/13/ruby-1-9-3-without-gcc.html&quot;&gt;last post&lt;/a&gt;, I showed how to install Ruby 1.9.3-p194 on
OS X without Xcode or &lt;a href=&quot;https://github.com/kennethreitz/osx-gcc-installer/&quot;&gt;OSX GCC Installer&lt;/a&gt;.  But, I
didn’t cover how to install &lt;a href=&quot;https://github.com/funny-falcon&quot;&gt;funny-falcon’s&lt;/a&gt; &lt;a href=&quot;https://gist.github.com/2593385&quot;&gt;performance
patches&lt;/a&gt;. I have another post which can show the
&lt;a href=&quot;/2012/07/22/ruby-executable-invocation.html&quot;&gt;speed benefits of using these patches&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The following steps assume you’ve followed steps 1-6 of my &lt;a href=&quot;/2012/07/13/ruby-1-9-3-without-gcc.html&quot;&gt;last
post&lt;/a&gt;; and, can be applied in addition to, or in replacement
of, steps 7-8.  In these steps, we will install a new version of Ruby
which will be named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.9.3-p194-perf&lt;/code&gt;, which you can keep as a separate
installation of Ruby from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1.9.3-p194&lt;/code&gt;, or it can be the only
installation of Ruby on your development environment.&lt;/p&gt;

&lt;h2 id=&quot;installation-steps&quot;&gt;Installation steps&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Install autoconf:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ brew install autoconf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Install &lt;a href=&quot;https://gist.github.com/3126141/&quot;&gt;Ruby 1.9.3-p194 with performance patches&lt;/a&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ curl &quot;https://raw.github.com/gist/3126141/rbenv.sh&quot; | sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Optionally, set Ruby 1.9.3-p194-perf as global version to use:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ rbenv global 1.9.3-p194-perf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;adjust-ruby-environment-variables&quot;&gt;Adjust Ruby environment variables&lt;/h2&gt;

&lt;p&gt;With those patches in place, we can now improve Ruby’s performance a bit
more.  Whenever Ruby’s garbage collector (GC) is running, nothing else can
run; and, by default, Ruby’s settings are a bit conservative, potentially
causing Ruby’s GC to run multiple times within a single Rails request.
So, if we can allow Ruby to use more memory, while having the GC run
less frequently, allowing more time for our code to run and less GC time,
we can improve our applications’ performance.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Install &lt;a href=&quot;https://github.com/sstephenson/rbenv-vars&quot;&gt;rbenv-vars&lt;/a&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ cd ~/.rbenv/plugins
 $ git clone https://github.com/sstephenson/rbenv-vars.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Add the following to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.rbenv/vars&lt;/code&gt;, or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.rbenv-vars&lt;/code&gt; in a
project directory:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; RUBY_GC_MALLOC_LIMIT=1000000000
 RUBY_HEAP_FREE_MIN=500000
 RUBY_HEAP_MIN_SLOTS=1000000
 RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
 RUBY_HEAP_SLOTS_INCREMENT=1000000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

</content>
 </entry>
 
 <entry>
   <title>Ruby 1.9.3 without Xcode or GCC</title>
   <link href="https://jacobswanner.com/development/2012/ruby-1-9-3-without-gcc/"/>
   <updated>2012-07-13T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2012/ruby-1-9-3-without-gcc</id>
   <content type="html">&lt;p&gt;I recently purchased a &lt;a href=&quot;http://www.apple.com/macbookair/&quot;&gt;new Mac&lt;/a&gt;, and needed to set up my development environment again; I thought I’d record the steps taken, in case it helps anyone else out in a similar position.&lt;/p&gt;

&lt;p&gt;Starting with version 4.3, Xcode no longer ships with command line developer tools, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt;; instead, they are available as an &lt;a href=&quot;http://developer.apple.com/library/ios/#documentation/DeveloperTools/Conceptual/WhatsNewXcode/Articles/xcode_4_3.html&quot;&gt;optional component to Xcode&lt;/a&gt; and as a &lt;a href=&quot;https://developer.apple.com/downloads/index.action?=command%20line%20tools&quot;&gt;download separate from Xcode&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And, since Ruby 1.9.3 supports being compiled with &lt;a href=&quot;http://www.ruby-lang.org/en/news/2012/02/16/ruby-1-9-3-p125-is-released/&quot;&gt;LLVM/clang&lt;/a&gt;, I thought I’d try setting up my environment without Xcode and without the &lt;a href=&quot;https://github.com/kennethreitz/osx-gcc-installer/&quot;&gt;OSX GCC Installer&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;installation-steps&quot;&gt;Installation steps&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Run OS X’s “Software Update”, to make sure the operating system and built-in software are up-to-date.&lt;/li&gt;
  &lt;li&gt;Download and install &lt;a href=&quot;https://developer.apple.com/downloads/index.action?=command%20line%20tools&quot;&gt;Command Line Tools for Xcode&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Install &lt;a href=&quot;http://mxcl.github.com/homebrew/&quot;&gt;Homebrew&lt;/a&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ ruby -e &quot;$(curl -fsSkL raw.github.com/mxcl/homebrew/go)&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Install &lt;a href=&quot;http://git-scm.com/&quot;&gt;Git&lt;/a&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ brew install git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Install &lt;a href=&quot;https://github.com/sstephenson/rbenv/#-2-installation&quot;&gt;rbenv&lt;/a&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ cd
 $ git clone git://github.com/sstephenson/rbenv.git .rbenv
 $ echo &apos;export PATH=&quot;$HOME/.rbenv/bin:$PATH&quot;&apos; &amp;gt;&amp;gt; ~/.bash_login
 $ echo &apos;eval &quot;$(rbenv init -)&quot;&apos; &amp;gt;&amp;gt; ~/.bash_login
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Install &lt;a href=&quot;https://github.com/sstephenson/ruby-build/#installation&quot;&gt;ruby-build&lt;/a&gt;:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ mkdir -p ~/.rbenv/plugins
 $ cd ~/.rbenv/plugins
 $ git clone git://github.com/sstephenson/ruby-build.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Install Ruby 1.9.3:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ CC=/usr/bin/clang rbenv install 1.9.3-p194
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Set Ruby 1.9.3 as global version to use:&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; $ rbenv global 1.9.3-p194
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;note&quot;&gt;Note:&lt;/h3&gt;

&lt;p&gt;In steps 3, 5 and 6, I’m showing you the commands I used, which are
based on the respective tool’s current installation guide; but, those
commands are subject to change.  Also, in step 3, I’m using the version
of Ruby that ships with OS X.&lt;/p&gt;

&lt;h2 id=&quot;result&quot;&gt;Result&lt;/h2&gt;

&lt;p&gt;Homebrew makes sure you are well aware that its support of using “Command Line Tools” without Xcode is experimental:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Error: Experimental support for using the “Command Line Tools” without
Xcode.  Some formulae need Xcode to be installed (for the Frameworks
not in the CLT.)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Despite that, I have not had any trouble installing anything I’ve needed so far – including: &lt;a href=&quot;http://www.postgresql.org/&quot;&gt;PostgreSQL&lt;/a&gt;, &lt;a href=&quot;http://www.imagemagick.org/script/index.php&quot;&gt;ImageMagick&lt;/a&gt; and &lt;a href=&quot;http://qt.nokia.com/products/&quot;&gt;Qt&lt;/a&gt;.  Likewise, I haven’t had any trouble running any Ruby/Rails applications.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Upgrading to Rails 3.1.1</title>
   <link href="https://jacobswanner.com/development/2011/upgrading-to-rails-3-1-1/"/>
   <updated>2011-10-07T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2011/upgrading-to-rails-3-1-1</id>
   <content type="html">&lt;p&gt;Often, at &lt;a href=&quot;http://envylabs.com&quot;&gt;Envy Labs&lt;/a&gt;, when we start a new application, we’ll use the
latest version of Rails available; even if that version happens to be a
prerelease.  Unfortunately, as new versions are released, it can be
difficult to know what steps need to be taken to upgrade your
applications.&lt;/p&gt;

&lt;p&gt;There are many times when just modifying the Rails gem version in your
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt; and then running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bundle update rails&lt;/code&gt; seems
to work: your tests still pass, application runs like normal, etc.  So,
you never think twice and go about continuing to develop your
application.  But, were there other changes that could/should have been
made as well?  Perhaps Rails has changed the default value for some
configuration setting; perhaps release candidates did not deal with
assets in the same way the final release did.  If you are using
prerelease versions, more things tend to change as newer versions come
out.&lt;/p&gt;

&lt;p&gt;What the Rails application generator creates is specific to the version
of Rails it was generated for.  So, as new versions are released, what
the application generator creates changes; and, comparing the output of
different versions can give you some understanding of the changes going
on in Rails.&lt;/p&gt;

&lt;p&gt;So, to that end, I generated applications for the following versions: 3.1.1, 3.1.1.rc3, 3.1.1.rc2, 3.1.1.rc1, 3.1.0, 3.1.0.rc8, 3.1.0.rc6, 3.1.0.rc5, 3.1.0.rc4, 3.1.0.rc3, 3.1.0.rc2, 3.1.0.rc1, 3.1.0.beta1 (3.1.0.rc7 has been yanked from RubyGems); then compared all of them to version 3.1.1.  I’ve made a gist for each of the comparisons:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1270918&quot;&gt;Differences between Rails 3.1.0.beta1 &amp;amp; Rails 3.1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1271131&quot;&gt;Differences between Rails 3.1.0.rc1 &amp;amp; Rails 3.1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1271136&quot;&gt;Differences between Rails 3.1.0.rc2 &amp;amp; Rails 3.1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1271141&quot;&gt;Differences between Rails 3.1.0.rc3 &amp;amp; Rails 3.1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1271145&quot;&gt;Differences between Rails 3.1.0.rc4 &amp;amp; Rails 3.1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1271147&quot;&gt;Differences between Rails 3.1.0.rc5 &amp;amp; Rails 3.1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1271149&quot;&gt;Differences between Rails 3.1.0.rc6 &amp;amp; Rails 3.1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1271160&quot;&gt;Differences between Rails 3.1.0.rc8 &amp;amp; Rails 3.1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1271163&quot;&gt;Differences between Rails 3.1.0 &amp;amp; Rails 3.1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1271165&quot;&gt;Differences between Rails 3.1.1.rc1 &amp;amp; Rails 3.1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/1271168&quot;&gt;Differences between Rails 3.1.1.rc2 &amp;amp; Rails 3.1.1&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;There is no difference between 3.1.1.rc3 &amp;amp; 3.1.1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hopefully, this will come in handy for anyone else – like me – that
needs to update some applications that were generated with a Rails
version prior to 3.1.1.  And, as you can see, depending on what version
you used to generate your application, the changes needed will vary.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Common Rails command shortcuts</title>
   <link href="https://jacobswanner.com/development/2010/common-rails-command-shortcuts/"/>
   <updated>2010-07-15T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2010/common-rails-command-shortcuts</id>
   <content type="html">&lt;p&gt;I know many people – including myself – use Bash aliases for common
command line tasks.  Some popular examples would be: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ss&lt;/code&gt;
short for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script/server&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sc&lt;/code&gt; for
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script/console&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sg&lt;/code&gt; for
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script/generate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These are setup by putting the following code in a Bash configuration
file – such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.bash_login&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;script/server&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;script/console&apos;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;sg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;script/generate&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That works great, until you switch to Rails 3; all of these script files
have been removed, and you use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails&lt;/code&gt; command in their
place: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails server&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script/server&lt;/code&gt;,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails console&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script/console&lt;/code&gt;, etc.
Rails 3 provides shortcuts for the common commands: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails s&lt;/code&gt;
is short for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails server&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails c&lt;/code&gt; is short
for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails console&lt;/code&gt;, and so on.  Some have suggested aliasing
the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rails&lt;/code&gt; command to just &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt;, allowing you to
use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r s&lt;/code&gt; to start a server.&lt;/p&gt;

&lt;p&gt;These shortcuts are nice, and is much less typing.  But, I don’t want to
have to remember when I’m in a Rails 2 app to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ss&lt;/code&gt; and
then when I’m in a Rails 3 app to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r s&lt;/code&gt;; I want
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ss&lt;/code&gt; to just work in every project.  Unfortunately, you
cannot use a Bash alias to solve this problem; you can however use a
Bash function!  The following is a drop in replacement for the old
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;alias ss=...&lt;/code&gt; stuff in your Bash configuration file:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;ss &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; script/rails &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;script/rails server &lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else
    &lt;/span&gt;script/server &lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;sc &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; script/rails &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;script/rails console &lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else
    &lt;/span&gt;script/console &lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;sg &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; script/rails &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;script/rails generate &lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else
    &lt;/span&gt;script/generate &lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;They work by checking for the existence of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;script/rails&lt;/code&gt;
file, which is new to Rails 3; if the file exists use it, otherwise fall
back to using the Rails 2 version of the command; any arguments given to
the function are passed along to the script, which is the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$@&lt;/code&gt; bit above.&lt;/p&gt;

&lt;p&gt;I’ve contributed these changes to the &lt;a href=&quot;http://github.com/pigment/terminal&quot;&gt;Terminal project by Pigment&lt;/a&gt;, which includes similar shortcuts for many other common tasks.&lt;/p&gt;

&lt;h2 id=&quot;update&quot;&gt;Update:&lt;/h2&gt;

&lt;p&gt;A nice refactoring, courtesy of &lt;a href=&quot;http://www.hashref.com/&quot;&gt;Xavier
Noria&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;rails_command &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;shift
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; script/rails &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then
    &lt;/span&gt;script/rails &lt;span class=&quot;nv&quot;&gt;$cmd&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else
    &lt;/span&gt;script/&lt;span class=&quot;nv&quot;&gt;$cmd&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;ss &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  rails_command &lt;span class=&quot;s2&quot;&gt;&quot;server&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;sc &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  rails_command &lt;span class=&quot;s2&quot;&gt;&quot;console&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;sg &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  rails_command &lt;span class=&quot;s2&quot;&gt;&quot;generate&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;sr &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  rails_command &lt;span class=&quot;s2&quot;&gt;&quot;runner&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$@&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</content>
 </entry>
 
 <entry>
   <title>What’s new in Rails 3.0 Beta 2</title>
   <link href="https://jacobswanner.com/development/2010/whats-new-rails-3-0-beta2/"/>
   <updated>2010-04-06T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2010/whats-new-rails-3-0-beta2</id>
   <content type="html">&lt;p&gt;On April 1st, &lt;a href=&quot;http://weblog.rubyonrails.org/2010/4/1/rails-3-0-second-beta-release&quot;&gt;Rails 3.0 Beta 2 was released&lt;/a&gt;, I thought I’d take this opportunity to
highlight some of the changes between the Beta 1 and Beta 2 releases.
 According to &lt;a href=&quot;http://github.com/rails/rails/compare/v3.0.0.beta1...v3.0.0.beta2&quot;&gt;GitHub&lt;/a&gt;,
there are 2,691 new, unique commits – contributed by 244 authors –
that were included in the Beta 2 release.  I’ve picked some of the
changes that I felt were important from the perspective of someone using
Rails to build a web application and those that build plugins and other
extensions for Rails.&lt;/p&gt;

&lt;p&gt;The changes are separated by each of Rails’ individual components:&lt;/p&gt;
&lt;h2 id=&quot;actionmailer&quot;&gt;ActionMailer&lt;/h2&gt;
&lt;p&gt;You can now register interceptors and observers that will be called
before and after an email is sent, respectively.  The interceptor object
must implement the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delivering_email&lt;/code&gt; method, while the
observer object must implement &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delivered_email&lt;/code&gt;.  Here’s a
simple example:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyInterceptor&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delivering_email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# do something before sending the email&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyObserver&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delivered_email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# do something after sending the email&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;ActionMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_interceptor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MyInterceptor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;ActionMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;register_observer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MyObserver&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;actionpack&quot;&gt;ActionPack&lt;/h2&gt;
&lt;p&gt;Block helpers now return Strings, so you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;%= form_for
@foo do |f| %&amp;gt;&lt;/code&gt;.  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;% form_for @foo do |f| %&amp;gt;&lt;/code&gt;
still works but will give you a deprecation notice.&lt;/p&gt;

&lt;p&gt;The way that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;send_file&lt;/code&gt; works has changed, it now defers to
a Rack middleware called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rack::Sendfile&lt;/code&gt;.  With that, the
following options have been removed from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;send_file&lt;/code&gt;:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:stream&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:buffer_size&lt;/code&gt;, and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:x_sendfile&lt;/code&gt;.  The header used to send the file is
configurable via &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.action_dispatch.x_sendfile_header&lt;/code&gt;
– which defaults to “X-Sendfile” – , and servers can configure this
setting as well by setting the “X-Sendfile-Type” header.  Hopefully,
hosting companies specializing in Rails deployments will set this
header, so that it will work transparently for those deploying there.
If you do need to set it manually, for say Lighttpd, here’s an example:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyApp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Application&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;action_dispatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;x_sendfile_header&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;X-Lighttpd-Send-File&apos;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;activemodel&quot;&gt;ActiveModel&lt;/h2&gt;
&lt;p&gt;For those creating libraries that they want to conform with ActiveModel,
there has been some changes to ActiveModel::Lint – a module of tests
that you can include in your tests to ensure your library conforms to
ActiveModel.  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#new_record?&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#destroyed?&lt;/code&gt;
were removed, use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#persisted?&lt;/code&gt; instead.  For those of you
that are curious, ActiveRecord’s implementation of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;persisted?&lt;/code&gt; is as follows: A model is persisted if it’s not
a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new_record?&lt;/code&gt; and it was not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;destroyed?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In addition, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#to_key&lt;/code&gt; was added to ActiveModel::Lint, this
is used to generate DOM IDs for ActiveModel objects.&lt;/p&gt;

&lt;h2 id=&quot;activerecord&quot;&gt;ActiveRecord&lt;/h2&gt;
&lt;p&gt;You can now prefix the table names all of the models in a module, you
just need to define &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;self.table_name_prefix&lt;/code&gt; on the module:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Prefixed&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;table_name_prefix&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;&apos;prefixed_&apos;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ModelName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;activesupport&quot;&gt;ActiveSupport&lt;/h2&gt;
&lt;p&gt;There are new assertions you can use in your tests:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;assert_blank&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;assert_present&lt;/code&gt;.  Here they
are used in a simple example:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;assert_blank&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;assert_present&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;x&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yajl-ruby&lt;/code&gt; was added as a JSON parsing backend; and is the
preferred backend, if available.  There was an interesting discussion
about using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveSupport::JSON.encode&lt;/code&gt; over
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#to_json&lt;/code&gt; on the patch’s &lt;a href=&quot;https://rails.lighthouseapp.com/projects/8994/tickets/2666&quot;&gt;Lighthouse ticket&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Session store configuration has changed.  The
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cookie_verifier_secret&lt;/code&gt; has been deprecated and it is now
assigned through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rails.application.config.cookie_secret&lt;/code&gt;
instead and moved into it’s own file:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;initializers/cookie_verification_secret.rb&lt;/code&gt;.  Also,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;session_store&lt;/code&gt; configuration has also been changed from
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActionController::Base.session&lt;/code&gt; to
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rails.application.config.session_store&lt;/code&gt; and has been moved
to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;initializers/session_store.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you were building a plugin that inherited from
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rails::Railtie&lt;/code&gt;, you were probably setting
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;railtie_name&lt;/code&gt; and/or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;engine_name&lt;/code&gt;, well both of
them have been deprecated.  You can now add any object to the
configuration object: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.your_plugin = {}&lt;/code&gt;.  To see how
the Rails internals switched to this new configuration approach, &lt;a href=&quot;http://github.com/rails/rails/commit/395d6648ce7549f71dd0a76dc061e87f608aaaab&quot;&gt;view the commit&lt;/a&gt;.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>OpenID delegates</title>
   <link href="https://jacobswanner.com/development/2008/openid-delegates/"/>
   <updated>2008-04-09T00:00:00+00:00</updated>
   <id>https://jacobswanner.com/development/2008/openid-delegates</id>
   <content type="html">&lt;p&gt;This is more or less to add to what James Duncan Davidson has already
said about OpenID and delegates.&lt;/p&gt;

&lt;p&gt;Even though I had been using OpenID for a while prior to his post, I
hadn’t set things up to use my own domain. After his post, I realized
how easy it was to do. In his example he’s using myOpenID, which I don’t
use; so, I had to figure out how to do it using my provider, Verisign
Labs PIP. I had to do a bit of searching to find the server URL
(https://pip.verisignlabs.com/server), but after that it was simple.&lt;/p&gt;

&lt;p&gt;So, to amend James Duncan Davidson’s three easy steps, replace the HTML
snippet in step 2 with the following:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;openid.server&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://pip.verisignlabs.com/server&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;openid.delegate&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://yourid.pip.verisignlabs.com&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Today I also tried out another OpenID provider built on Google App
Engine, which authenticates with your Google ID; that’s a plus if you
already have a Google account (such as Gmail) because that’s one less
account you have to remember (isn’t less IDs part of the point of
OpenID?). Anyway, the HTML snippet you need to use that provider is the
following:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;openid.server&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://openid-provider.appspot.com/&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;link&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;rel=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;openid.delegate&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;http://openid-provider.appspot.com/yourid&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Update: The above provider built on Google App Engine is currently a bit
buggy. I would shy away from changing any of your accounts to use that
as your OpenID URL directly. That’s another plus of using your own
domain as your OpenID URL, you can change the server you use on your
site without having to change the accounts that use your OpenID URL.&lt;/p&gt;
</content>
 </entry>
 

</feed>
