Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

1122 lines (928 sloc) 75.002 kb
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[John Firebaugh]]></title>
<link href="http://jfirebaugh.github.com/atom.xml" rel="self"/>
<link href="http://jfirebaugh.github.com/"/>
<updated>2013-04-09T10:46:51-04:00</updated>
<id>http://jfirebaugh.github.com/</id>
<author>
<name><![CDATA[John Firebaugh]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[new-less JavaScript]]></title>
<link href="http://jfirebaugh.github.com/blog/2013/03/20/newless-javascript/"/>
<updated>2013-03-20T10:15:00-04:00</updated>
<id>http://jfirebaugh.github.com/blog/2013/03/20/newless-javascript</id>
<content type="html"><![CDATA[<p>JavaScript borrowed the <code>new</code> and <code>delete</code> keywords from its less-dynamic
predecessor languages. They feel a bit out of place in a garbage collected
language and are a source of confusion for newbies &#8211; one of the reasons
popular libraries such as jQuery, d3, and Ember.js have adopted APIs that
don&#8217;t require using <code>new</code> at all. In this post I&#8217;ll show you one way do it,
and why you should consider it for your next JavaScript library.</p>
<p>In C++, <code>new</code> and <code>delete</code> are symmetric operators that combine memory
management and object lifecycle operations. <code>new</code> allocates an instance and
calls the constructor, and <code>delete</code> calls the destructor and deallocates it.
In garbage collected languages, <code>delete</code> isn&#8217;t necessary; Java doesn&#8217;t have
it, for example. It&#8217;s one of JavaScript&#8217;s quirks that it <em>does</em> use <code>delete</code>,
and for a purpose (removing a property from an object) that&#8217;s not symmetric
with <code>new</code>. You&#8217;ll sometimes see confused JavaScript programmers trying to
<code>delete</code> plain objects.</p>
<p><code>new</code> can itself be a source of confusion. Looking at instantiation with
<code>new</code>, it&#8217;s easy to see why: <code>new User()</code> requires both a language keyword
<em>and</em> a unique syntactic form. In other scripting languages, neither are
needed: instantiation is done via regular function notation, either via a
class method as in Ruby (<code>User.new</code>), or calling the class object as a
function as in Python (<code>User()</code>).</p>
<p>What&#8217;s worse, in JavaScript, forgetting <code>new</code> when calling a constructor can
produce some very strange behavior &#8211; leaving variables undefined and polluting
the global scope. John Resig gave a great <a href="http://ejohn.org/blog/simple-class-instantiation/">rundown of the issues and proposed a solution</a>, often dubbed the
&#8216;instanceof trick&#8217;:</p>
<figure class='code'><figcaption><span>The instanceof trick</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">function</span> <span class="nx">User</span><span class="p">(</span><span class="nx">first</span><span class="p">,</span> <span class="nx">last</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="k">this</span> <span class="k">instanceof</span> <span class="nx">User</span><span class="p">))</span> <span class="k">return</span> <span class="k">new</span> <span class="nx">User</span><span class="p">(</span><span class="nx">first</span><span class="p">,</span> <span class="nx">last</span><span class="p">);</span>
</span><span class='line'> <span class="k">this</span><span class="p">.</span><span class="nx">first</span> <span class="o">=</span> <span class="nx">first</span><span class="p">;</span>
</span><span class='line'> <span class="k">this</span><span class="p">.</span><span class="nx">last</span> <span class="o">=</span> <span class="nx">last</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="nx">User</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">fullName</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">first</span> <span class="o">+</span> <span class="s1">&#39; &#39;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">last</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>Class constructors defined with the instanceof trick can be called with or
without <code>new</code>:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'> <span class="kd">var</span> <span class="nx">userViaNew</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">User</span><span class="p">(</span><span class="s2">&quot;John&quot;</span><span class="p">,</span> <span class="s2">&quot;Firebaugh&quot;</span><span class="p">);</span>
</span><span class='line'> <span class="nx">userViaNew</span><span class="p">.</span><span class="nx">fullName</span><span class="p">();</span> <span class="c1">// &quot;John Firebaugh&quot;</span>
</span><span class='line'>
</span><span class='line'> <span class="kd">var</span> <span class="nx">userDirect</span> <span class="o">=</span> <span class="nx">User</span><span class="p">(</span><span class="s2">&quot;John&quot;</span><span class="p">,</span> <span class="s2">&quot;Resig&quot;</span><span class="p">);</span>
</span><span class='line'> <span class="nx">userDirect</span><span class="p">.</span><span class="nx">fullName</span><span class="p">();</span> <span class="c1">// &quot;John Resig&quot;</span>
</span></code></pre></td></tr></table></div></figure>
<p>In either case, the result is a newly allocated and initialized User.</p>
<p>John Resig goes on to show how to create a reusable function that builds
constructors that use the instanceof trick. This way, instead of writing it
out manually for every class, you write it once and use a <a href="https://github.com/jfirebaugh/Leaflet/blob/auto_new/src/core/Class.js">higher-level function</a>
to declare classes and their prototype properties:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="c1">// The `Class.extend` function defines a new constructor that uses</span>
</span><span class='line'><span class="c1">// the instanceof trick internally, and then calls `initialize`:</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">User</span> <span class="o">=</span> <span class="nx">Class</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
</span><span class='line'> <span class="nx">initialize</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">first</span><span class="p">,</span> <span class="nx">last</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">this</span><span class="p">.</span><span class="nx">first</span> <span class="o">=</span> <span class="nx">first</span><span class="p">;</span>
</span><span class='line'> <span class="k">this</span><span class="p">.</span><span class="nx">last</span> <span class="o">=</span> <span class="nx">last</span><span class="p">;</span>
</span><span class='line'> <span class="p">},</span>
</span><span class='line'>
</span><span class='line'> <span class="nx">fullName</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">first</span> <span class="o">+</span> <span class="s1">&#39; &#39;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">last</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="kd">var</span> <span class="nx">userViaNew</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">User</span><span class="p">(</span><span class="s2">&quot;John&quot;</span><span class="p">,</span> <span class="s2">&quot;Firebaugh&quot;</span><span class="p">);</span>
</span><span class='line'><span class="kd">var</span> <span class="nx">userDirect</span> <span class="o">=</span> <span class="nx">User</span><span class="p">(</span><span class="s2">&quot;John&quot;</span><span class="p">,</span> <span class="s2">&quot;Resig&quot;</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>
<p>APIs that use the instanceof trick internally often publicly document only the
newless form of instantiation. This minimizes the API surface area, gives new
users less to learn, and avoids the awkward aspects of <code>new</code>. Another
advantage is that it allows the implementation to choose either the <a href="http://macwright.org/2012/06/04/the-module-pattern.html">Module pattern</a> or classic
prototypal instantiation without changing the public API. For example, we can
rewrite the <code>User</code> class to use the Module pattern without changing how it&#8217;s
used:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="kd">function</span> <span class="nx">User</span><span class="p">(</span><span class="nx">first</span><span class="p">,</span> <span class="nx">last</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="kd">function</span> <span class="nx">fullName</span><span class="p">()</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="nx">first</span> <span class="o">+</span> <span class="s1">&#39; &#39;</span> <span class="o">+</span> <span class="nx">last</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="k">return</span> <span class="p">{</span>
</span><span class='line'> <span class="nx">first</span><span class="o">:</span> <span class="nx">first</span><span class="p">,</span>
</span><span class='line'> <span class="nx">last</span><span class="o">:</span> <span class="nx">last</span><span class="p">,</span>
</span><span class='line'> <span class="nx">fullName</span><span class="o">:</span> <span class="nx">fullName</span>
</span><span class='line'> <span class="p">};</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>Similarly, if we had started out with the Module pattern, but discovered that
we needed the <a href="http://macwright.org/2013/01/22/javascript-module-pattern-memory-and-closures.html">memory efficiency of prototypal instantation</a>,
we could switch without changing client code.</p>
<p>An alternative that some library use is to pair each constructor with a factory
function of the same name but with leading lower-case, e.g. <code>User</code> and <code>user</code>:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'> <span class="kd">function</span> <span class="nx">user</span><span class="p">(</span><span class="nx">first</span><span class="p">,</span> <span class="nx">last</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">return</span> <span class="k">new</span> <span class="nx">User</span><span class="p">(</span><span class="nx">first</span><span class="p">,</span> <span class="nx">last</span><span class="p">);</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'> <span class="kd">var</span> <span class="nx">userViaNew</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">User</span><span class="p">(</span><span class="s2">&quot;John&quot;</span><span class="p">,</span> <span class="s2">&quot;Firebaugh&quot;</span><span class="p">);</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">userViaFactory</span> <span class="o">=</span> <span class="nx">user</span><span class="p">(</span><span class="s2">&quot;John&quot;</span><span class="p">,</span> <span class="s2">&quot;Resig&quot;</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>
<p>This works, but again, it increases the size of the API you need to document
and users need to learn, and unlike the instanceof trick, there&#8217;s no way to
implement it in a reusable form. You&#8217;re stuck writing a factory wrapper for
every class.</p>
<p>A newless API works great for as jQuery and d3, and I&#8217;ve found it very useful
in <a href="http://ideditor.com/">iD</a> as well. Consider using it for your next
library.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[How to securely bootstrap JSON in a Rails view]]></title>
<link href="http://jfirebaugh.github.com/blog/2012/04/30/how-to-securely-bootstrap-json-in-a-rails-view/"/>
<updated>2012-04-30T10:13:00-04:00</updated>
<id>http://jfirebaugh.github.com/blog/2012/04/30/how-to-securely-bootstrap-json-in-a-rails-view</id>
<content type="html"><![CDATA[<p>A common pattern with client-side MVC applications is to embed the data for a
base set of models in the initial page instead of making a separate AJAX request to
load them. In a Rails application, this is typically done by interpolating the
result of a call to <code>to_json</code> in the view. The <a href="http://backbonejs.org/#FAQ-bootstrap">Backbone.js docs</a>
provide this example:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='erb'><span class='line'><span class="x">&lt;script&gt;</span>
</span><span class='line'><span class="x"> var Accounts = new Backbone.Collection;</span>
</span><span class='line'><span class="x"> Accounts.reset(</span><span class="cp">&lt;%=</span> <span class="vi">@accounts</span><span class="o">.</span><span class="n">to_json</span> <span class="cp">%&gt;</span><span class="x">);</span>
</span><span class='line'><span class="x"> var Projects = new Backbone.Collection;</span>
</span><span class='line'><span class="x"> Projects.reset(</span><span class="cp">&lt;%=</span> <span class="vi">@projects</span><span class="o">.</span><span class="n">to_json</span><span class="p">(</span><span class="ss">:collaborators</span> <span class="o">=&gt;</span> <span class="kp">true</span><span class="p">)</span> <span class="cp">%&gt;</span><span class="x">);</span>
</span><span class='line'><span class="x">&lt;/script&gt;</span>
</span></code></pre></td></tr></table></div></figure>
<p>If you try this in a Rails 3 application, you will discover that by default,
the interpolated results of <code>to_json</code> are HTML-escaped: <code>&amp;</code>, <code>&gt;</code>, <code>&lt;</code>, and <code>"</code>
are replaced with the equivalent HTML entities. Inside the script tag, this is
almost certainly not what you want. JSON strings containing <code>&amp;</code>, <code>&gt;</code>, and <code>&lt;</code>
should contain those characters literally, and the <code>"</code> character delimits the
JSON strings themselves. Escaping them prevents the desired result:
a literal JavaScript value embedded in the script.</p>
<p>The common reaction is to disable HTML escaping, either by prepending the call
to <code>to_json</code> with the <code>raw</code> helper, or calling <code>html_safe</code> on the result. Here&#8217;s
the same example using each of these techniques:</p>
<figure class='code'><figcaption><span>DO NOT FOLLOW THIS EXAMPLE</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='erb'><span class='line'><span class="x">&lt;script&gt;</span>
</span><span class='line'><span class="x"> var Accounts = new Backbone.Collection;</span>
</span><span class='line'><span class="x"> Accounts.reset(</span><span class="cp">&lt;%=</span> <span class="n">raw</span> <span class="vi">@accounts</span><span class="o">.</span><span class="n">to_json</span> <span class="cp">%&gt;</span><span class="x">);</span>
</span><span class='line'><span class="x"> var Projects = new Backbone.Collection;</span>
</span><span class='line'><span class="x"> Projects.reset(</span><span class="cp">&lt;%=</span> <span class="vi">@projects</span><span class="o">.</span><span class="n">to_json</span><span class="p">(</span><span class="ss">:collaborators</span> <span class="o">=&gt;</span> <span class="kp">true</span><span class="p">)</span><span class="o">.</span><span class="n">html_safe</span> <span class="cp">%&gt;</span><span class="x">);</span>
</span><span class='line'><span class="x">&lt;/script&gt;</span>
</span></code></pre></td></tr></table></div></figure>
<p><em>Do not follow this example!</em> Used in this way, both <code>raw</code> and <code>html_safe</code> open
vectors for a cross-site scripting vulnerability, and it is unfortunate that their
use is <a href="https://github.com/search?utf8=%E2%9C%93&amp;q=raw+to_json&amp;repo=&amp;langOverride=&amp;start_value=1&amp;type=Code&amp;language=HTML%2BERB">so</a>
<a href="https://github.com/search?utf8=%E2%9C%93&amp;q=to_json+html_safe&amp;repo=&amp;langOverride=&amp;start_value=1&amp;type=Code&amp;language=HTML%2BERB">widespread</a> and
commonly <a href="http://stackoverflow.com/a/3758055/52207">recommended</a>.</p>
<p>To understand the vulnerability, consider what happens if one of the strings
in the JSON contains the text <code>&lt;/script&gt;</code>. This text is interpolated
into the page, and since both <code>raw</code> and <code>html_safe</code> disable HTML-escaping, it
is interpolated literally. As a consequence, and despite the fact that it appears
within a JavaScript string literal, <code>&lt;/script&gt;</code> <a href="http://mathiasbynens.be/notes/etago">closes the script element</a>,
leaving an opportunity to embed an XSS payload in the subsequent text:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='html'><span class='line'><span class="nt">&lt;script&gt;</span>
</span><span class='line'> <span class="kd">var</span> <span class="nx">Accounts</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Backbone</span><span class="p">.</span><span class="nx">Collection</span><span class="p">;</span>
</span><span class='line'> <span class="nx">Accounts</span><span class="p">.</span><span class="nx">reset</span><span class="p">([{</span><span class="nx">name</span><span class="o">:</span> <span class="err">&quot;</span><span class="nt">&lt;/script&gt;&lt;script&gt;</span><span class="nx">alert</span><span class="p">(</span><span class="s1">&#39;xss&#39;</span><span class="p">)</span><span class="nt">&lt;/script&gt;</span>&quot;, ...}]);
</span><span class='line'> // ...
</span><span class='line'><span class="nt">&lt;/script&gt;</span>
</span></code></pre></td></tr></table></div></figure>
<p>The simplest way to escape JSON strings that may contain the <code>&lt;/</code> sequence
is to precede the slash with a backslash. Though simple to do, this should be built
in to Rails. Unfortunately, it is not. The obvious candidate would be <code>json_escape</code>,
aliased as <code>j</code>, which one would expect to be the JSON analog of the old Rails 2 <code>h</code> helper
for HTML escaping:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='erb'><span class='line'><span class="x">&lt;script&gt;</span>
</span><span class='line'><span class="x"> var Accounts = new Backbone.Collection;</span>
</span><span class='line'><span class="x"> Accounts.reset(</span><span class="cp">&lt;%=</span><span class="n">j</span> <span class="vi">@accounts</span><span class="o">.</span><span class="n">to_json</span> <span class="cp">%&gt;</span><span class="x">);</span>
</span><span class='line'><span class="x"> // ...</span>
</span><span class='line'><span class="x">&lt;/script&gt;</span>
</span></code></pre></td></tr></table></div></figure>
<p>However, in addition to escaping the JSON in a way that prevents XSS, <code>json_escape</code>
also <em>removes</em> double quote (<code>"</code>) characters. Yes, that&#8217;s right, <code>json_escape</code>
is <a href="http://api.rubyonrails.org/classes/ERB/Util.html#method-c-json_escape">documented</a>
to return invalid JSON. This baffling behavior is most likely a mistake in the
<a href="https://github.com/rails/rails/commit/0ff7a2d89fc95dcb0a32ed92aab7156b0778a7ea">original implementation</a>.
I&#8217;ve submitted a <a href="https://github.com/rails/rails/pull/6094">pull request</a> to change it, which will hopefully be accepted for Rails 4.</p>
<p>A second attempt might be to try <a href="http://api.rubyonrails.org/classes/ActionView/Helpers/JavaScriptHelper.html#method-i-escape_javascript"><code>escape_javascript</code></a>,
but this escapes much more than necessary. It could probably be made to work, but would
require parsing JSON on the client rather than simply interpolating a literal JavaScript
value.</p>
<p>Finally, there&#8217;s the option of setting <code>ActiveSupport::JSON::Encoding.escape_html_entities_in_json</code>
to true. This works, but since the default was <a href="https://github.com/rails/rails/commit/6042067c0b20602e72954450e9e8a19dfa8a9f7d">explicitly changed to false</a>
in Rails 3, it feels like a workaround at best. If you change the default globally, be sure
that any consumers of JSON APIs provided by your application are prepared to handle
Unicode escape sequences, because it will result in <code>&lt;/script&gt;</code> being escaped as
<code>\u003C/script\u003E</code> rather than <code>&lt;\/script&gt;</code>.</p>
<p>My recommendation is to overwrite <code>json_escape</code> with a sensible definition and use
that:</p>
<figure class='code'><figcaption><span>config/initializers/json_escape.rb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">ActionView</span><span class="o">::</span><span class="no">Base</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">json_escape</span><span class="p">(</span><span class="n">s</span><span class="p">)</span>
</span><span class='line'> <span class="n">result</span> <span class="o">=</span> <span class="n">s</span><span class="o">.</span><span class="n">to_s</span><span class="o">.</span><span class="n">gsub</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">,</span> <span class="s1">&#39;\/&#39;</span><span class="p">)</span>
</span><span class='line'> <span class="n">s</span><span class="o">.</span><span class="n">html_safe?</span> <span class="p">?</span> <span class="n">result</span><span class="o">.</span><span class="n">html_safe</span> <span class="p">:</span> <span class="n">result</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="k">alias</span> <span class="n">j</span> <span class="n">json_escape</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<figure class='code'><figcaption><span>view.html.erb</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='erb'><span class='line'><span class="x">&lt;script&gt;</span>
</span><span class='line'><span class="x"> var Accounts = new Backbone.Collection;</span>
</span><span class='line'><span class="x"> Accounts.reset(</span><span class="cp">&lt;%=</span><span class="n">j</span> <span class="vi">@accounts</span><span class="o">.</span><span class="n">to_json</span><span class="o">.</span><span class="n">html_safe</span> <span class="cp">%&gt;</span><span class="x">);</span>
</span><span class='line'><span class="x"> var Projects = new Backbone.Collection;</span>
</span><span class='line'><span class="x"> Projects.reset(</span><span class="cp">&lt;%=</span><span class="n">j</span> <span class="vi">@projects</span><span class="o">.</span><span class="n">to_json</span><span class="p">(</span><span class="ss">:collaborators</span> <span class="o">=&gt;</span> <span class="kp">true</span><span class="p">)</span><span class="o">.</span><span class="n">html_safe</span> <span class="cp">%&gt;</span><span class="x">);</span>
</span><span class='line'><span class="x">&lt;/script&gt;</span>
</span></code></pre></td></tr></table></div></figure>
<p>This is simple, sufficient to prevent XSS from bootstrapped JSON, and will hopefully
be the built-in behavior of <code>json_escape</code>/<code>j</code> in Rails 4.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Why Ember.js doesn't use property descriptors]]></title>
<link href="http://jfirebaugh.github.com/blog/2012/04/19/why-ember-dot-js-doesnt-use-property-descriptors/"/>
<updated>2012-04-19T08:11:00-04:00</updated>
<id>http://jfirebaugh.github.com/blog/2012/04/19/why-ember-dot-js-doesnt-use-property-descriptors</id>
<content type="html"><![CDATA[<p>Like model classes in many other JavaScript MVC frameworks, <code>Ember.Object</code> uses
<code>get()</code>/<code>set()</code>-based property accessor functions rather than native JavaScript
properties:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">MyApp</span><span class="p">.</span><span class="nx">president</span> <span class="o">=</span> <span class="nx">Ember</span><span class="p">.</span><span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">({</span>
</span><span class='line'> <span class="nx">name</span><span class="o">:</span> <span class="s2">&quot;Barack Obama&quot;</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="nx">MyApp</span><span class="p">.</span><span class="nx">president</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">);</span> <span class="c1">// Not `MyApp.president.name`</span>
</span></code></pre></td></tr></table></div></figure>
<p>Of course, Ember provides computed properties and property bindings, features
that plain JavaScript properties don&#8217;t support. Fortunately, ECMAScript 5 includes
<em><a href="http://ejohn.org/blog/ecmascript-5-objects-and-properties/">property descriptors</a></em>, and in particular, the
<a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/defineProperty"><code>Object.defineProperty()</code></a>
method. <code>Object.defineProperty</code> allows you to specify a function to serve as a
getter for the property (for example, to implement a computed property) and a
corresponding function to serve as a setter (which can be used to implement
properties that notify their observers when they change). So why doesn&#8217;t Ember
use property descriptors to provide more natural, less intrusive object properties?</p>
<p>Browser compatibility is only part of the answer. Browser support for property
descriptors is actually reasonably decent: present on Firefox, Chrome, Safari, and
Opera (naturally), and IE >= 9. For applications that can afford to drop IE 8 support,
particularly mobile apps, property descriptor-based model objects would work great.</p>
<p>The other part of the answer is that Ember provides a feature that goes beyond what
property descriptors can support: <em>unknown properties</em>. This is a feature akin to
Ruby&#8217;s <code>method_missing</code>, where you can define a handler that&#8217;s called upon access
to a property you haven&#8217;t explicitly defined:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='js'><span class='line'><span class="nx">MyApp</span><span class="p">.</span><span class="nx">president</span> <span class="o">=</span> <span class="nx">Ember</span><span class="p">.</span><span class="nb">Object</span><span class="p">.</span><span class="nx">create</span><span class="p">({</span>
</span><span class='line'> <span class="nx">unknownProperty</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">key</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'> <span class="k">if</span> <span class="p">(</span><span class="nx">key</span> <span class="o">===</span> <span class="s2">&quot;name&quot;</span><span class="p">)</span> <span class="k">return</span> <span class="s2">&quot;Barack Obama&quot;</span><span class="p">;</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="p">});</span>
</span><span class='line'>
</span><span class='line'><span class="nx">MyApp</span><span class="p">.</span><span class="nx">president</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">);</span> <span class="c1">//=&gt; &quot;Barack Obama&quot;</span>
</span></code></pre></td></tr></table></div></figure>
<p>Property descriptors do not allow you to define a function that&#8217;s called when a
previously undefined property is accessed or assigned. Accesses of undefined properties
simply produce <code>undefined</code>, and without a previously installed setter function the
object has no way of detecting assignment to a previously undefined property,
which it needs to be able to do in order to notify observers of the change. So
Ember needs something more than property descriptors in order to support
unknown properties.</p>
<p>Good news: that &#8220;something more&#8221; is on the horizon, in the form of
<a href="http://wiki.ecmascript.org/doku.php?id=harmony:direct_proxies">object proxies</a>, a
language feature slated for ECMAScript Harmony, the next release of the JavaScript
standard. Object proxies allow you to create a virtualized object that wraps a
given target object. The key feature for Ember is that <code>get</code> and <code>set</code> are part
of the proxy API, permitting the wrapper to intercept and handle all property
accesses and assignments, even for unknown properties.</p>
<p>Bad news: it will be awhile before support for object proxies is widespread. Currently,
support is limited to <a href="https://developer.mozilla.org/en/JavaScript/ECMAScript_6_support_in_Mozilla">Firefox</a>
and <a href="https://plus.google.com/113127438179392830442/posts/T615Md5JPQG">Chrome</a>
(after enabling &#8220;Experimental JavaScript&#8221; in <code>chrome://flags</code>),
both of which actually support an older, slightly different proxy specification.</p>
<p>Thanks to <a href="https://twitter.com/#!/tomdale">Tom Dale</a> for answering this question
for me. Any inaccuracies in the above are my own.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Code Archaeology with Git]]></title>
<link href="http://jfirebaugh.github.com/blog/2012/03/07/code-archaeology-with-git/"/>
<updated>2012-03-07T15:35:00-05:00</updated>
<id>http://jfirebaugh.github.com/blog/2012/03/07/code-archaeology-with-git</id>
<content type="html"><![CDATA[<p>Have you ever dug through the commit history of an open source project, peeling
away layers, sifting for clues, trying to answer the question, &#8220;why does this
code do what it does&#8221;? I call this process <em>code archaeology</em>.</p>
<p>Code archaeology is made difficult by historical debris: reformatting, refactoring,
code movement, and other incidental changes. This post takes a look at techniques
for separating the interesting commits from the uninteresting ones. We&#8217;ll look at
existing git tools, a tool provided by another SCM system that I wish had a git
equivalent, and a promising feature of git that has yet to arrive.</p>
<h2>Blame</h2>
<p><code>git blame</code> or github&#8217;s blame view is frequently the first step&#8212;but also the first
source of frustration:</p>
<div class='embed tweet'><blockquote class="twitter-tweet tw-align-center"><p>Is there a tool that tracks the history of a line in git (git blame almost always lands on a refactor commit for me)</p>&mdash; wycats (@wycats) <a href="https://twitter.com/wycats/status/153970008983216128" data-datetime="2012-01-02T22:44:45+00:00">January 2, 2012</a></blockquote>
<script src="http://jfirebaugh.github.com//platform.twitter.com/widgets.js" charset="utf-8"></script></div>
<p><code>git blame</code> has a few options that can help with this problem.</p>
<ul>
<li>With <code>-w</code>, blame ignores lines where only whitespace changed.</li>
<li>With <code>-M</code>, blame detects moved or copied lines within a file, and blames them on
the original commit instead of the commit that moved or copied them.</li>
<li>With <code>-C</code>, blame extends this move or copy detection to other files that were
modified in the same commit. You can specify this option two or three times to
make git look even harder (but more slowly) for moves and copies. See the
<a href="http://schacon.github.com/git/git-blame.html">manpage</a> for details.</li>
</ul>
<p>For example, I compared the blame for
<a href="https://github.com/rails/rails/blob/master/actionpack/lib/sprockets/railtie.rb">Rails&#8217;s sprockets railtie</a>
without any options and with <code>-wCCC</code>. The latter was able to tell that
<a href="https://github.com/rails/rails/commit/6960e481cb87964bd450ec3fbaa1087f44c3b860">this commit</a>
shouldn&#8217;t be blamed because it changed only whitespace, and it blamed the multiline
comment near the end of the file on the
<a href="https://github.com/rails/rails/commit/8f75c3abcde4f2ff64e855178027e1bd93976de9">commit where it was originally introduced</a>,
rather than a <a href="https://github.com/rails/rails/commit/8248052ee74465abfae5b202270e96c9fd93e785">later commit which moved it</a>.</p>
<p>If any githubbers are reading this: how about supporting some power-user query
parameters on blame pages? I suggest <code>w=1</code> for ignoring whitespace (a parameter
which is already supported on diff pages); <code>M=1</code>, <code>C=1</code>, <code>C=2</code>, and <code>C=3</code> for various
levels of move and copy detection.</p>
<h2>Pickaxe</h2>
<p>If you read the <code>git blame</code> manpage, you might have noticed a somewhat cryptic
reference to the &#8220;pickaxe&#8221; interface. Pickaxes are often useful for archaeological
purposes, and git&#8217;s pickaxe is no exception. It refers to the <code>-S</code> option to
<code>git log</code>. The <code>-S</code> option takes a string parameter and searches the commit history for
commits that introduce or remove that string. That&#8217;s not quite the same thing as
searching for commits whose diff contains the string&#8212;the change must
actually add or delete that string, not simply include a line on which it appears.</p>
<p>For example, I was looking at the same Sprockets railtie I looked at with <code>blame</code>
and trying to figure out why <code>Rails.env</code> was included in Sprocket&#8217;s environment
version on <a href="https://github.com/rails/rails/blob/6960e481cb87964bd450ec3fbaa1087f44c3b860/actionpack/lib/sprockets/railtie.rb#L24">line 24</a>.
Blame landed on an <a href="https://github.com/rails/rails/commit/63d3809e31cc9c0ed3b2e30617310407ae614fd4">uninteresting commit</a>:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ git blame -L23,25 actionpack/lib/sprockets/railtie.rb
</span><span class='line'>8248052e (Joshua Peek 2011-07-27 15:09:42 -0500 23) app.assets = Sprockets::Environment.new(app.root.to_s) do |env|
</span><span class='line'>63d3809e (Joshua Peek 2011-08-21 16:42:06 -0500 24) env.version = ::Rails.env + "-#{config.assets.version}"
</span><span class='line'>8248052e (Joshua Peek 2011-07-27 15:09:42 -0500 25)
</span><span class='line'>$ git log -1 63d3809e
</span><span class='line'>commit 63d3809e31cc9c0ed3b2e30617310407ae614fd4
</span><span class='line'>Author: Joshua Peek &lt;josh@joshpeek.com&gt;
</span><span class='line'>Date: Sun Aug 21 16:42:06 2011 -0500
</span><span class='line'>
</span><span class='line'> Fix sprockets warnings
</span><span class='line'>
</span><span class='line'> Fixes #2598</span></code></pre></td></tr></table></div></figure>
<p>But the pickaxe found the answer right away:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ git log -S'Rails.env' actionpack/lib/sprockets/railtie.rb
</span><span class='line'>commit ed5c6d254c9ef5d44a11159561fddde7a3033874
</span><span class='line'>Author: Ilya Grigorik &lt;ilya@igvita.com&gt;
</span><span class='line'>Date: Thu Aug 4 23:48:40 2011 -0400
</span><span class='line'>
</span><span class='line'> generate environment dependent asset digests
</span><span class='line'>
</span><span class='line'> If two different environments are configured to use the pipeline, but
</span><span class='line'> one has an extra step (such as compression) then without taking the
</span><span class='line'> environment into account you may end up serving wrong assets</span></code></pre></td></tr></table></div></figure>
<h2><code>git gui blame</code></h2>
<p><a href="http://schacon.github.com/git/git-gui.html"><code>git gui blame</code></a> might be the most
useful and least known features of the Tcl/Tk-based GUI included with git.
You give it the name of a file and it opens an interactive blame viewer with built-in
move and copy detection and an easy way to reblame from a parent commit. Check it out:</p>
<p><img src="http://jfirebaugh.github.com/images/git-gui-blame.png" alt="Screenshot of git gui blame" /></p>
<p>The first column on the left shows the blame <em>with</em> move and rename detection, and the second
shows who moved the line to its current location. In the lines selected in
green, we see evidence of the movement of the same comment that
we looked at with command-line blame: in the first column, José Valim (JV)
originated it in <code>8f75</code>, and Josh Peek (JP) later moved it in <code>8428</code>.</p>
<p>The killer feature of <code>git gui blame</code> is found in the context menu: &#8220;Blame Parent
Commit&#8221;. When blame lands on an uninteresting commit, you can use this command to
skip over it and reblame from the immediately prior commit. This is so useful that
gui blame has become my go-to tool for code archeology.</p>
<h2>Perforce Time-lapse View</h2>
<p>I would never choose to use Perforce over git, but I do miss one feature that it
provides: the <a href="http://filehost.perforce.com/downloads/media/tlv/tlv.html">time-lapse view</a>.</p>
<div class="flash-video">
<div>
<object type="application/x-shockwave-flash" name="swftools-4f57b6e32a8d5" data="http://www.perforce.com/sites/all/libraries/flowplayer3/flowplayer-3.2.2.swf" width="670" height="528" id="swftools-4f57b6e32a8d5">
<param name="version" value="9">
<param name="play" value="true">
<param name="loop" value="true">
<param name="menu" value="false">
<param name="allowfullscreen" value="true">
<param name="swliveconnect" value="false">
<param name="quality" value="autohigh">
<param name="scale" value="noborder">
<param name="wmode" value="transparent">
<param name="align" value="l">
<param name="salign" value="tl">
<param name="allowscriptaccess" value="sameDomain">
<param name="base" value="/sites/default/files/">
<param name="flashvars" value="config=%7B%20%27playerId%27%3A%20%27swftools-4f57b6e32a8d5%27%2C%20%27playlist%27%3A%20%5B%20%27http%3A%2F%2Ffilehost.perforce.com%2Fdownloads%2Fmedia%2Ftlv%2Ftlv.flv%27%20%5D%2C%20%27canvas%27%3A%20%7B%20%27height%27%3A%20%27528%27%2C%20%27width%27%3A%20%27670%27%2C%20%27backgroundRepeat%27%3A%20%27repeat%27%2C%20%27backgroundGradient%27%3A%20%27low%27%2C%20%27backgroundColor%27%3A%20%27%23000000%27%20%7D%2C%20%27clip%27%3A%20%7B%20%27autoPlay%27%3A%20false%2C%20%27autoBuffering%27%3A%20true%2C%20%27scaling%27%3A%20%27fit%27%2C%20%27accelerated%27%3A%20false%2C%20%27linkWindow%27%3A%20%27_blank%27%2C%20%27live%27%3A%20false%20%7D%2C%20%27play%27%3A%20%7B%20%27opacity%27%3A%20%270.8%27%2C%20%27fadeSpeed%27%3A%20%27500%27%2C%20%27rotateSpeed%27%3A%20%2750%27%2C%20%27height%27%3A%20%2710%25%27%2C%20%27width%27%3A%20%2710%25%27%2C%20%27replayLabel%27%3A%20%27Play%20again%27%20%7D%2C%20%27plugins%27%3A%20%7B%20%27controls%27%3A%20%7B%20%27backgroundGradient%27%3A%20%27medium%27%2C%20%27progressGradient%27%3A%20%27medium%27%2C%20%27bufferGradient%27%3A%20%27none%27%2C%20%27sliderGradient%27%3A%20%27none%27%2C%20%27volumeSliderGradient%27%3A%20%27none%27%2C%20%27autoHide%27%3A%20%27fullscreen%27%2C%20%27play%27%3A%20true%2C%20%27volume%27%3A%20true%2C%20%27mute%27%3A%20true%2C%20%27time%27%3A%20true%2C%20%27stop%27%3A%20false%2C%20%27playlist%27%3A%20false%2C%20%27fullscreen%27%3A%20true%2C%20%27scrubber%27%3A%20true%2C%20%27borderRadius%27%3A%20%270%27%2C%20%27scrubberHeightRatio%27%3A%20%270.4%27%2C%20%27scrubberBarHeightRatio%27%3A%20%271%27%2C%20%27volumeSliderHeightRatio%27%3A%20%270.4%27%2C%20%27volumeBarHeightRatio%27%3A%20%271%27%2C%20%27timeBgHeightRatio%27%3A%20%270.7%27%2C%20%27hideDelay%27%3A%20%274000%27%2C%20%27backgroundColor%27%3A%20%27%23000000%27%2C%20%27timeColor%27%3A%20%27%2301daff%27%2C%20%27durationColor%27%3A%20%27%23ffffff%27%2C%20%27progressColor%27%3A%20%27%23015b7a%27%2C%20%27bufferColor%27%3A%20%27%236c9cbc%27%2C%20%27sliderColor%27%3A%20%27%23000000%27%2C%20%27buttonColor%27%3A%20%27%23889aa4%27%2C%20%27buttonOverColor%27%3A%20%27%2392b2bd%27%2C%20%27volumeSliderColor%27%3A%20%27%23000000%27%2C%20%27timeBgColor%27%3A%20%27%23000000%27%20%7D%20%7D%20%7D">
</object>
</div>
</div>
<p>The time-lapse view is great for quickly scrubbing through the history of a file,
but it&#8217;s difficult to keep a particular line of interest in view as you scrub.
And because it showed only a linear history, it suffers from Perforce&#8217;s branching model;
I would frequently land on a huge &#8220;integration changelist&#8221; (Perforce&#8217;s equivalent
of a merge commit) and need to go look at the time-lapse on a different branch.</p>
<p>Still, I was often able to unearth interesting commits more quickly than I can with
<code>git blame</code>, and I still hope somebody creates a similar tool for git.</p>
<h2>Git Line-level History Browser</h2>
<p>The 2010 Google Summer of Code included a project for git called the
<a href="https://git.wiki.kernel.org/articles/s/o/c/SoC2010Projects_041c.html#Line_level_history_browser">Line-level History Browser</a>,
a set of feature additions for the <code>git log</code> command to make it easy to track the
history of a line (or set of lines), even through file renames and code movement.</p>
<p>Thomas Rast, co-mentor for the project, <a href="http://article.gmane.org/gmane.comp.version-control.git/154190">explains</a>
the purpose of the feature:</p>
<blockquote><p>For me it replaces a manual iterative process to find out in what ways
a function was patched until it came to have its current shape:</p>
<pre><code>git-blame the area, find the most recent commit C
while 1:
git show C
if that explains the code: break
git-blame the area in C^
find the most recent commit and call it C again
</code></pre>
<p>I do this a lot when a particular section of code puzzles me or seems
buggy, to see if any commit message provides a reason for it. I think
(but I never got good with it) the &#8220;blame parent&#8221; feature of <code>git gui
blame</code> covers a similar use-case.</p>
<p>All of this can now be replaced by a simple <code>git log -L &lt;range&gt; &lt;filename&gt;</code></p></blockquote>
<p>And Bo Yang, the mentee, <a href="http://article.gmane.org/gmane.comp.version-control.git/154040">lists details</a>:</p>
<blockquote><p>Generally, the goal of this project is to:</p>
<ol>
<li><code>git log -L</code> to trace multiple ranges from multiple files;</li>
<li>move/copy detect when we reach the end of some lines(where lines
are added from scratch).</li>
</ol>
<p>And now, we have supports in detail:</p>
<ol>
<li><code>git log -L</code> can trace multiple ranges from multiple files;</li>
<li>we support the same syntax with <code>git blame</code> <code>-L</code> options;</li>
<li>we integrate the <code>git log -L</code> with <code>--graph</code> options with
parent-rewriting to make the history looks better and clear;</li>
<li>move/copy detect is in its half way. We get a nearly workable
version of it, and now it is in a phrase of refactor, so in the scope
of GSoC, move/copy detect only partly complete.</li>
</ol>
</blockquote>
<p>Eventually, the feature was to support &#8220;fuzzy&#8221; matching of moves and copies, so
that the history could be traced across even more &#8220;refactoring&#8221;-type commits.
Sounds fantastic, right? Why am I not using this every day? Unfortunately, Bo&#8217;s work
didn&#8217;t get merged to git master. It&#8217;s not completely defunct; Thomas Rast maintains
<a href="https://github.com/trast/git/tree/line-log-WIP">a WIP version</a> which has seen some
recent activity, so I&#8217;m cautiously optimistic this feature may yet be released.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Xcode 4.3, homebrew, and Ruby]]></title>
<link href="http://jfirebaugh.github.com/blog/2012/03/02/xcode-4-dot-3-homebrew-and-ruby/"/>
<updated>2012-03-02T00:00:00-05:00</updated>
<id>http://jfirebaugh.github.com/blog/2012/03/02/xcode-4-dot-3-homebrew-and-ruby</id>
<content type="html"><![CDATA[<p>Ruby on Mac OS Lion is going through a bit of a rough patch,
installation-wise. With Xcode 4.2, clang became the default compiler and gcc
was no longer included. Unfortunately, this has caused a lot of grief for
Rubyists on OS X, because for a while, MRI did not officially support
compiling with clang. With the release of 1.9.3-p125,
that situation has changed&#8211;clang is now officially supported&#8211;but
there are still some gotchas. This post details my toolchain and process for
running MRI 1.9.3 and 1.8.7 on Lion with Xcode 4.3.</p>
<p>If you want a TL;DR: install the Xcode 4.3 command line tools. Then,</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ brew update
</span><span class='line'>$ brew install autoconf automake
</span><span class='line'>$ brew install https://raw.github.com/Homebrew/homebrew-dupes/master/apple-gcc42.rb
</span><span class='line'>$ rvm get head
</span><span class='line'>$ rvm install 1.8.7
</span><span class='line'>$ rvm install 1.9.3-head</span></code></pre></td></tr></table></div></figure>
<p>Read on for a detailed rationale.</p>
<h2>Xcode</h2>
<p>I use Xcode 4.3 and have installed the Xcode command line tools. I&#8217;ve
uninstalled all previous versions of Xcode. If you don&#8217;t use Xcode itself,
save yourself a multi-gigabyte download and install just the command line
tools, which are now available
<a href="http://developer.apple.com/downloads">separately</a>. Thanks to Kenneth Reitz for
<a href="http://kennethreitz.com/xcode-gcc-and-homebrew.html">his work making this happen</a>.</p>
<h2>Homebrew</h2>
<p>Homebrew now has good support for Xcode 4.3. Just make sure to <code>brew update</code>.</p>
<p>In order to build MRI, you&#8217;ll need to install some specific formulas. First
of all, autoconf and automake:</p>
<pre><code>$ brew install autoconf automake
</code></pre>
<p>You need these because Xcode 4.3 no longer includes autotools; if you have
installed Xcode 4.3 and uninstalled the previous versions,
you will no longer have <code>/usr/bin/autoconf</code>. You don&#8217;t usually need the
autotools for installing homebrew formulas, since the downloaded packages
should come with <code>configure</code> pregenerated, but you do need them in order to
install head versions of MRI as described below.</p>
<p>Second, install gcc&#8211;the real version&#8211;from homebrew-dupes:</p>
<pre><code>$ brew install https://raw.github.com/Homebrew/homebrew-dupes/master/apple-gcc42.rb
</code></pre>
<p>The command line tools provide <code>/usr/bin/gcc</code>, but it&#8217;s a modified version
based on LLVM and if you try to use it to compile 1.8.7,
you&#8217;ll get the following crash when trying to install gems:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>$ gem install bundler
</span><span class='line'>/Users/john/.rvm/rubies/ruby-1.8.7-p358/lib/ruby/1.8/timeout.rb:60: [BUG] Segmentation fault
</span><span class='line'>ruby 1.8.7 (2012-02-08 patchlevel 358) [i686-darwin11.3.0]</span></code></pre></td></tr></table></div></figure>
<p>Kenneth Reitz&#8217;s
<a href="https://github.com/kennethreitz/osx-gcc-installer">osx-gcc-installer</a> is another
popular way of getting GCC,
but you don&#8217;t want to install it on top of the Xcode 4.3 command line tools,
because it will overwrite working versions of llvm-gcc and clang.
Homebrew-alt&#8217;s apple-gcc42 formula gives you <em>just</em> Apple&#8217;s GCC 4.2,
installed at <code>/usr/local/bin/gcc-4.2</code>.</p>
<h2>RVM</h2>
<p>Install RVM and run <code>rvm get head</code>. The latest RVM
<a href="https://github.com/wayneeseguin/rvm/issues/763">has the smarts</a> to use the
correct compilers to build both 1.9.3 and 1.8.7 &#8211; clang for 1.9.3 and gcc-4.2
for 1.8.7. I tend to install both so I can test my gems on both versions.</p>
<pre><code>rvm install 1.9.3
rvm install 1.8.7
</code></pre>
<p>You shouldn&#8217;t see any errors or warnings from these commands,
and you shouldn&#8217;t need to specify <code>--with-gcc=clang</code> or <code>--with-gcc=gcc-4.2</code>.
If you see something like <code>Building 'ruby-1.8.7-p358' using clang - but it's
not (fully) supported, expect errors</code>, you&#8217;ve done something wrong. Go back
and make sure your command line tools are correctly installed and you&#8217;ve
installed the apple-gcc42 homebrew-alt formula.</p>
<p>You should now have working copies of 1.9.3 and 1.8.7. Hooray!</p>
<p>Still, you might run into one more problem. If you try to debug on 1.9.3,
you&#8217;ll get this error:</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>/Users/john/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:
</span><span class='line'> in `require': dlopen(/Users/john/.rvm/gems/ruby-1.9.3-p125/gems/ruby-debug-base19-0.11.25/lib/ruby_debug.bundle, 9):
</span><span class='line'> Symbol not found: _ruby_current_thread (LoadError)
</span><span class='line'> Referenced from: /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/ruby-debug-base19-0.11.25/lib/ruby_debug.bundle
</span><span class='line'> Expected in: flat namespace
</span><span class='line'> in /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/ruby-debug-base19-0.11.25/lib/ruby_debug.bundle - /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/ruby-debug-base19-0.11.25/lib/ruby_debug.bundle
</span><span class='line'> from /Users/john/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
</span><span class='line'> from /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/ruby-debug-base19-0.11.25/lib/ruby-debug-base.rb:1:in `&lt;top (required)&gt;'
</span><span class='line'> from /Users/john/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
</span><span class='line'> from /Users/john/.rvm/rubies/ruby-1.9.3-p125/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
</span><span class='line'> from /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/ruby-debug19-0.11.6/cli/ruby-debug.rb:5:in `&lt;top (required)&gt;'
</span><span class='line'> from /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/ruby-debug19-0.11.6/bin/rdebug:108:in `require_relative'
</span><span class='line'> from /Users/john/.rvm/gems/ruby-1.9.3-p125/gems/ruby-debug19-0.11.6/bin/rdebug:108:in `&lt;top (required)&gt;'
</span><span class='line'> from /Users/john/.rvm/gems/ruby-1.9.3-p125/bin/rdebug:19:in `load'
</span><span class='line'> from /Users/john/.rvm/gems/ruby-1.9.3-p125/bin/rdebug:19:in `&lt;main&gt;'</span></code></pre></td></tr></table></div></figure>
<p>This is caused by a <a href="https://bugs.ruby-lang.org/issues/6080">clang incompatibility</a>
that didn&#8217;t get fixed until after the 1.9.3-p125 release. Use the head
version of 1.9.3 instead: <code>rvm install 1.9.3-head</code>.</p>
<p>Phew! Now you&#8217;re really bleeding edge.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Visualizing SFpark Demand-Responsive Meter Rate Adjustments]]></title>
<link href="http://jfirebaugh.github.com/blog/2011/09/03/visualizing-sfpark-demand-responsive-meter-rate-adjustments/"/>
<updated>2011-09-03T00:00:00-04:00</updated>
<id>http://jfirebaugh.github.com/blog/2011/09/03/visualizing-sfpark-demand-responsive-meter-rate-adjustments</id>
<content type="html"><![CDATA[<p>On July 11th 2011, <a href="http://sfpark.org/">SF<em>park</em></a> announced the
first set of <a href="http://sfpark.org/how-it-works/pricing/">meter rate adjustments</a>.
Meter operational hours were divided into six distinct rate periods, and the hourly
price of metered parking in the project&#8217;s seven pilot areas was adjusted on a
block-to-block basis in response to parking demand during each period:</p>
<ul>
<li>+25¢ in periods of 80% or more occupancy</li>
<li>No change in periods of 60-80% occupancy</li>
<li>−25¢ in periods of 30-60% occupancy</li>
<li>−50¢ in periods of less than 40% occupancy</li>
</ul>
<p>I created this visualization using the <a href="http://mbostock.github.com/d3/">d3.js</a>
framework and data provided by SF<em>park</em>. Click for full size.</p>
<p><a href="http://jfirebaugh.github.com/sfpark/rates.html"><img src="http://jfirebaugh.github.com/sfpark/SFpark.png" alt="SFpark meter
rate adjustment visualization" /></a></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Kernel Density Estimation with Protovis]]></title>
<link href="http://jfirebaugh.github.com/blog/2011/04/03/kernel-density-estimation-with-protovis/"/>
<updated>2011-04-03T00:00:00-04:00</updated>
<id>http://jfirebaugh.github.com/blog/2011/04/03/kernel-density-estimation-with-protovis</id>
<content type="html"><![CDATA[<p><a href="http://bl.ocks.org/900762"><img src="http://dl.dropbox.com/u/7078234/KDE.png" alt="" /></a></p>
<p>A <a href="http://en.wikipedia.org/wiki/Kernel_density_estimation">kernel density estimate</a> provides a
means of estimating and visualizing the probability distribution function of a
random variable based on a random sample. In contrast to a histogram, a kernel
density estimate provides a smooth estimate, via the effect of a smoothing
parameter called the <em>bandwidth</em>, here denoted by <em>h</em>. With the correct choice
of bandwidth, important features of the distribution can be seen; an incorrect
choice will result in undersmoothing or oversmoothing and obscure those
features.</p>
<p>Here we see a histogram and three kernel density estimates for a sample of
waiting times in minutes between eruptions of
<a href="http://en.wikipedia.org/wiki/Old_Faithful">Old Faithful Geyser</a> in Yellowstone National
Park, taken from R&#8217;s
<a href="http://stat.ethz.ch/R-manual/R-patched/library/datasets/html/faithful.html"><code>faithful</code></a>
dataset. The data follow a <a href="http://en.wikipedia%0A.org/wiki/Bimodal_distribution">bimodal distribution</a>; short
eruptions are followed by a wait time averaging about 55 minutes, and long
eruptions by a wait time averaging about 80 minutes. In recent years, wait
times have been increasing, possibly due to the effects of earthquakes on the
geyser&#8217;s geohydrology.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Making sense of constant lookup in Ruby]]></title>
<link href="http://jfirebaugh.github.com/blog/2011/01/21/making-sense-of-constant-lookup-in-ruby/"/>
<updated>2011-01-21T00:00:00-05:00</updated>
<id>http://jfirebaugh.github.com/blog/2011/01/21/making-sense-of-constant-lookup-in-ruby</id>
<content type="html"><![CDATA[<p>In Ruby 1.8, constant lookup is mostly <a
href="http://en.wikipedia.org/wiki/Scope_(programming)#Lexical_versus_dynamic_scoping">lexically scoped</a>,
even when using <tt>class_eval</tt> or <tt>instance_eval</tt>.
That is, constant lookup always searches the chain of <em>lexically
enclosing</em> classes or modules. The first lexically enclosing class or
module is not necessarily the same as <tt>self.class</tt>:</p>
<div><script src='https://gist.github.com/790454.js?file=constants.rb'></script>
<noscript><pre><code>puts &quot;#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}&quot;
X = '::X'
class Foo
X = 'Foo::X'
def foo
puts &quot;instance method: #{X}&quot;
end
end
Foo.new.foo
f = Foo.new
def f.bar
puts &quot;singleton method: #{X}&quot;
end
f.bar
Foo.class_eval do
puts &quot;class_eval: #{X}&quot;
end
Foo.new.instance_eval do
puts &quot;instance_eval: #{X}&quot;
end
</code></pre></noscript></div>
<p>Here&#8217;s the output on 1.8.7:</p>
<div><script src='https://gist.github.com/790510.js?file='></script>
<noscript><pre><code>1.8.7-p330
instance method: Foo::X
singleton method: ::X
class_eval: ::X
instance_eval: ::X</code></pre></noscript></div>
<p>Here we can see that within the lexical block defining <tt>Foo#foo</tt>, which
is enclosed by <tt>class Foo</tt>, <tt>X</tt> refers to <tt>Foo::X</tt>, while
in the lexical blocks used for the singleton method, <tt>class_eval</tt>, and
<tt>instance_eval</tt>, which are not in <tt>class Foo</tt>&#8217;s scope,
<tt>X</tt> refers to <tt>::X</tt>, the global constant.</p>
<p>However, in 1.9, the situation changes, and moreover, the behavior is
different between 1.9.1 and 1.9.2. Here&#8217;s the result of running <tt><a
href="http://rvm.beginrescueend.com/set/ruby/">rvm 1.9.1,1.9.2
constants.rb</a></tt>:</p>
<div><script src='https://gist.github.com/790511.js?file='></script>
<noscript><pre><code>1.9.1-p378
instance method: Foo::X
singleton method: ::X
class_eval: Foo::X
instance_eval: Foo::X
1.9.2-p136
instance method: Foo::X
singleton method: Foo::X
class_eval: ::X
instance_eval: Foo::X</code></pre></noscript></div>
<p>So, in 1.9.1, constant lookup in <tt>class_eval</tt> and
<tt>instance_eval</tt> proceeds from the receiver, rather than the lexically
enclosing scope. Particularly for <tt>class_eval</tt>, this turned out to be a
<a href="http://www.ruby-forum.com/topic/191672">problematic</a> <a
href="http://www.ruby-forum.com/topic/199317">change</a>, breaking existing
libraries that depended on the 1.8.7 behavior and making it hard to build DSLs
that behaved in predictable ways. Eventually, it was decided to <a
href="http://www.ruby-forum.com/topic/199317#871425">revert to the 1.8
behavior</a>, and this was supposedly implemented:</p>
<blockquote><pre>
&gt; [Matz] would like to revert all of instance_eval, instance_exec,
&gt; class_eval, and class_exec to the behavior of 1.8 (including class
&gt; variables). [...]
I have just commited it to the SVN trunk.
</pre></blockquote>
<p>I say &#8220;supposedly&#8221; only because as you can see, the 1.9.2 behavior still
differs from 1.8.7 in the case of <tt>instance_eval</tt>. Was this an
oversight, or was the revert later unreverted for&nbsp;<span
style="font-family: monospace;">instance_eval</span>? If so, what was the
rationale? I searched the mailing list and subsequent commits, but couldn&#8217;t
find an explanation. If anyone can shed light on the matter, I would
appreciate it.</p>
<p>As you can see, 1.9.2 also changed the behavior for singleton methods: the
receiver&#8217;s scope is now searched before the lexically enclosing scope. This
change makes sense to me, and I haven&#8217;t heard of it causing any problems.</p>
<p>Note that these rules apply to constant <em>definition</em>&nbsp;as well as
lookup. In 1.8 and 1.9.2, a constant defined in a class_evaluated block will
be defined in the enclosing lexical scope, rather than the scope of the
receiver. This is one of the things that makes <tt>Foo = Class.new { &#8230;
}</tt> not <em>quite</em> the same as <tt>class Foo; &#8230;; end</tt>:</p>
<div><script src='https://gist.github.com/790492.js?file='></script>
<noscript><pre><code>puts &quot;#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL}&quot;
class Foo
class Bar
end
end
Baz = Class.new do
class Quux
end
end
puts Foo::Bar
puts Quux
</code></pre></noscript></div>
<p>The block passed to <tt>Class.new</tt> is effectively
<tt>class_eval</tt>uated, so in this example, the constant <tt>Quux</tt> ends
up defined at the top level. (And once again 1.9.1 is the exception: it
defines <tt>Baz::Quux</tt> instead.) This behavior can cause problems if you
are in the habit of defining test classes in RSpec <tt>describe</tt> blocks:</p>
<div><script src='https://gist.github.com/790496.js?file='></script>
<noscript><pre><code>require 'rspec'
describe &quot;a TestClass&quot; do
class TestClass &lt; String
end
end
describe &quot;other TestClass&quot; do
class TestClass &lt; Integer
end
end
</code></pre></noscript></div>
<p>Here <tt>TestClass</tt> winds up in the global scope, not the scope of the
RSpec example group that <tt>describe</tt> creates. If you have multiple specs
that define test classes with the same name, you may get collisions unless you
place each <tt>describe</tt> within a uniquely-named module or diligently
remove the constants in an <tt>after</tt> block. In the above example, you&#8217;ll
get the error &#8220;superclass mismatch for class TestClass&#8221;.</p>
<p>If you need to ensure a particular scoping is used (for example, if you need
to support 1.9.1 as well as 1.8.7/1.9.2), you can always be explicit about it
by prefixing constants with <tt>::</tt> (for global lookup), <tt>self::</tt>
(for receiver scope), or the fully qualified desired scope:</p>
<div><script src='https://gist.github.com/790500.js?file='></script>
<noscript><pre><code>require 'rspec'
describe &quot;a TestClass&quot; do
class self::TestClass &lt; String
end
end
describe &quot;other TestClass&quot; do
class ::TestClass &lt; Integer
end
end
module A
module B
end
end
describe &quot;third TestClass&quot; do
class A::B::TestClass &lt; Integer
end
end
</code></pre></noscript></div>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Selenium on Ruby]]></title>
<link href="http://jfirebaugh.github.com/blog/2010/12/22/selenium-on-ruby/"/>
<updated>2010-12-22T00:00:00-05:00</updated>
<id>http://jfirebaugh.github.com/blog/2010/12/22/selenium-on-ruby</id>
<content type="html"><![CDATA[<p>The state of Selenium on Ruby is a bit confusing. Among the top google results for
<a href="http://www.google.com/search?q=selenium+ruby">&#8220;selenium ruby&#8221;</a> are several links that are badly out of date, and it&#8217;s
not clear which of the many <a href="http://rubygems.org/search?utf8=%E2%9C%93&amp;amp;query=selenium">gems</a> are ones you would want
to use. This post aims to clear up some of the confusion.</p>
<p>First of all, you should be aware that there are two Selenium APIs: the original 1.0 API, called Selenium-RC, and a
newer 2.0 API called Selenium WebDriver. Internally, the two have quite different architectures. In a nutshell,
Selenium-RC is based around a Java &#8220;Remote Control&#8221; server process that launches the browser under test and manages
communication between the client process (the Ruby interpreter, in our case) and the browser. The browser is controlled
by injecting the &#8220;Selenium Core&#8221; JavaScript framework into the Browser&#8217;s built-in JavaScript interpreter. In contrast,
WebDriver requires no external process; the browser is launched directly, and controlled via means that vary from
browser to browser. For example, WebDriver controls Firefox via a custom Firefox extension.</p>
<p>Ruby has good support for both RC and WebDriver. The <a href="http://rubygems.org/gems/selenium-client">selenium-client</a> gem
(<a href="http://selenium-client.rubyforge.org/">docs</a>, <a href="https://github.com/ph7/selenium-client">source</a>) provides bindings for
the RC API, and the <a href="http://rubygems.org/gems/selenium-webdriver">selenium-webdriver</a> gem
(<a href="http://code.google.com/p/selenium/wiki/RubyBindings">wiki</a>,
<a href="http://selenium.googlecode.com/svn/trunk/docs/api/rb/index.html">docs</a>,
<a href="http://code.google.com/p/selenium/source/browse/#svn%2Ftrunk%2Frb">source</a>) provides bindings for the WebDriver API.
You will likely want to use one of these two gems, but which one? If you are using Selenium via a higher-level Ruby
library such as Webrat or Capybara, the choice will be made for you: Webrat uses selenium-client, Capybara uses
selenium-webdriver. If you want to access a Selenium API directly, I would generally recommend selenium-webdriver.
The WebDriver API provides several advantages, including multi-browser testing, page navigation, drag-and-drop, and
multi-frame and multi-window support. It recently released its
<a href="http://groups.google.com/group/selenium-users/browse_thread/thread/28ce2b37123a4e4d">first beta</a> and is where the
future of Selenium and Selenium on Ruby lies. It is, however, still beta software and sometimes changes its API in
aggravating ways. If stability is of paramount concern, stick with selenium-client.</p>
<p>You may find references to some other Selenium-related Ruby projects. The <a href="http://rubygems.org/gems/Selenium">Selenium</a>
gem (with a capital &#8220;S&#8221;) and its associated website <a href="http://selenium.rubyforge.org/">selenium.rubyforge.org</a> paved the
way for Selenium on Ruby, but today it is obsolete, as is the <a href="http://rubygems.org/gems/selenium-rails">selenium-rails</a>
gem which depends on it. Unfortunately they are still prominently featured in search results and on the
<a href="http://seleniumhq.org/projects/ruby/">outdated &#8220;Selenium on Ruby&#8221; page</a>, which doesn&#8217;t even mention selenium-webdriver.</p>
<p>The Selenium RC API relies on an external Java-based server process, and though the selenium-client gem provides rake
tasks to start and stop an RC server, it does not provide the actual jar file necessary to run the service. You can
either download and install it yourself, or install the <a href="http://rubygems.org/gems/selenium-rc">selenium-rc</a> gem, which
bundles it. You&#8217;ll sometimes see a gem that depends on selenium-client also depending on selenium-rc solely for the jar,
as the <a href="https://github.com/pivotal/jasmine-gem">jasmine</a> gem does. The selenium-rc gem has some Ruby code in it too, but
it more or less duplicates functionality that&#8217;s already part of selenium-client.</p>
<p>Finally there&#8217;s the <a href="http://rubygems.org/gems/selenium">selenium</a> and
<a href="http://rubygems.org/gems/selenium_remote_control">selenium_remote_control</a> gems, which provide functionality similar
to selenium-client and selenium-rc. They don&#8217;t seem widely used and at first glance I don&#8217;t see any reason to prefer
them to the more popular gems. Recent releases of the selenium-webdriver gem include the selenium-client code as well,
and personally, I hope that selenium-webdriver can usurp the &#8220;selenium&#8221; gem name and become the One True Selenium gem
for Ruby.</p>
]]></content>
</entry>
</feed>
Jump to Line
Something went wrong with that request. Please try again.