<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Virtual Surreality</title>
	
	<link>http://grahamis.com/blog</link>
	<description>It's too real to be true</description>
	<lastBuildDate>Sat, 28 Aug 2010 23:20:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/VirtualSurreality" /><feedburner:info uri="virtualsurreality" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Ruby5 podcast</title>
		<link>http://feedproxy.google.com/~r/VirtualSurreality/~3/Xeo0vXd5wxE/</link>
		<comments>http://grahamis.com/blog/2010/08/28/ruby5-podcast/#comments</comments>
		<pubDate>Sat, 28 Aug 2010 23:19:39 +0000</pubDate>
		<dc:creator>Josh Graham</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://grahamis.com/blog/?p=285</guid>
		<description><![CDATA[You can hear my dulcet tones at Ruby5 eposide 106 hosted with Jon &#8220;Lark&#8221; Larkowski. It was great fun &#8211; he made me do the accent at the beginning and we had a lot of laughs over the &#8220;it&#8217;s gonna rain&#8221; part. Hope you find it of use and if you have some Ruby news, [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F08%2F28%2Fruby5-podcast%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F08%2F28%2Fruby5-podcast%2F&amp;source=delitescere&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>You can hear my dulcet tones at <a href="http://ruby5.envylabs.com/episodes/108-episode-106-august-27-2010">Ruby5 eposide 106</a> hosted with Jon &#8220;<a href="http://l4rk.com/">Lark</a>&#8221; Larkowski.</p>
<p>It was great fun &#8211; he <em>made</em> me do the accent at the beginning and we had a lot of laughs over the &#8220;it&#8217;s gonna rain&#8221; part.</p>
<p>Hope you find it of use and if you have some Ruby news, please do <a href="mailto:lark@hashrocket.com?Subject=Ruby5+story">submit stories to Lark</a>.</p>
<img src="http://feeds.feedburner.com/~r/VirtualSurreality/~4/Xeo0vXd5wxE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grahamis.com/blog/2010/08/28/ruby5-podcast/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://grahamis.com/blog/2010/08/28/ruby5-podcast/</feedburner:origLink></item>
		<item>
		<title>How to disable submit buttons using jQuery</title>
		<link>http://feedproxy.google.com/~r/VirtualSurreality/~3/jOYPSFzEJ9Q/</link>
		<comments>http://grahamis.com/blog/2010/08/17/disable-submit-buttons-using-jquery/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 13:58:55 +0000</pubDate>
		<dc:creator>Josh Graham</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Reminder]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://grahamis.com/blog/?p=277</guid>
		<description><![CDATA[Came across this twice in the past two weeks. How NOT to do it: $('form :submit').click(function() { $(this).attr("disabled", true); $(this).val("wait..."); $(this).addClass("disabled"); }); Doing it the above way, the click event will indeed fire, but on some browsers the submit event will not. The event to bind to is submission of a form, not clicking of [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F08%2F17%2Fdisable-submit-buttons-using-jquery%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F08%2F17%2Fdisable-submit-buttons-using-jquery%2F&amp;source=delitescere&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>Came across this twice in the past two weeks.</p>
<p>How <strong><em>NOT</em></strong> to do it:</p>
<pre class="javascript" name="code">
$('form :submit').click(function() {
    $(this).attr("disabled", true);
    $(this).val("wait...");
    $(this).addClass("disabled");
});
</pre>
<p>Doing it the above way, the click event will indeed fire, but on some browsers the submit event will not.</p>
<p>The event to bind to is submission of a form, not clicking of a submit button. </p>
<p>How to do it:</p>
<pre class="javascript" name="code">
$('form').submit(function() {
    $(":submit").attr("disabled", "disabled");
    $(":submit").val("wait...");
    $(":submit").addClass("disabled");
});
</pre>
<p>Also, the <code>:submit</code> selector is a jQuery cross-browser selector for input and button elements that could submit the form, used in preference to <code>input[type="submit"]</code></p>
<img src="http://feeds.feedburner.com/~r/VirtualSurreality/~4/jOYPSFzEJ9Q" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grahamis.com/blog/2010/08/17/disable-submit-buttons-using-jquery/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://grahamis.com/blog/2010/08/17/disable-submit-buttons-using-jquery/</feedburner:origLink></item>
		<item>
		<title>Heroku, bundler, Ruby 1.9, Rails 3, RSpec 2</title>
		<link>http://feedproxy.google.com/~r/VirtualSurreality/~3/n_GeC2Swq3I/</link>
		<comments>http://grahamis.com/blog/2010/07/01/heroku-bundler-ruby19-rails3-rspec2/#comments</comments>
		<pubDate>Thu, 01 Jul 2010 20:33:30 +0000</pubDate>
		<dc:creator>Josh Graham</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Operating Systems]]></category>
		<category><![CDATA[Reminder]]></category>
		<category><![CDATA[bundler]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[heroku]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[rspec]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://grahamis.com/blog/?p=246</guid>
		<description><![CDATA[A little &#8220;remember me later&#8221; for conditionally deploying a Rails 3 app running on Ruby 1.9 on Heroku. $ruby_version = `ruby --version`.split[1].to_f $heroku = ENV['USER'].match(/^repo\d+/) source :rubygems source 'http://gems.github.com' gem 'rails', '3.0.0.beta4' # gem 'rails', :git => 'git://github.com/rails/rails.git' gem 'bson_ext', '~> 1.0.1' gem 'decent_exposure' gem 'haml' gem 'mongoid', '>= 2.0.0.beta.9' unless $heroku if $ruby_version < [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F07%2F01%2Fheroku-bundler-ruby19-rails3-rspec2%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F07%2F01%2Fheroku-bundler-ruby19-rails3-rspec2%2F&amp;source=delitescere&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>A little &#8220;remember me later&#8221; for conditionally deploying a Rails 3 app running on Ruby 1.9 on Heroku.</p>
<pre name="code" class="ruby">
$ruby_version = `ruby --version`.split[1].to_f
$heroku = ENV['USER'].match(/^repo\d+/)

source :rubygems
source 'http://gems.github.com'

gem 'rails', '3.0.0.beta4'
# gem 'rails', :git => 'git://github.com/rails/rails.git'

gem 'bson_ext', '~> 1.0.1'
gem 'decent_exposure'
gem 'haml'
gem 'mongoid', '>= 2.0.0.beta.9'

unless $heroku
  if $ruby_version < 1.9
    gem 'ruby-debug'
  else
    gem 'ruby-debug19'
  end

  group :development, :test do
    gem 'rspec-rails', '>= 2.0.0.beta.17'
    gem 'rails3-generators' #for HAML
  end
end
</pre>
<p>The <code>--without=test</code> option isn&#8217;t (yet) being used on Heroku deploys, thus the <code>:test</code> group is in the unheroku block. <b>Update: check if <code>.bundle/config WITHOUT=""</code> works.</b></p>
<p><b>Update: Mongoid changed gem versioning for lexicographical sorting (a &#8220;dot&#8221; between &#8220;beta&#8221; and the number</b><br />
<b>Update: Latest mongoid (beta.16 and something after beta.9) requires Rails 3.0.0.rc which doesn&#8217;t support Ruby 1.9.1 which isn&#8217;t yet on Heroku</b><br />
<b>Update: Heroku user doesn&#8217;t have &#8220;repo&#8221; in it anymore and USER env var isn&#8217;t available &#8211; find new mechanism if bundler config WITHOUT option doesn&#8217;t work</b></p>
<p>Also:</p>
<ul>
<li>Only the <code>--colo(u)r</code> and <code>--format</code> options work in the <code>.rspec</code> file</li>
<li><code>use_transactional_fixtures=false</code> in <code>spec_helper.rb</code> (talk to Chelimsky about transactional fixtures in non-ActiveRecord environments)</li>
<li>In application.rb:
<ul>
<li><code>require 'mongoid/railtie'</code></li>
<li><code>require 'decent_exposure/railtie'</code></li>
<li><code>g.orm :mongoid</code></li>
<li><code>g.template-engine :haml</code></li>
<li><code>g.text_framework :rspec, :fixture => false, :views => false</code></li>
</ul>
</li>
</ul>
<img src="http://feeds.feedburner.com/~r/VirtualSurreality/~4/n_GeC2Swq3I" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grahamis.com/blog/2010/07/01/heroku-bundler-ruby19-rails3-rspec2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://grahamis.com/blog/2010/07/01/heroku-bundler-ruby19-rails3-rspec2/</feedburner:origLink></item>
		<item>
		<title>WindyCityDB lightning talk</title>
		<link>http://feedproxy.google.com/~r/VirtualSurreality/~3/XhpJHRxIwMA/</link>
		<comments>http://grahamis.com/blog/2010/06/26/windycitydb-lightning-talk/#comments</comments>
		<pubDate>Sat, 26 Jun 2010 18:55:12 +0000</pubDate>
		<dc:creator>Josh Graham</dc:creator>
				<category><![CDATA[Conference]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://grahamis.com/blog/?p=240</guid>
		<description><![CDATA[WindyCityDB &#8211; great conference! I did a lightning talk on squealer, and here is the PDF of the slides (1.7MB) squealer Lightning Talk slides]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F06%2F26%2Fwindycitydb-lightning-talk%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F06%2F26%2Fwindycitydb-lightning-talk%2F&amp;source=delitescere&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p><a href="http://windycitydb.com/">WindyCityDB</a> &#8211; great conference!</p>
<p>I did a lightning talk on <a href="http://vurl.me/SXT">squealer</a>, and here is the PDF of the slides (1.7MB)</p>
<p><a href='http://grahamis.com/blog/wp-content/uploads/2010/06/squealer-lightning.pdf'>squealer Lightning Talk slides</a></p>
<img src="http://feeds.feedburner.com/~r/VirtualSurreality/~4/XhpJHRxIwMA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grahamis.com/blog/2010/06/26/windycitydb-lightning-talk/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://grahamis.com/blog/2010/06/26/windycitydb-lightning-talk/</feedburner:origLink></item>
		<item>
		<title>Less than one year to go</title>
		<link>http://feedproxy.google.com/~r/VirtualSurreality/~3/wrBi5CY1LRI/</link>
		<comments>http://grahamis.com/blog/2010/06/12/less-than-one-year-to-go/#comments</comments>
		<pubDate>Sat, 12 Jun 2010 16:27:59 +0000</pubDate>
		<dc:creator>Josh Graham</dc:creator>
				<category><![CDATA[Information Science]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://grahamis.com/blog/?p=223</guid>
		<description><![CDATA[Roy Singham's gonna owe me a drink.]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F06%2F12%2Fless-than-one-year-to-go%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F06%2F12%2Fless-than-one-year-to-go%2F&amp;source=delitescere&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>One evening in <a href="/blog/2006/05/28/rubylove/">May, 2006</a> at a ThoughtWorks Sydney company meeting, Richard McLaren (then a Senior VP of ThoughtWorks) and I made a bet with Jon Tirsen (now Google überwunderkind) and Roy Singham (still Chairman of ThoughtWorks) about Ruby in the Enterprise.</p>
<p>The claim from Roy and Jon was that within five years, 10% of applications running in the Enterprise would be written in Ruby. Richard and I bet against that. The prize is a case each of the winners&#8217; favourite potable.</p>
<p>I&#8217;ve since been steadily working to try to lose that bet, and now code daily in Ruby at Hashrocket.</p>
<p>Alas, with just one year to go, I think Richard and I are going to win. Although there&#8217;s been a decent growth in Ruby&#8217;s adoption in the Enterprise, my esteemed colleagues underestimated the lack of capability, talent, and intellect of the majority of corporate IT decision makers.</p>
<img src="http://feeds.feedburner.com/~r/VirtualSurreality/~4/wrBi5CY1LRI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grahamis.com/blog/2010/06/12/less-than-one-year-to-go/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://grahamis.com/blog/2010/06/12/less-than-one-year-to-go/</feedburner:origLink></item>
		<item>
		<title>Why “squealer” – MongoDB to SQL</title>
		<link>http://feedproxy.google.com/~r/VirtualSurreality/~3/72WzOjf-xEI/</link>
		<comments>http://grahamis.com/blog/2010/06/10/squealer-intro/#comments</comments>
		<pubDate>Thu, 10 Jun 2010 15:12:16 +0000</pubDate>
		<dc:creator>Josh Graham</dc:creator>
				<category><![CDATA[Agile / Lean]]></category>
		<category><![CDATA[Coding]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Rant]]></category>
		<category><![CDATA[hashrocket]]></category>
		<category><![CDATA[mongodb]]></category>
		<category><![CDATA[nosql]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://grahamis.com/blog/?p=171</guid>
		<description><![CDATA[Object/Relational Mappings (ORM's) are in the wrong place in the architecture.

An application should have minimal impedance mismatch with the persistence of its own data. External or ancillary systems should bear the cost of mapping between paradigms. If you want to access application data in a relational way for reports, do the mapping for the report.

Squealer is a simple, declarative language where the mapping from the tree structure of MongoDB to the tuple space in mySQL can be scripted.]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F06%2F10%2Fsquealer-intro%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F06%2F10%2Fsquealer-intro%2F&amp;source=delitescere&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>Object/Relational Mappings (ORM&#8217;s) are in the wrong place in the architecture.</p>
<p>An application should have minimal impedance mismatch with the persistence of its own data. External or ancillary systems should bear the cost of mapping between paradigms. If you are writing an application with the concepts modelled in an object-oriented fashion, then the state of those objects should be stored in an object-oriented fashion. Mapping from the object-oriented structure to a relational structure should be done where and when it&#8217;s needed. If you want to access application data in a relational way for reports, do the mapping for the report.</p>
<p>There has been a low uptake of OODBMS&#8217;s. Why is outside the scope of this post. However, there are other, older (albeit feeling newer) data storage techniques available that more readily persist an object graph than a relational database. A flurry of open-source implementations have come along. You may have heard of MongoDB, neo4j, Redis, Hadoop, CouchDB, Memcached, and <a href="http://ravendb.net/" target="_blank">Raven DB</a> (a native .NET document database). These are all under active development, and almost all have been proven on many large commercial projects (Raven was being developed by <a href="http://ayende.com/Blog/" target="_blank">Oren</a> while he was at <a href="http://speakerconf.com" target="_blank">speakerconf</a> 2010!).</p>
<p>For an introductory look at evaluating the landscape, check out Sarah Mei&#8217;s RailsConf <a href="http://www.sarahmei.com/blog/2010/06/09/railsconf-slides" target="_blank">presentation slides</a>.</p>
<p>One of the projects I&#8217;ve worked on at Hashrocket involved a large MongoDB database. The reasons for the choice for MongoDB were clear:</p>
<ul>
<li>the way the users handled most of the data more naturally fitted an embedded document model;</li>
<li>the scale and speed required were far greater than relational databases could achieve; and</li>
<li>the need for ACID transactions was almost nil</li>
</ul>
<p>Additionally, the data was mostly read, rather than written (although MongoDB writes blazingly fast too). I&#8217;m hoping to address the equivocations in those reasons in a subsequent post.</p>
<p>MongoDB uses a binary form of <a href="http://www.json.org/" target="_blank">JSON</a>. As JSON is a serialization format for object state, it&#8217;s a good candidate for persisting an object graph. JavaScript, remember, uses composition rather than inheritance, so there is also a tendency to &#8220;embed&#8221; document instances within other document instances. So, for MongoDB, most of the object graph is stored a tree structure. Cyclic graphs and associated objects (those that aren&#8217;t aggregated with composition) are handled with references to identifiers.</p>
<p>As a consequence of using Rails and MongoDB, the team looked to various ways of manipulating the JSON structures from Ruby: directly through the driver, <a href="http://rubygems.org/gems/mongo_mapper" target="_blank">MongoMapper</a>, <a href="http://rubygems.org/gems/mongodoc" target="_blank">MongoDoc</a>, and <a href="http://mongoid.org/" target="_blank">Mongoid</a>. The rationales behind these libraries and their different and interesting approaches are the subject of additional blogs (hopefully jointly with Nunemaker, Hill, and Jordan respectively). The needs and makeup of the project we were on fell into the lap of mongoid to solve.</p>
<p>DBAs want to interact directly with the database. Because of this &#8220;new-fangled&#8221; approach to data storage that has been around since before SQL, some are unwilling or unable to learn the query language to interact directly with the database. So, to make their world a less scary place and let them retire without the stress of intellectual endeavour, I built a simple, declarative language where the mapping from the tree structure of MongoDB to the tuple space in an RDBMS can be scripted.</p>
<p>Durran Jordan (author of Mongoid) and I paired on &#8220;squealer&#8221; (and on emptying bottles) in our evenings while he was stationed in the Chicago office of Hashrocket. The name came from &#8220;SQL&#8221; (which some of us still pronounce &#8220;squeal&#8221; rather than &#8220;sequel&#8221;) and the facetious notion that it turned the data into a pig.</p>
<p>We decided to focus on mySQL as the target and MongoDB as the source as these are the technologies we were using. Upcoming targets will include PostgreSQL, SQL Server, Oracle. Upcoming sources will include Redis and CouchDB.</p>
<p><em>UPDATE: squealer 2.2 now supports PostgreSQL!</em></p>
<p>Matt Yoho provided multiple insights into implementing the Ruby DSL, and Bernerd Schaefer helped me reduce the DSL syntax and provide sensible defaults (as well as the righteous progress bar). Bernerd then struck on the idea of reflecting on the Mongoid declarations in the Rails domain model classes to generate an initial squealer script and SQL DDL to build the target SQL database. He then set about writing it overnight and we tweaked it over lunch. We called this tool &#8220;skewer&#8221;, because that&#8217;s what you do to something to make it squeal <img src='http://grahamis.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> . It&#8217;s part of the squealer RubyGem.</p>
<p>Next time: how to use skewer and squealer.</p>
<img src="http://feeds.feedburner.com/~r/VirtualSurreality/~4/72WzOjf-xEI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grahamis.com/blog/2010/06/10/squealer-intro/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://grahamis.com/blog/2010/06/10/squealer-intro/</feedburner:origLink></item>
		<item>
		<title>Hashrocket man (and I think it’s gonna be a long, long time)</title>
		<link>http://feedproxy.google.com/~r/VirtualSurreality/~3/ovagpq5-frM/</link>
		<comments>http://grahamis.com/blog/2010/01/19/hashrocket-man/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 19:30:27 +0000</pubDate>
		<dc:creator>Josh Graham</dc:creator>
				<category><![CDATA[Information Science]]></category>
		<category><![CDATA[hashrocket]]></category>

		<guid isPermaLink="false">http://grahamis.com/blog/?p=150</guid>
		<description><![CDATA[After 4.5 years at ThoughtWorks, I&#8217;ve put down the purple elephant and donned my spacesuit to join Hashrocket and open the Chicago office. Hashrocket is the world&#8217;s best Ruby on Rails shop — a world-class team of spectacular developers, lead by my former and now current colleague Obie Fernandez. Our Chicago office has been set [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F01%2F19%2Fhashrocket-man%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2010%2F01%2F19%2Fhashrocket-man%2F&amp;source=delitescere&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>After 4.5 years at ThoughtWorks, I&#8217;ve put down the purple elephant and donned my spacesuit to join <a href="http://hashrocket.com/">Hashrocket</a> and open the Chicago office.</p>
<p>Hashrocket is the <a href="http://railscompanies.com/">world&#8217;s best</a> Ruby on Rails shop — a world-class team of spectacular developers, lead by my former and now current colleague <a href="http://obiefernandez.com/">Obie Fernandez</a>.</p>
<p>Our Chicago office has been set up to help draw in more talent to meet our growing client needs. Some devs would prefer to live in a big city and Chicago has a strong Ruby community.</p>
<p>If you&#8217;re a Rubyist in Chicago, you can look forward to Hashrocket soon hosting some of the user groups and other events. We will be open at 661 W Lake St on Feb 1, 2010.</p>
<img src="http://feeds.feedburner.com/~r/VirtualSurreality/~4/ovagpq5-frM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grahamis.com/blog/2010/01/19/hashrocket-man/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://grahamis.com/blog/2010/01/19/hashrocket-man/</feedburner:origLink></item>
		<item>
		<title>PreparedEval</title>
		<link>http://feedproxy.google.com/~r/VirtualSurreality/~3/DQgNkW71DAY/</link>
		<comments>http://grahamis.com/blog/2009/10/06/preparedeval/#comments</comments>
		<pubDate>Tue, 06 Oct 2009 15:46:12 +0000</pubDate>
		<dc:creator>Josh Graham</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://grahamis.com/blog/?p=141</guid>
		<description><![CDATA[Prepare Java strings for JavaScript evaluation, similar to SQL prepared statements. Saves you from quote escape nightmares!]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2009%2F10%2F06%2Fpreparedeval%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2009%2F10%2F06%2Fpreparedeval%2F&amp;source=delitescere&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>Announcing PreparedEval, prepared statements for generating JavaScript (and the like) from Java. It prepares Java strings for JavaScript evaluation, similar to SQL prepared statements. Saves you from quote escape nightmares! Great for Selenium tests and Rhino JavaScript.</p>
<p>As a follow-up to my post on escaped, quoted strings, Taking the idea of using a different encoding scheme further (and not being super happy about the need to pump the string through <code>unescape()</code>) I thought about interpolation and wondered about prepared statements in SQL. Some quick research turned nothing up, but while chatting with <a href="http://www.olabini.com/">Ola Bini</a> he also mentioned prepared statements, so this convinced me to knock something together that might be useful.</p>
<p>More information is at <a href="http://wiki.github.com/delitescere/PreparedEval">http://wiki.github.com/delitescere/PreparedEval</a>.</p>
<p>There&#8217;s no runtime dependencies so it&#8217;s nice and tiny if you just want the JAR.</p>
<p>Let me know if you use if to help with CSS / XPath selectors for Selenium or if you have any suggestions on improving the API.</p>
<img src="http://feeds.feedburner.com/~r/VirtualSurreality/~4/DQgNkW71DAY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grahamis.com/blog/2009/10/06/preparedeval/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://grahamis.com/blog/2009/10/06/preparedeval/</feedburner:origLink></item>
		<item>
		<title>Escape the literal prison.</title>
		<link>http://feedproxy.google.com/~r/VirtualSurreality/~3/svbWIvBpGRA/</link>
		<comments>http://grahamis.com/blog/2009/09/20/escape-the-literal-prison/#comments</comments>
		<pubDate>Sun, 20 Sep 2009 06:17:18 +0000</pubDate>
		<dc:creator>Josh Graham</dc:creator>
				<category><![CDATA[Coding]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://grahamis.com/blog/?p=96</guid>
		<description><![CDATA[When you have more backslashes than words in the strings you are constructing, perhaps it's time to look at another way of handling special characters like quotes.]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2009%2F09%2F20%2Fescape-the-literal-prison%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2009%2F09%2F20%2Fescape-the-literal-prison%2F&amp;source=delitescere&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>When you have more backslashes than words in the strings you are constructing, perhaps it&#8217;s time to look at another way of handling special characters like quotes.</p>
<h3>The problem</h3>
<p>You&#8217;re generating JavaScript code from another language with C-like quoting and escaping syntax (e.g. Java).</p>
<p>As part of that code generation, you&#8217;re substituting strings that have both double quotes (&#8220;) and single quotes (&#8216;). My team&#8217;s actual problem stems from using XPath locators which include quoted text and sending that to Selenium so we can obtain the particular element that contains the text<sup><a href="#why">*</a></sup>.</p>
<p>Let&#8217;s say we want to pop up an alert within which are some double quotes:</p>
<pre name="code" class="java">
String original = "Hello \"stranger\", how are you?";
String quoted = original.replaceAll("\"", "\\\"");
String script = "alert(\"" + quoted + "\")";
eval(script);
</pre>
<p>We then expect the browser to have this JavaScript code to process:</p>
<pre name="code" class="javascript">alert("Hello \"stranger\", how are you?")</pre>
<p>and when then expect the alert to display the string:</p>
<blockquote><p>Hello &#8220;stranger&#8221;, how are you?</p></blockquote>
<p>But why doesn&#8217;t it work?<br />
<span id="more-96"></span><br />
Well, as you can already see, there&#8217;s lots of escaping of quotes going on so let&#8217;s analyze each line of the code:</p>
<ol>
<li>Needs to escape the quotes around the word <u>stranger</u> in a string literal for the Java compiler.</li>
<li>Replaces all double quotes with a backslash and double quotes (or does it??). The intent is to inject the same escaped quotes for the benefit of the JavaScript interpreter, when it&#8217;s a string literal in JavaScript code. To do that we inject the backslash character to escape the quote. But the backslash character also needs to be escaped for the Java compiler so we escape it too.</li>
<li>Then constructs another string which is the JavaScript function to execute in the browser, containing our escaped-quotes string. Again, we&#8217;ve had to escape quotes in the string literals for the Java compiler.</li>
<li>Sends the command to the JavaScript interpreter (e.g. a browser) for evaluation.</li>
</ol>
<p>What does the JavaScript interpreter do with the command we&#8217;ve asked it to evaluate? Something like this:</p>
<blockquote><p>
ERROR: Threw an exception: missing ) after argument list
</p></blockquote>
<p>All that trouble we went to to escape the quotes and the escape character has disappeared! In fact, the result is identical to not having tried to inject the escape characters at all.</p>
<p>What&#8217;s going on? Let&#8217;s try escaping the backslash:</p>
<pre name="code" class="java">
String original = "Hello \"stranger\", how are you?";
String quoted = original.replaceAll("\"", "\\\\\"");
String script = "alert(\"" + quoted + "\")";
eval(script);
</pre>
<p>This works. Why? We&#8217;re using <code>String replaceAll()</code>. It seems that not only is backslash an escape character for the Java compiler, it is also an escape character for the regex Matcher. From the JavaDoc of <code>Matcher replaceAll()</code>:</p>
<blockquote><p>
Note that backslashes (\) and dollar signs ($) in the replacement string may cause the results to be different than if it were being treated as a literal replacement string. Dollar signs may be treated as references to captured subsequences as described above, and <strong>backslashes are used to escape literal characters in the replacement string</strong>.
</p></blockquote>
<p>Hmm, that vital piece of information might have been useful in the JavaDoc for <code>String replaceAll()</code> which delegates to <code>Matcher replaceAll()</code>. Obviously we can&#8217;t rely on the Java standard libraries for names being obvious (Principle Of Least Surprise does not hold with these APIs). Let&#8217;s try another method, <code>String replace()</code>. After looking at the JavaDoc we see:</p>
<blockquote><p>
Replaces each substring of this string that matches the literal target sequence with the specified literal replacement sequence&#8230;
</p></blockquote>
<p>The word &#8220;literal&#8221; is used a couple of times here, so we might interpret that to mean the special backslash and dollar sign handling doesn&#8217;t apply here. Indeed, looking at the JavaDoc of the functionality <code>String replace()</code> delegates to, <code>Matcher.quoteReplacement()</code>:</p>
<blockquote><p>
Returns a literal replacement String for the specified String. This method produces a String that will work use as a literal replacement s in the appendReplacement method of the Matcher class. The String produced will match the sequence of characters in s treated as a literal sequence. <strong>Slashes (&#8216;\&#8217;) and dollar signs (&#8216;$&#8217;) will be given no special meaning</strong>.
</p></blockquote>
<p>Apart from the fact that the author meant &#8220;backslashes&#8221; not &#8220;slashes&#8221;, this makes it obvious. Again, the JavaDoc for <code>String replace()</code> could have been more explicit and actually useful.</p>
<pre name="code" class="java">
String original = "Hello \"stranger\", how are you?";
String quoted = original.replace("\"", "\\\"");
String script = "alert(\"" + quoted + "\")";
eval(script);
</pre>
<p>The strategic lesson is to not rely on the name of a library method to mean what you think it means, nor to rely on the API documentation to tell you what you really need to know about using the method. Although this is exactly what you <strong>should</strong> be able to do, you can&#8217;t.</p>
<div class="callout">Another time encoding bites is with HTML and URL encoding. If each part of the software chain doesn&#8217;t correctly encode and decode, we end up with pages that have spurious <code>&amp;</code> or <code>&lt;</code> characters (btw, I had to HTML encode the ampersand and less-than sign for the blog) or <code>%HH</code> hex-encoded values in the text, or an invalid document that has double decoded characters that the renderer takes as markup characters rather than character data (have you ever seen something like this on a web page&#8230; Ben &amp;amp; Jerry&#8217;s).
</div>
<p>So we&#8217;ve found out that at least three parts of our infrastructure (Java compiler, JavaScript interpreter, and the standard Java regular expression matcher) treat backslash specially. Are there more? Probably, and typically they&#8217;ll change as time goes by.</p>
<p><em><strong>Perhaps the following approach goes from the frying pan into the fire</strong></em> (in which case you might not want to use something like it), but it uses a blend of the C-style escaping with encoding<sup><a href="#encode_or_escape">†</a></sup>&#8230;</p>
<h3 style="float: clear">Different encodings</h3>
<p>Instead, let&#8217;s escape the literal prison and use a different mechanism to embed quotes in the string.</p>
<pre name="code" class="java">
String original = "Hello \"stranger\", how are you?";
String quoted = original.replace("\"", "%22");
quoted = "unescape(\"" + quoted + "\")";
String script = "alert(\"" + quoted + "\")";
eval(script);
</pre>
<p>Now line 2 uses the character encoded version of double quote (the ASCII/UTF-8 hexadecimal value).<br />
Also, line 4 includes the instruction for JavaScript to decode the string which would revert the %22 back to a double quote.</p>
<div class="callout">
Please note that the JavaScript <code>escape()</code> and <code>unescape()</code> functions are <strong>NOT</strong> for encoding values in a URI. They are now merely for JavaScript functions to safely represent certain characters within the JavaScript context. URI encoding may have been their original intent but the <code>encodeURI()</code> and <code>encodeURIComponent()</code> functions are the correct ones to use for URI purposes.
</div>
<p>Here, we are generating JavaScript and using a naive implementation of <code>escape()</code> so we can use the inbuilt JavaScript <code>unescape()</code> to decode the quotes at runtime. </p>
<p>Given we&#8217;re dealing with JavaScript, we can also use single quotes for string literals so we&#8217;d include the encoded version of them in our substitution too:</p>
<pre name="code" class="java">
String quoted = original.replace("\"", "%22").replace("'", "%27");
</pre>
<hr />
<h3>Footnotes</h3>
<p><a name="why"></a><br />
<h4>*Why are you trying to find an element based on the text within it?</h4>
<p>That is a long story but let&#8217;s imagine a website where the HTML structure is very poor, you want to run some functional tests against it, you don&#8217;t have access to the source of the application that generates the HTML, and you have only marginal influence on the third-party who writes that application.</p>
<p>In some unfortunate circumstances, there is nothing unique about an element except the text within it, or even worse, the text within a nearby element.</p>
<hr />
<a name="encode_or_escape"></a><br />
<h4>†Is it encode or escape?</h4>
<p>Probably a naming accident during the rushed implementation that JavaScript originally was, the <code>escape()</code> and <code>unescape()</code> functions are probably better called <code>encode()</code> and <code>decode()</code>.</p>
<p>&#8220;Escaping&#8221; refers to using a special character to have compiler temporarily &#8220;escape&#8221; from processing other special characters and rather treat them as normal, literal characters.</p>
<p>You use the same characters, but just prefix them with the escape character. In C-like languages, the escape character in string literals is backslash.</p>
<p>Encoding refers to using a different form to represent the data. So JavaScript encodes a double-quote character as the string <code>%22</code>. The URI standard also encodes them as <code>%22</code> and the HTML standard encodes them as the HTML entity <code>&amp;quot;</code> or <code>&amp;#34;</code> (as 34 is the decimal encoding of double-quote), and in C we could use <code>\%x22</code></p>
<p>In these encoding schemes, the <code>%</code>, <code>&amp;</code> and <code>\</code> characters are used as escape characters to indicate to the relevant parser that it needs to deviate from its normal processing and go into &#8220;encoding&#8221; mode.</p>
<hr />
<img src="http://feeds.feedburner.com/~r/VirtualSurreality/~4/svbWIvBpGRA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grahamis.com/blog/2009/09/20/escape-the-literal-prison/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://grahamis.com/blog/2009/09/20/escape-the-literal-prison/</feedburner:origLink></item>
		<item>
		<title>Indian Summer</title>
		<link>http://feedproxy.google.com/~r/VirtualSurreality/~3/Bp8JmVtAE4M/</link>
		<comments>http://grahamis.com/blog/2009/08/07/indian-summer/#comments</comments>
		<pubDate>Fri, 07 Aug 2009 10:28:25 +0000</pubDate>
		<dc:creator>Josh Graham</dc:creator>
				<category><![CDATA[Agile / Lean]]></category>

		<guid isPermaLink="false">http://grahamis.com/blog/2009/08/07/indian-summer/</guid>
		<description><![CDATA[I&#8217;m visiting our India operation for a few months, mostly at our Pune office. I&#8217;m trying my hand at various coaching activities on a number of fronts, including working with some of our technical leads, aspiring architects, business development team, and recruitment. I&#8217;ve always been a fan of our teams in India and China. In [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2009%2F08%2F07%2Findian-summer%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fgrahamis.com%2Fblog%2F2009%2F08%2F07%2Findian-summer%2F&amp;source=delitescere&amp;style=normal&amp;service=bit.ly" height="61" width="50" /><br />
			</a>
		</div>
<p>I&#8217;m visiting our India operation for a few months, mostly at our Pune office. I&#8217;m trying my hand at various coaching activities on a number of fronts, including working with some of our technical leads, aspiring architects, business development team, and recruitment.</p>
<p>I&#8217;ve always been a fan of our teams in India and China. In the early days of the ThoughtWorks Sydney office, to help fill the rapidly growing demand pipeline, we were able to bring people in from TW offices around the world, including some from India (Nitesh rocks!). We also had to distribute some delivery work to India (and later, China too) on some large projects. This was an eye-opening time for us in learning how to make Agile software development work across teams in different places and timezones. (People like Ben Hogan, Naresh Jain, Shyam Mohan, and Jane Robarts have been able to share some of that experience at conferences.)</p>
<p>It wasn&#8217;t the reduced rates that these projects were able to offer to clients that appealed to them &#8211; it was the large capacity of ThoughtWorks talent available that we simply couldn&#8217;t fill quickly enough locally. ThoughtWorks and clients alike insisted on top grade delivery team members, no matter where they happened to be located during any given iteration (we rotated people through the locations quite a bit to engender better collaboration, shared understanding, and teamwork).</p>
<p>Being a senior member of the company for four years, I had always felt a little incomplete in not having visited any offshore teams &#8211; based on the stories from others who had visited, I was missing out. I&#8217;m pleased now I&#8217;m here and I can experience for myself the atmosphere, attitude and aptitude of the Pune office and I&#8217;ll get to meet everyone from Chennai and Bangalore at the ThoughtWorks India Away Day in a few weeks.</p>
<p>It&#8217;s also pleasing that we have evolved the offshore capability to the point it is a compelling set of offerings that really appeal to companies looking for top quality, technical innovation, agile software delivery, and commitment to results within leaner budgets. <a href="http://offshore.thoughtworks.com/">http://offshore.thoughtworks.com/</a></p>
<p>I&#8217;m very excited to be here right now. Amanda is knocking out her &#8220;F# In Action&#8221; book from Manning as fast as an autorickshaw darts between pedestrians, I&#8217;m working with some awesome new and old faces, and the <em>dal makhani</em> is delicious!</p>
<p>However, I&#8217;m not having much luck getting people to call me &#8220;RoganJoshG&#8221;&#8230; <img src='http://grahamis.com/blog/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<img src="http://feeds.feedburner.com/~r/VirtualSurreality/~4/Bp8JmVtAE4M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://grahamis.com/blog/2009/08/07/indian-summer/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://grahamis.com/blog/2009/08/07/indian-summer/</feedburner:origLink></item>
	</channel>
</rss>
