<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/atom10full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0"><id>tag:blogger.com,1999:blog-6369418367411691447</id><updated>2008-08-28T08:22:51.655-05:00</updated><title type="text">Mike Subelsky's Blog</title><subtitle type="html">Mike Subelsky's hacking and improv theater blog.</subtitle><link rel="alternate" type="text/html" href="http://www.subelsky.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default?start-index=26&amp;max-results=25" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>53</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><geo:lat>39.325956</geo:lat><geo:long>-76.606026</geo:long><link rel="license" type="text/html" href="http://creativecommons.org/licenses/by-sa/3.0/" /><logo>http://creativecommons.org/images/public/somerights20.gif</logo><link rel="self" href="http://feeds.feedburner.com/subelskyblog" type="application/atom+xml" /><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-1120034496802012380</id><published>2008-08-19T19:28:00.002-05:00</published><updated>2008-08-19T19:41:47.529-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="baltimore" /><category scheme="http://www.blogger.com/atom/ns#" term="Ignite" /><title type="text">Ignite Baltimore Call for Participants</title><content type="html">Hey everyone, we're organizing &lt;a href="http://ignitebaltimore.com/"&gt;Ignite Baltimore&lt;/a&gt;, and we're looking for interesting topics.  Check out the site for more details, or visit these other city Ignite pages for inspiration:&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'times new roman'; "&gt;&lt;a href="http://www.ignite-phoenix.org/submissions/subs-aug-08/"&gt;Phoenix&lt;/a&gt;&lt;a href="http://radar.oreilly.com/2008/07/ignite-nyc-soldering-guerilla.html"&gt;&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'times new roman'; "&gt;&lt;a href="http://radar.oreilly.com/2008/07/ignite-nyc-soldering-guerilla.html"&gt;New York&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'times new roman'; "&gt;&lt;a href="http://www.igniteseattle.com/2008/02/ignite-seattle-5-the-schedule/"&gt;Seattle&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'times new roman';"&gt;If you're a Twitter person, follow &lt;a href="http://twitter.com/ignitebaltimore"&gt;@ignitebaltimore&lt;/a&gt;. &lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/369511386" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/369511386/ignite-baltimore-call-for-participants.html" title="Ignite Baltimore Call for Participants" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=1120034496802012380" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/1120034496802012380" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/1120034496802012380" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/08/ignite-baltimore-call-for-participants.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-4079363372029503588</id><published>2008-08-12T14:46:00.004-05:00</published><updated>2008-08-12T15:25:04.256-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="sproutcore" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">Humane Sproutcore Server Development Environment</title><content type="html">Recently I've started to build a new, rich user interface for &lt;a href="http://otherinbox.com/"&gt;OtherInbox&lt;/a&gt; using &lt;a href="http://sproutcore.com/"&gt;SproutCore&lt;/a&gt;, which has been very enjoyable.  One thing that was not enjoyable was properly configuring my development environment.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In production, you'll usually deploy your SproutCore app as a static file, so all you have to do is arrange for your users to hit that URL (which out of the box is configured as /static, but could be anything).&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In development mode, though, you want to be regenerating your client on the fly by serving it dynamically from sc-server.  To use your app, you talk to http://localhost:4020, and if you want your client to communicate with a backend server, you configure the "proxy" setting in sc-config.  Thus when the Sproutcore server gets a request for "/gadgets", it proxies that request to your local development server.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For some kinds of apps, this works well.  For OtherInbox though, everything the Sproutcore app does requires you to be signed-in and have an active session with the Rails application server.  This caused all kinds of cookie problems, probably because of same origin policy (e.g. my Rails app running at otherinbox.dev was issuing cookies that were somehow getting mangled by the proxying process).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's what I solved the problem.  Check out &lt;a href="http://www.subelsky.com/2007/11/testing-rails-ssl-requirements-on-your.html"&gt;my local Apache setup&lt;/a&gt; for details about the whole stack:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="textmate-source"&gt;&lt;span class="source source_apache-config"&gt;&lt;span class="meta meta_vhost meta_vhost_apache-config"&gt; &lt;span class="meta meta_tag meta_tag_apache-config"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_apache-config"&gt;&amp;lt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_apache-config"&gt;VirtualHost&lt;/span&gt; &lt;span class="meta meta_toc-list meta_toc-list_virtual-host meta_toc-list_virtual-host_apache-config"&gt;*:80&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_apache-config"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="support support_constant support_constant_apache-config"&gt;ProxyPass&lt;/span&gt; /app http://localhost:4020/other_inbox/&lt;br /&gt; &lt;span class="support support_constant support_constant_apache-config"&gt;ProxyPassReverse&lt;/span&gt; /app http://localhost:4020/other_inbox&lt;br /&gt;&lt;br /&gt; &lt;span class="support support_constant support_constant_apache-config"&gt;ProxyPass&lt;/span&gt; /static http://localhost:4020/static/&lt;br /&gt; &lt;span class="support support_constant support_constant_apache-config"&gt;ProxyPassReverse&lt;/span&gt; /static http://localhost:4020/static&lt;br /&gt;&lt;br /&gt; &lt;span class="support support_constant support_constant_apache-config"&gt;ProxyPass&lt;/span&gt; / http://localhost:3000/&lt;br /&gt; &lt;span class="support support_constant support_constant_apache-config"&gt;ProxyPassReverse&lt;/span&gt; / http://localhost:3000&lt;br /&gt;&lt;br /&gt; &lt;span class="support support_constant support_constant_apache-config"&gt;ProxyPreserveHost&lt;/span&gt; on&lt;br /&gt;&lt;span class="meta meta_tag meta_tag_apache-config"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_apache-config"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_apache-config"&gt;VirtualHost&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_apache-config"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;See how that works?  When I load http://otherinbox.dev/app in the browser, Apache proxies that request to sc-server, which dynamically generates my Sproutcore client app.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When components of that app make requests for other parts of Sproutcore, using the /static URL, Apache also proxies those back to sc-server.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When the app makes requests for anything else, those requests get proxied by Apache to the Mongrel I have running the Rails code.  Because my Sproutcore app is making REST calls to the backend, this ensures that anything the Sproutcore app asks for from my server gets proxied properly, in this case to localhost:3000.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As soon as I did this, all of the cookie issues were done.  You'll also have to add some application-specific code about how you want to force logins if the user is not already signed-in. In our code, I just check for a logged-in cookie, and if it's not there, we open up the URL for a signin window.&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/363220970" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/363220970/humane-sproutcore-server-development.html" title="Humane Sproutcore Server Development Environment" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=4079363372029503588" title="1 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/4079363372029503588" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/4079363372029503588" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/08/humane-sproutcore-server-development.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-8076927519108051077</id><published>2008-07-30T14:19:00.005-05:00</published><updated>2008-07-30T20:23:55.092-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="micro-apps" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="gruff" /><title type="text">Cool Medialets Micro-App</title><content type="html">My good friend &lt;a href="http://paulbarry.com/"&gt;Paul Barry&lt;/a&gt; and I have been helping our friends at &lt;a href="http://medialets.com/"&gt;Medialets&lt;/a&gt; out with a &lt;a href="http://www.medialets.com/app-store-metrics/"&gt;neat little Rails micro-app&lt;/a&gt; that culls iPhone App Store data from Apple's endless array of plists, and makes a &lt;a href="http://www.medialets.com/app-store-metrics/"&gt;chart&lt;/a&gt;, a dynamically-generated &lt;a href="http://www.medialets.com/app-store-metrics/charts/apps-by-price"&gt;Gruff graph&lt;/a&gt;, and a bunch of RSS feeds.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My favorite thing about this app is the &lt;a href="http://www.medialets.com/app-store-metrics/feeds/new/"&gt;New Apps RSS feed&lt;/a&gt; which lets me keep up with the newest time-wasters/productivity enhancers for the iPhone.  Let me take this opportunity to say that the world does not need any more iPhone tip calculators or fortune-telling games.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I wrote a bit more about the latest features &lt;a href="http://www.medialets.com/blog/2008/07/30/screenshots-and-company-profile-listing-added-to-app-store-metrics-and-rss-feeds/"&gt;over at the Medialets blog&lt;/a&gt;. &lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/351057958" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/351057958/cool-medialets-micro-app.html" title="Cool Medialets Micro-App" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=8076927519108051077" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/8076927519108051077" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/8076927519108051077" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/07/cool-medialets-micro-app.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-3609653870784322680</id><published>2008-07-18T12:12:00.005-05:00</published><updated>2008-07-18T12:27:43.635-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="iPhone" /><title type="text">My iPhone app screens</title><content type="html">&lt;p&gt;I got stuck for 90 minutes at the dentist office, so I decided to organize all my iPhone apps.  First screen (left) is essentials, stuff I use every day.  Second screen (right) is references and tools.&lt;/p&gt;&lt;div style="float: left; margin-right: 5px; text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.subelsky.com/uploaded_images/IMG_0001-706756.png"&gt;&lt;img style="cursor: pointer;" src="http://www.subelsky.com/uploaded_images/IMG_0001-706703.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.subelsky.com/uploaded_images/IMG_0002-706842.png"&gt;&lt;img style="cursor: pointer;" src="http://www.subelsky.com/uploaded_images/IMG_0002-706832.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Third screen is "communications and entertainment". Fourth screen is the graveyard, for things I don't use regularly or can't get rid of.&lt;br /&gt;&lt;div style="float: left; margin-right: 5px;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.subelsky.com/uploaded_images/IMG_0003-773921.png"&gt;&lt;img style="cursor: pointer;" src="http://www.subelsky.com/uploaded_images/IMG_0003-773908.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.subelsky.com/uploaded_images/IMG_0004-774033.png"&gt;&lt;img style="cursor: pointer;" src="http://www.subelsky.com/uploaded_images/IMG_0004-774026.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;I can think of worse ways to kill 90 minutes.&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/339195488" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/339195488/my-iphone-app-screens.html" title="My iPhone app screens" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=3609653870784322680" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/3609653870784322680" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/3609653870784322680" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/07/my-iphone-app-screens.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-5882074637176893404</id><published>2008-07-02T14:03:00.002-05:00</published><updated>2008-07-02T14:05:30.669-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="git" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">Contributing to Rails is easier than you think</title><content type="html">&lt;img alt="Rails_2" title="Rails_2" src="http://joshuabaer.blogs.com/photos/uncategorized/2008/07/02/rails_2.png" border="0" style="float: left; margin: 0px 5px 5px 0px;" /&gt;At &lt;a href="http://www.otherinbox.com/"&gt;OtherInbox&lt;/a&gt; we love open source and are looking for ways to share some of our labors with the community.  Today I came across a great opportunity to contribute something to &lt;a href="http://rubyonrails.org/"&gt;Ruby-on-Rails&lt;/a&gt; core development.  I'm posting it here so everyone can see how easy it is to contribute.&lt;br /&gt;&lt;br /&gt;I was building a JSON API to enable some new awesome features we're working on.  Following the &lt;a href="http://www.json.org/JSONRequest.html"&gt;JSON request specification&lt;/a&gt;, I had the client setting its MIME type to "application/jsonrequest".  But this was not causing Rails to recognize the request as JSON and thus the request body was not properly parsed.  After doing some digging, I realized that Rails only looks for MIME type "application/json".&lt;br /&gt;&lt;br /&gt;Fortunately, MIME type processing is implemented really humanely in Rails, so I whipped up a little patch that adds "application/jsonrequest" as a synonym for the JSON MIME type.   First I wrote a test to prove that this was a problem.  Once I had a failing test, I added the MIME type, and got my test passing.  I followed the &lt;a href="http://rails.lighthouseapp.com/projects/8994/sending-patches"&gt;git patch instructions&lt;/a&gt; on lighthouse, then jumped into IRC #rails-contrib to garner support for it. &lt;br /&gt;&lt;br /&gt;I happened to see that &lt;a href="http://weblog.techno-weenie.net/"&gt;Rick Olson&lt;/a&gt;, the author of the existing JSON parsing code, was in the chat, so I pinged him with the lighthouse ticket.  He tested it and applied it, and now &lt;a href="http://github.com/rails/rails/commit/8f640c381d9d1b74f6a0fc3648c21da373661914"&gt;our one line of code is a part of Rails&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;Hopefully this will save some future JSON implementer a bit of pain.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;Cross-posted from the &lt;/span&gt;&lt;a href="http://blog.otherinbox.com/"&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;OtherInbox blog&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/325119829" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/325119829/contributing-to-rails-is-easier-than.html" title="Contributing to Rails is easier than you think" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=5882074637176893404" title="2 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/5882074637176893404" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/5882074637176893404" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/07/contributing-to-rails-is-easier-than.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-7138014355572897317</id><published>2008-06-10T09:34:00.003-05:00</published><updated>2008-06-10T09:41:13.262-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="otherinbox" /><category scheme="http://www.blogger.com/atom/ns#" term="deployment" /><category scheme="http://www.blogger.com/atom/ns#" term="lone star ruby conference" /><category scheme="http://www.blogger.com/atom/ns#" term="god.rb" /><category scheme="http://www.blogger.com/atom/ns#" term="conferences" /><title type="text">Speaking at Lone Star Ruby Conference</title><content type="html">I will be speaking at the &lt;a href="http://lonestarrubyconf.com/"&gt;Lone Star Ruby Conference&lt;/a&gt; in September about how we use Ruby to deploy, monitor, and manage a cluster of servers running in the &lt;a href="http://aws.amazon.com/"&gt;Amazon Web Services&lt;/a&gt; virtual cloud.   Below is a summary of what I'll be talking about.&lt;br /&gt;&lt;br /&gt;In OtherInbox, almost every system administration task imaginable is carried out using Ruby, meaning we as developers can enjoy all of Ruby's expressive benefits and spend less time scripting the shell, writing cron tasks, or using other languages.  Because we make fewer context switches from thinking in Ruby to thinking in other languages, we also reap a big productivity benefit.&lt;br /&gt;&lt;br /&gt;Using Ruby throughout our cloud also means that porting the application to run in different production environments is a trivial task, because Ruby is the glue connecting the Ruby components together, thus all we require is a Ruby interpreter to deploy.&lt;br /&gt;&lt;br /&gt;Two key Ruby technologies have matured in the previous 18 months which make it ideal for almost every layer of managing a cluster of servers:&lt;ul&gt;&lt;li&gt;&lt;a href="http://god.rubyforge.org/"&gt;god.rb&lt;/a&gt; allows fine-grained process monitoring and daemon control (a la &lt;a href="http://www.tildeslash.com/monit/"&gt;monit&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="http://rufus.rubyforge.org/rufus-scheduler/files/README_txt.html"&gt;rufus-scheduler&lt;/a&gt; enables Ruby-based scheduling (replacing cron, and providing a great facility for running daemons that must be executed on a recurring basis)&lt;/li&gt;&lt;/ul&gt;When combined with these Ruby workhorses, developers today can spend much more of their time writing Ruby code, and less time struggling with the vagaries of their production environment:&lt;ul&gt;&lt;li&gt;Ruby &lt;a href="http://www.ruby-doc.org/stdlib/"&gt;standard library&lt;/a&gt; utilities (File, FileUtils, etc.)&lt;/li&gt;&lt;li&gt;&lt;a href="http://rake.rubyforge.org/"&gt;Rake&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.capify.org/"&gt;Capistrano&lt;/a&gt; (for any kind of remote application, not just Rails)&lt;/li&gt;&lt;/ul&gt;The talk will also include a discussion of using several different &lt;a href="http://aws.amazon.com/"&gt;AWS&lt;/a&gt; gems to make &lt;a href="http://en.wikipedia.org/wiki/Cloud_computing"&gt;cloud computing&lt;/a&gt; simple, by illustrating the use of Amazon's &lt;a href="http://aws.amazon.com/s3"&gt;S3&lt;/a&gt; and &lt;a href="http://www.amazon.com/Simple-Queue-Service-home-page/b?ie=UTF8&amp;amp;node=13584001"&gt;SQS&lt;/a&gt; services to distribute asychnronous work and handle communication between servers.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;(cross-posted from the &lt;/span&gt;&lt;a href="http://blog.otherinbox.com/"&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;OtherInbox blog&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/308874720" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/308874720/i-will-be-speaking-at-lone-star-ruby.html" title="Speaking at Lone Star Ruby Conference" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=7138014355572897317" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/7138014355572897317" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/7138014355572897317" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/06/i-will-be-speaking-at-lone-star-ruby.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-437172103165556069</id><published>2008-06-06T22:26:00.002-05:00</published><updated>2008-06-06T22:34:49.221-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="random_data" /><title type="text">random_data v1.3.1 released</title><content type="html">&lt;a href="http://random-data.rubyforge.org/"&gt;random_data&lt;/a&gt; v1.3.1 is out.  Courtesy of stalwart contributor Hugh Sasse, this release includes more firstnames, and two new methods: &lt;a href="http://random-data.rubyforge.org/classes/RandomData/Names.html#M000005"&gt;Random.firstname_male&lt;/a&gt; and &lt;a href="http://random-data.rubyforge.org/classes/RandomData/Names.html#M000006"&gt;Random.firstname_female&lt;/a&gt;. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Install it via:&lt;/div&gt;&lt;pre class="textmate-source"&gt;sudo gem install random_data&lt;/pre&gt;&lt;div&gt;or get it &lt;a href="http://rubyforge.org/projects/random-data/"&gt;manually&lt;/a&gt;.&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/306551486" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/306551486/randomdata-v131-released.html" title="random_data v1.3.1 released" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=437172103165556069" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/437172103165556069" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/437172103165556069" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/06/randomdata-v131-released.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-6144208641877455392</id><published>2008-06-02T17:52:00.003-05:00</published><updated>2008-06-02T17:59:33.914-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="otherinbox" /><category scheme="http://www.blogger.com/atom/ns#" term="railsconf" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">RailsConf 2008 Recap</title><content type="html">I wrote up a few articles on the &lt;a href="http://blog.otherinbox.com/"&gt;OtherInbox blog&lt;/a&gt; about my experiences at RailsConf 2008:&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://blog.otherinbox.com/2008/05/railsconf-2008.html"&gt;Friday recap&lt;/a&gt; (where I got to meet Geoffrey Grosenbach and sign some books)&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.otherinbox.com/2008/06/railsconf-2008.html"&gt;Saturday recap&lt;/a&gt; (where things get technical)&lt;/li&gt;&lt;li&gt;&lt;a href="http://blog.otherinbox.com/2008/06/railsconf-birds.html"&gt;Birds-of-a-Feather session recap&lt;/a&gt; (where I get to talk with cool people)&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;The best blow-by-blow coverage so far is from &lt;a href="http://drewblas.com/"&gt;Drew Blas&lt;/a&gt;.  Of the ones I attended or heard the best feedback about, I most strongly recommend looking at the slides for these: &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://assets.en.oreilly.com/1/event/6/Surviving%20the%20Big%20Rewrite_%20Moving%20YELLOWPAGES_COM%20to%20Rails%20Presentation%201.pdf"&gt;Surviving the Big Rewrite&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.dcmanges.com/blog/railsconf-08-slides-for-testing-talk"&gt;Fast, Sexy, and Svelte: Our Kind of Testing&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.oreilly.com/rails2008/public/schedule/detail/1962"&gt;Refactoring Your Rails Application&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.oreilly.com/rails2008/public/schedule/detail/2072"&gt;CI for the Rails Guy (or Gal)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Facebook Development on Rails (no slides posted yet)&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/303295706" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/303295706/railsconf-2008-recap.html" title="RailsConf 2008 Recap" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=6144208641877455392" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/6144208641877455392" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/6144208641877455392" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/06/railsconf-2008-recap.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-5740271077106696099</id><published>2008-05-28T08:21:00.004-05:00</published><updated>2008-05-28T08:29:02.320-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">See you at Railsconf 2008</title><content type="html">I'll be leading two Birds of a Feather sessions at &lt;a href="http://en.oreilly.com/rails2008/"&gt;RailsConf 2008&lt;/a&gt; that I hope everyone will attend (or flock to):&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.oreilly.com/rails2008/public/schedule/detail/4368"&gt;Presenter Classes and the Power of Abstraction&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.oreilly.com/rails2008/public/schedule/detail/4367"&gt;Rails and Amazon Web Services&lt;/a&gt; &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;I was also invited to sign copies of the book &lt;a href="http://www.pragprog.com/titles/fr_arr/advanced-rails-recipes"&gt;Advanced Rails Recipes&lt;/a&gt; (to which I contributed a couple of recipes) at &lt;a href="http://www.powells.com/"&gt;Powell's books&lt;/a&gt; in Portland on May 30th at 12:30 pm.  Hope to see you there!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'll be there with the full &lt;a href="http://www.otherinbox.com/"&gt;OtherInbox&lt;/a&gt; contingent, so if you're looking for an awesome startup to join, come and track us down.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/299852925" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/299852925/see-you-at-railsconf-2008.html" title="See you at Railsconf 2008" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=5740271077106696099" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/5740271077106696099" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/5740271077106696099" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/05/see-you-at-railsconf-2008.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-4326383836973444697</id><published>2008-05-25T12:09:00.002-05:00</published><updated>2008-05-25T12:16:22.919-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="random_data" /><title type="text">random_data v1.3.0 released</title><content type="html">&lt;a href="http://random-data.rubyforge.org/"&gt;random_data&lt;/a&gt; is a testing and seed data gem I wrote a few years back to help get Ruby projects up and running with semi-realistic fake data (the &lt;a href="http://faker.rubyforge.org/"&gt;faker&lt;/a&gt; gem provides similar functionality).&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I just released version 1.3.0 which includes a bunch of RDoc enhancements as well as some new features contributed by the tireless (and patient!) Hugh Sasse:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Added RandomData::Grammar, which lets you create simple random sentences from a grammar supplied as a hash, like so:&lt;br /&gt;&lt;pre class="textmate-source"&gt;&lt;span class="text text_plain"&gt;&lt;span class="meta meta_paragraph meta_paragraph_text"&gt;Random::grammatical_construct({:story =&amp;gt; [:man, " bites ", :dog], :man =&amp;gt; { :bob =&amp;gt; "Bob"}, :dog =&amp;gt; {:a =&amp;gt;"Rex", :b =&amp;gt;"Rover"}}, :story)&lt;br /&gt;==&gt; "Bob bites Rex"&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Added Random.bit and Random.bits&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Added Random.uk_post_code&lt;/li&gt;&lt;li&gt;Bug fix: zipcodes should strings, not integers&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Thanks Hugh!  Open source is awesome!&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737152" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737152/randomdata-v130-released.html" title="random_data v1.3.0 released" /><link rel="related" href="http://random-data.rubyforge.org/" title="random_data v1.3.0 released" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=4326383836973444697" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/4326383836973444697" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/4326383836973444697" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/05/randomdata-v130-released.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-2494596248892007071</id><published>2008-05-25T11:10:00.005-05:00</published><updated>2008-05-25T11:17:43.701-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">Using Ruby's Autoload Method To Configure Your App Just-in-Time</title><content type="html">&lt;div&gt;Reading &lt;a href="http://www.amazon.com/Ruby-Programming-Language-David-Flanagan/dp/0596516177"&gt;The Ruby Programming Language&lt;/a&gt; was a great experience — like revisiting a country I thought I knew intimately, but with expert tour guides who showed me whole new landscapes.  It's also a good primer on what's changing in Ruby 1.9.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;One of my favorite discoveries was Ruby's &lt;a href="http://www.ruby-doc.org/core/classes/Kernel.html#M005968"&gt;autoload&lt;/a&gt; method.  Using autoload, you can associate a constant with a filename to be loaded the first time that constant is referenced, like so:&lt;/div&gt;&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;autoload &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;BCrypt&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;bcrypt&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;autoload &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;Digest&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;digest/sha2&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div&gt;The first time the interpreter encounters the constant BCrypt, it will load the file 'bcrypt' from Ruby's current load path, which it assumes will contain the definition of that constant.  (Note that autoload takes the name of the constant, in symbol form, not the constant itself).&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Here's an example of how useful it can be. &lt;a href="http://www.otherinbox.com/"&gt;OtherInbox&lt;/a&gt; uses &lt;a href="http://xph.us/software/beanstalkd/"&gt;beanstalkd&lt;/a&gt; in a few places where we haven't yet migrated to &lt;a href="http://www.amazon.com/Simple-Queue-Service-home-page/b?ie=UTF8&amp;amp;node=13584001"&gt;SQS&lt;/a&gt;.  I was loading the &lt;a href="http://beanstalk.rubyforge.org/"&gt;beanstalk client&lt;/a&gt; with a Rails initializer, 'config/initializers/beanstalk.rb':&lt;/div&gt;&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;beanstalk-client&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;BEANSTALK&lt;/span&gt; &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;Beanstalk&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Pool&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;[&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;localhost:11300&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby"&gt;]&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div&gt;Making this initial connection on our production server takes five seconds or more each time I restarted the app or dropped into the console.  That doesn't sound like much but when you're doing that a few times a day, it starts to add up.  So I moved the beanstalk code out of the initializer and into 'lib/etc/load_beanstalk.rb'.  I placed all of my autoloads in a single initializer, 'config/initializers/autoload.rb'.  For beanstalk, the statement is:&lt;/div&gt;&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;autoload &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;BEANSTALK&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;etc/load_beanstalk&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div&gt;Now, the app starts more quickly, and even better, this library doesn't get loaded into memory by parts of the app that don't need it.&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737153" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737153/using-rubys-autoload-method-to.html" title="Using Ruby's Autoload Method To Configure Your App Just-in-Time" /><link rel="related" href="http://www.ruby-doc.org/core/classes/Kernel.html#M005968" title="Using Ruby's Autoload Method To Configure Your App Just-in-Time" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=2494596248892007071" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/2494596248892007071" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/2494596248892007071" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/05/using-rubys-autoload-method-to.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-1858535346601608681</id><published>2008-05-21T15:02:00.003-05:00</published><updated>2008-05-21T21:08:48.666-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="databases" /><category scheme="http://www.blogger.com/atom/ns#" term="otherinbox" /><category scheme="http://www.blogger.com/atom/ns#" term="mysql" /><category scheme="http://www.blogger.com/atom/ns#" term="optimization" /><title type="text">ORDER BY null kills MySQL filesorts dead</title><content type="html">I spent some time today optimizing &lt;a href="http://otherinbox.com/"&gt;OtherInbox&lt;/a&gt;.  As our private beta expands, we are starting to see heavier usage, and so it's time to revisit some of my beloved SQL queries.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I use the &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/slow-query-log.html"&gt;MySQL slow query log&lt;/a&gt; to find out which queries were taking the most time -- that's been a wonderful tool that I plan to blog about later.  I will note that the output is much easier to make sense of if you parse it first with &lt;a href="http://www.retards.org/projects/mysql/"&gt;this script&lt;/a&gt;.  (It's really old, so I had to modify it to look at Query_time instead of Time)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Using the &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/using-explain.html"&gt;EXPLAIN&lt;/a&gt; command for each of the slow queries identified in the above log, I found one that was especially disturbing.   According to EXPLAIN's "extra" column, MySQL was resolving these queries with two fairly expensive operations: &lt;/div&gt;&lt;pre class='textmate-source'&gt;Using where; Using temporary; Using filesort&lt;/pre&gt;Fixing the "Using temporary" required some nimble manipulation of indices, but filesort was really perplexing me.  I wasn't using an ORDER BY clause, so as I read &lt;a href="http://dev.mysql.com/doc/refman/5.0/en/order-by-optimization.html"&gt;the docs&lt;/a&gt;, there was no reason to be doing a filesort.  But then I remembered that MySQL automatically does ordering based on GROUP BY clauses.  All I had to do was add "ORDER BY null" to the end of my query, and that did the trick:&lt;/div&gt;&lt;pre class='textmate-source'&gt;Using where; Using temporary&lt;/pre&gt;&lt;div&gt;If only all optimizations were so simple.&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737154" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737154/order-by-null-kills-mysql-filesorts.html" title="ORDER BY null kills MySQL filesorts dead" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=1858535346601608681" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/1858535346601608681" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/1858535346601608681" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/05/order-by-null-kills-mysql-filesorts.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-616149576619295261</id><published>2008-05-14T10:14:00.002-05:00</published><updated>2008-05-14T10:17:55.502-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="festival" /><category scheme="http://www.blogger.com/atom/ns#" term="improv" /><title type="text">Applications due for Baltimore Improv Festival 2008</title><content type="html">We have a formal application process for this year's Baltimore Improv Festival taking place in August.  &lt;a href="http://baltimoreimprovfestival.org/"&gt;Submissions are due May 23rd&lt;/a&gt;.  We'd like to get as diverse a pool of performers from all over the country as we can.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On a related note, &lt;a href="http://bigimprov.org/"&gt;BIG&lt;/a&gt; has been accepted into &lt;a href="http://artscape.org/"&gt;Artscape&lt;/a&gt; to perform on the Saturday night show (7/19)  along with the Mimehunters.  See you there!&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737155" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737155/applications-due-for-baltimore-improv.html" title="Applications due for Baltimore Improv Festival 2008" /><link rel="related" href="http://baltimoreimprovfestival.org/" title="Applications due for Baltimore Improv Festival 2008" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=616149576619295261" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/616149576619295261" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/616149576619295261" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/05/applications-due-for-baltimore-improv.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-2893882269922410821</id><published>2008-05-12T12:08:00.003-05:00</published><updated>2008-05-12T12:19:32.271-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="social media" /><category scheme="http://www.blogger.com/atom/ns#" term="startups" /><title type="text">SocialDevCampEast recap</title><content type="html">&lt;a href="http://barcamp.pbwiki.com/SocialDevCampEast"&gt;SocialDevCampEast&lt;/a&gt; on Saturday was a blast.  Lots of talk about building up the "Amtrak corridor" running from DC to Boston as one unified, tech-ified region.  The talks people gave were interesting (I even got to do one on my experiences with Amazon Web Services), but for me the most valuable experiences took place in between sessions and at the after-party held at Brewer's Art.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I met several cool DC, MD, and VA entrepreneurs which was really invigorating.  I found out about some new blogs that I need to be reading, including &lt;a href="http://eastcoastblogging.com/"&gt;eastcoastblogging.com&lt;/a&gt;, written by the creator of the newly-launched &lt;a href="http://mydropbin.com/myDropBin/"&gt;MyDropBin.com&lt;/a&gt;. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I also saw first-hand the value of Twitter, which I'm very late to the party on.  I don't know that many people in my own circle who were using it, but after seeing how it was fostering the collaboration among people in the conference environment, I'm sold, especially if you have something client-side that checks tweets for you (my friend Brian Lyles aka &lt;a href="http://smartic.us/"&gt;Smarticus&lt;/a&gt; recommended &lt;a href="http://iconfactory.com/software/twitterrific"&gt;Twitterific&lt;/a&gt;, which works great).  So you can now catch me &lt;a href="http://twitter.com/subelsky/"&gt;@subelsky&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thanks to the sponsors and organizers for a great event; I'll be at the next one for sure.&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737156" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737156/socialdevcampeast-recap.html" title="SocialDevCampEast recap" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=2893882269922410821" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/2893882269922410821" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/2893882269922410821" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/05/socialdevcampeast-recap.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-7881807098412486661</id><published>2008-05-06T09:11:00.004-05:00</published><updated>2008-05-06T09:31:31.284-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="baltimore" /><category scheme="http://www.blogger.com/atom/ns#" term="startups" /><title type="text">Startup community in Baltimore</title><content type="html">&lt;p&gt;I just found about a very interesting Barcamp called &lt;a href="http://barcamp.pbwiki.com/SocialDevCampEast"&gt;SocialDevCamp East&lt;/a&gt; planned in Baltimore on Saturday, just a few miles south of my house.    It's very heartening to see enthusiasm building for a &lt;a href="http://davetroy.blogspot.com/2008/04/building-tech-startups-on-east-coast.html"&gt;tech community here on the east coast&lt;/a&gt; and this has gotten me thinking about the Baltimore startup community in general.  Below are some notes on startup life in Baltimore.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Here are some Baltimore startups I know about:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &lt;ul&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://cogmap.com/"&gt;http://cogmap.com&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://fetchfood.com/"&gt;http://fetchfood.com&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://twittervision.com/"&gt;http://twittervision.com&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;&lt;a href="http://600block.com/"&gt;http://600block.com&lt;/a&gt;&lt;/li&gt;&lt;br /&gt; &lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I'm sure there are more; send me some and I'll add them to the list.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;I've talked to many other Baltimore entrepreneurs with ideas in various stages of development, and there are lots of hackers here working remotely (or commuting to DC and Northern Virginia) on startups.   We're also the home of &lt;a href="http://advertising.com/"&gt;advertising.com&lt;/a&gt; which employs a lot of smart people and brings a lot of talent to the area.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;I meet a lot of cool hackers through the &lt;a href="http://ruby.meetup.com/85/"&gt;local Ruby on Rails meetup&lt;/a&gt;.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;One of my favorite blogs is written by a Baltimorean, &lt;a href="http://paulbarry.com/"&gt;Paul Barry&lt;/a&gt;. He's a Ruby on Rails expert, but has in no way drunk the Kool Aid. He's got plenty of love for Java and Scala and whatever else gets the job done.&lt;/li&gt;&lt;br /&gt;&lt;br /&gt;&lt;li&gt;I've been dreaming for awhile about organizing a "Baltimore Demo Night" where all of us could gather and show off our wares, get feedback, and so on.  Who's down for that?&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737157" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737157/startup-community-in-baltimore.html" title="Startup community in Baltimore" /><link rel="related" href="http://barcamp.pbwiki.com/SocialDevCampEast" title="Startup community in Baltimore" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=7881807098412486661" title="2 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/7881807098412486661" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/7881807098412486661" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/05/startup-community-in-baltimore.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-2773893711366624537</id><published>2008-05-06T07:53:00.002-05:00</published><updated>2008-05-06T07:57:03.209-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">Advanced Rails Recipes out now</title><content type="html">I contributed two recipes to the newly-released &lt;a href="http://www.pragprog.com/titles/fr_arr/advanced-rails-recipes"&gt;Advanced Rails Recipes&lt;/a&gt; which I highly recommend.  It's got 84 very eye-opening solutions to problems faced by a lot of Rails programmers.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I feel lucky to be working with cool, open technology that's yielded an opportunity to be part of a project like this.&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737158" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737158/advanced-rails-recipes-out-now.html" title="Advanced Rails Recipes out now" /><link rel="related" href="http://www.pragprog.com/titles/fr_arr/advanced-rails-recipes" title="Advanced Rails Recipes out now" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=2773893711366624537" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/2773893711366624537" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/2773893711366624537" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/05/advanced-rails-recipes-out-now.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-7886555936747095061</id><published>2008-05-01T08:00:00.004-05:00</published><updated>2008-05-01T08:14:24.130-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="otherinbox" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">Looking for Rails developers (who isn't?)</title><content type="html">For the past seven months I've been building a cool new consumer web app with some folks in Austin, TX, &lt;a href="http://otherinbox.com/"&gt;otherinbox.com/&lt;/a&gt;, and we're looking for experienced Ruby On Rails developers. We're a small agile team led by Steven Smith, founder of &lt;a href="http://fiveruns.com/"&gt;FiveRuns&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;The whole site is Rails-based and makes extensive use of Amazon Web Services (EC2, S3, and SQS) and there's a new awesome challenge every day.  More info on our &lt;a href="http://www.otherinbox.com/jobs"&gt;jobs&lt;/a&gt; page.&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737159" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737159/looking-for-rails-developers-who-isnt.html" title="Looking for Rails developers (who isn't?)" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=7886555936747095061" title="1 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/7886555936747095061" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/7886555936747095061" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/05/looking-for-rails-developers-who-isnt.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-4097077743977659605</id><published>2008-03-23T16:59:00.002-05:00</published><updated>2008-03-23T17:02:18.775-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">Great explanation of Rails auto-loading</title><content type="html">I thought Mark Bush did a great job of explaining Rails' auto-loading behavior on the &lt;a href="http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/662abfd1df9b2612?hl=en"&gt;Rails-talk mailing list&lt;/a&gt;.  I'm posting it here to help others find it, and so I remember where to find it next time I'm struggling with it.  I've known that Rails automatically requires and loads classes on the fly using standard conventions for module names -&gt; file names, but I had a hard time grasping how it worked.  Mark explains it very concisely.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Rails list has a low signal-to-noise ratio but it's still worth paying attention to for gems like this.&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737160" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737160/great-explanation-of-rails-auto-loading.html" title="Great explanation of Rails auto-loading" /><link rel="related" href="http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/662abfd1df9b2612?hl=en" title="Great explanation of Rails auto-loading" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=4097077743977659605" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/4097077743977659605" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/4097077743977659605" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/03/great-explanation-of-rails-auto-loading.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-4197757480557459978</id><published>2008-03-15T11:55:00.006-05:00</published><updated>2008-03-15T12:32:04.234-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><title type="text">Using stunnel to wrap Ruby network operations on the fly</title><content type="html">In my current project, we need to be able to connect to POP3 servers.  Some POP3 servers, such as Gmail, only allow SSL connections.  Unfortunately, the &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/net/pop/rdoc/index.html"&gt;Ruby 1.8.x net/pop library&lt;/a&gt; doesn't support SSL (although the 1.9 library does, but that was not an option for us in this project).&lt;br /&gt;&lt;br /&gt;The usual answer here is to wrap your connection using &lt;a href="http://www.stunnel.org/"&gt;stunnel&lt;/a&gt;, which acts as an SSL proxy for whatever traffic you want to send over it.  Usually you run stunnel as a separate service pointing at the server, but since we'll be connecting to many different POP servers, I needed to be able to set up and tear down stunnels on the fly.  The first attempt looked something like this:&lt;br /&gt;&lt;pre class="textmate-source"&gt;system("echo -e 'foreground = yes\npid =\n[mail]\nclient = yes\n \&lt;br /&gt;      accept = 127.0.0.1:2000\nconnect = #{server}:#{port}\n'  \&lt;br /&gt;      | stunnel -fd 0") &lt;/pre&gt;Since stunnel doesn't accept command-line options, you have to pipe options to it.  The "fd -0" tells stunnel to read its configuration from file descriptor 0, better known as STDIN.&lt;br /&gt;&lt;br /&gt;Since I need to run that command in a child process, then have the parent resume and make use of the child service, I embarked on a fun foray of Ruby's forking and threading capabilities.&lt;br /&gt;&lt;br /&gt;First, I tried &lt;span style="font-family:monospace;"&gt;forking&lt;/span&gt;, replacing the child process with a call to &lt;span style="font-family:monospace;"&gt;exec&lt;/span&gt; instead of &lt;span style="font-family:monospace;"&gt;system&lt;/span&gt;, then detaching the parent and killing the child process when the POP session was done.  This partially worked, but I couldn't figure out how to kill the child process, so I'd end up with multiple copies of stunnel running after the script ran, or the parent process itself would hang.&lt;br /&gt;&lt;br /&gt;Looking through the Pickaxe chapter on &lt;a href="http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_threads.html"&gt;threads and processes&lt;/a&gt;, I discovered &lt;a href="http://www.ruby-doc.org/core/classes/IO.html#M002267"&gt;IO.popen&lt;/a&gt;, which works perfectly.  I can pipe input to STDIN, avoiding the ugliness of the "echo -e" above, and I can more easily kill the child process when I'm done.&lt;br /&gt;&lt;br /&gt;This is what the final method looks like:&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;stunnel_wrap(server, port)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;stunnel &lt;span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby"&gt;=&lt;/span&gt; &lt;span class="support support_class support_class_ruby"&gt;IO&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;popen&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;stunnel -fd 0&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;w+&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;stunnel&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;puts&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;foreground = yes&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\n&lt;/span&gt;pid =&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\n&lt;/span&gt;[mail]&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\n&lt;/span&gt;client = yes&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\n&lt;/span&gt; \&lt;br /&gt;              accept = 127.0.0.1:2000\nconnect = &lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;server&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;:&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;port&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\&lt;/span&gt;&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;n&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;stunnel&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;close_write&lt;br /&gt;&lt;span class="support support_class support_class_ruby"&gt; Kernel&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;sleep&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby"&gt; yield&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;ensure&lt;/span&gt;&lt;br /&gt;&lt;span class="support support_class support_class_ruby"&gt;Process&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;kill&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;9&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt;stunnel&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;pid&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;I handle exceptions at a higher layer in this class, so here all I do is make sure the stunnel process gets killed no matter what.  I'm not sure if the sleep call is needed, but when I was testing this with Gmail it seemed to help to wait one second for the tunnel to activate before trying to use it.&lt;br /&gt;&lt;br /&gt;To make the above example work, you just need to point your POP client at the stunnel (in this case 127.0.0.1 port 2000) and you'll be talking SSL to the server.&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;stunnel_wrap&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;pop.gmail.com&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;995&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do&lt;br /&gt;&lt;/span&gt;  &lt;span class="support support_class support_class_ruby"&gt;Net&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby"&gt;::&lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;POP3&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;start&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;127.0.0.1&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;2000&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; account&lt;span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby"&gt;,&lt;/span&gt; password&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;pop&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;br /&gt;&lt;span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"&gt;    &lt;span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby"&gt;#&lt;/span&gt; pop securely&lt;br /&gt;&lt;/span&gt;  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737161" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737161/using-stunnel-to-wrap-ruby-network.html" title="Using stunnel to wrap Ruby network operations on the fly" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=4197757480557459978" title="1 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/4197757480557459978" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/4197757480557459978" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/03/using-stunnel-to-wrap-ruby-network.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-35761530206691527</id><published>2008-02-18T15:25:00.003-05:00</published><updated>2008-02-18T15:43:06.358-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="rspec" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="testing" /><title type="text">ActiveRecord Double Validation Errors in RSpec</title><content type="html">I had a strange error occur in one of my rspec model unit tests today, and I wanted to document it here because my solution (which is a bit of a hack) is the opposite of what worked for other people.&lt;br /&gt;&lt;br /&gt;I have a bunch of tests that check to make sure I'm validating various properties of a model.  All of a sudden, I started having tests fail because the validations seemed to be adding the same error twice.&lt;pre class="textmate-source"&gt;'User creation should require domain names to be unique' FAILED&lt;br /&gt;expected 1 error on :domain, got 2&lt;br /&gt;&lt;/pre&gt;This error only occured when my full suite of tests ran.  If I ran the unit test by itself (or even if I just ran only the model tests by themselves), it didn't happen.  Unfortunately I didn't notice whatever it was I did to introduce this error, so I couldn't reverse it.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Several other people have encountered this problem, so I know it's because my tests are leaking state in some way.  Somehow I am doing something during my tests that rspec isn't able to clean up.  Usually it's because the tests are doing something weird with extra require or load statements, which causes multiple copies of the class to be loaded.  Removing these statements usually works.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had no such statements and so spent a while trying to sort this out.  On a whim, I added a require statement to the top of the failing User model spec, and that fixed it:&lt;/div&gt;&lt;pre class="textmate-source"&gt;require 'user'&lt;/pre&gt;I wish I had more time to investigate, because it makes me thing I don't know enough about Rails autoloading behavior, or Ruby's loading behavior. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you're running into this same problem, I found these mailing lists threads to be useful:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/a848f697dd7eba61"&gt;http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/a848f697dd7eba61&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.railsforum.com/viewtopic.php?pid=51214"&gt;http://www.railsforum.com/viewtopic.php?pid=51214&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.ruby-forum.com/topic/131855"&gt;http://www.ruby-forum.com/topic/131855&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://rubyforge.org/pipermail/rspec-users/2007-October/003866.html"&gt;http://rubyforge.org/pipermail/rspec-users/2007-October/003866.html&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737162" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737162/activerecord-double-validation-errors.html" title="ActiveRecord Double Validation Errors in RSpec" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=35761530206691527" title="1 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/35761530206691527" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/35761530206691527" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/02/activerecord-double-validation-errors.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-282266858439734189</id><published>2008-02-12T09:02:00.000-05:00</published><updated>2008-02-12T09:42:17.924-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="firefox" /><category scheme="http://www.blogger.com/atom/ns#" term="Javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">Unobtrusive Firefox Plugin Click-to-Install</title><content type="html">&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;I've been working on a really cool new project, to be announced soon, where I've built a Rails-based web app that has two interfaces: one for humans to interact with inside of a browser, and a &lt;a href="http://en.wikipedia.org/wiki/REST"&gt;RESTful&lt;/a&gt; API for browser plugins to interact with via GETs and POSTs.  We want people to be able to interact with our site while visiting other sites.&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;I had seen other Firefox plugins that were click-to-install, but I had a hard time figuring out how to make it work for our plugin. Firefox users were having to "Save Link As.." and open the downloaded .xpi file manually.  Very old-fashioned.  So here's a quick note to help future Mozilla or Firefox developers who need to create a click-to-install plugin:&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;1) It's all done through Javascript, so anyone without Javascript will have to install your plugin the old-fashioned way.  The Mozilla site documents &lt;a href="http://developer.mozilla.org/en/docs/XPInstall_API_Reference:InstallTrigger_Object"&gt;the API call you need to make&lt;/a&gt;.&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;2) I'm a huge proponent of unobtrusive javascript (UJS), which I learned by using Dan Webb's excellent &lt;a href="http://www.danwebb.net/2006/9/3/low-pro-unobtrusive-scripting-for-prototype"&gt;LowPro framework&lt;/a&gt;. Thus I wanted to make sure that the click-to-install javascript was offered as a progressive enhancement to the normal HTML links we provided.  That way, everyone could have a link to the plugin file itself for manual installation, but people with Javascript could enjoy click-to-install.&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica"&gt;In this part of the site, we weren't using any other Javascript libraries, so it seemed like overkill to include Prototype and LowPro just for this one effect.  So it was a great chance to learn how to roll my own UJS without library support.  I whipped up a quick UJS click-to-install technique following inspiration from &lt;a href="http://adactio.com/atmedia2005/"&gt;this presentation&lt;/a&gt;.  Here's what I came up with:&lt;/p&gt;&lt;pre class="textmate-source"&gt;&amp;lt;script defer="defer" type="text/javascript"&amp;gt;&lt;br /&gt;//&amp;lt;![CDATA[&lt;br /&gt;function doXPITrigger() {&lt;br /&gt;if (!document.getElementsByTagName) return false;&lt;br /&gt;var links = document.getElementsByTagName("a");&lt;br /&gt;for (var i=0; i &amp;lt; links.length; i++) {&lt;br /&gt; if (links[i].className.match("firefox")) {&lt;br /&gt;   links[i].onclick = function() {&lt;br /&gt;  xpi={'Awesome New Project Toolbar':'/downloads/awesome_project.xpi'};&lt;br /&gt;  InstallTrigger.install(xpi);&lt;br /&gt;     return false;&lt;br /&gt;   }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;window.onload = doXPITrigger&lt;br /&gt;//]]&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;P&gt;3) I've seen other advice recommending you configure your web server to recognize the .xpi mimetype appropriately.  I did this but it didn't make much difference in my case.  Still, it's probably worth doing.  I added this line to our Apache config:&lt;/p&gt;&lt;br /&gt;&lt;pre class="textmate-source"&gt;AddType application/x-xpinstall .xpi&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737163" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737163/unobtrusive-firefox-plugin-click-to.html" title="Unobtrusive Firefox Plugin Click-to-Install" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=282266858439734189" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/282266858439734189" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/282266858439734189" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/02/unobtrusive-firefox-plugin-click-to.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-5148538449870455834</id><published>2008-01-23T15:04:00.000-05:00</published><updated>2008-01-23T15:10:19.086-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="autotest" /><category scheme="http://www.blogger.com/atom/ns#" term="testing" /><title type="text">Shout out to Rails Envy &amp; More Autotest Love</title><content type="html">Thanks to the &lt;a href="http://www.railsenvy.com/2008/1/23/rails-envy-podcast-episode-015-1-23-2008"&gt;Rails Envy Podcast&lt;/a&gt; for mentioning my note on autotest configuration.  Another aspect I enjoy about using the verbose flag is that autotest tells you exactly what has triggered the re-test.  Kind of a fun way to look under the hood of your testing system:&lt;br /&gt;&lt;pre class="textmate-source"&gt;[["app/controllers/admin/users_controller.rb", Wed Jan 23 14:06:10 -0600 2008]]&lt;br /&gt;/usr/local/bin/ruby -S script/spec -O spec/spec.opts  spec/controllers/other_inboxes_controller_spec.rb spec/controllers/admin/users_controller_spec.rb&lt;br /&gt;&lt;/pre&gt;If you like that, you might also be interested in the autotest timestamp plugin, which stamps autotest runs like so:&lt;br /&gt;&lt;pre class="textmate-source"&gt;# Waiting at 2008-01-23 14:06:17&lt;br /&gt;&lt;/pre&gt;All you have to do is uncomment this line in your ~/.autotest file:&lt;br /&gt;&lt;pre class="textmate-source"&gt;require 'autotest/timestamp'&lt;br /&gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737164" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737164/shout-out-to-rails-envy-more-autotest.html" title="Shout out to Rails Envy &amp; More Autotest Love" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=5148538449870455834" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/5148538449870455834" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/5148538449870455834" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/01/shout-out-to-rails-envy-more-autotest.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-3452629994397315639</id><published>2008-01-16T12:54:00.000-05:00</published><updated>2008-01-16T13:08:52.599-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="rspec" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="autotest" /><category scheme="http://www.blogger.com/atom/ns#" term="testing" /><title type="text">Autotest with verbose flag on</title><content type="html">I followed a tip from &lt;a href="http://blog.davidchelimsky.net/"&gt;David Chelimsky's blog&lt;/a&gt; and began running autotest with the -v flag for verbosity.  When you first run it, you get a bunch of lines like this: &lt;pre class="textmate-source"&gt;Dunno! spec/other_inbox_spec_helpers.rb&lt;br /&gt;Dunno! app/views/layouts/main/_footer.erb&lt;br /&gt;&lt;/pre&gt;Which show all the files for which autotest doesn't have a mapping.  With &lt;a href="http://blog.zenspider.com/archives/2008/01/zentest_version_380_has_been_released.html"&gt;ZenTest 3.8.0&lt;/a&gt; out, it's easy to add mappings (which tell autotest which tests to run when a matching file changes) and exceptions (which tell autotest which files to ignore).  You can also set up .autotest files for particular projects, or for your whole development machine (~/.autotest).&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here's an example of a per-project .autotest I use, sitting in the Rails root directory.  I've got a custom spec helper and I want to rerun all my tests if this file ever changes:&lt;/div&gt;&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;&lt;span class="support support_class support_class_ruby"&gt;Autotest&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;add_hook &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;initialize&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;at&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;br /&gt;&lt;span class="string string_quoted string_quoted_other string_quoted_other_literal string_quoted_other_literal_lower string_quoted_other_literal_lower_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%w{&lt;/span&gt; domain_regexp perfdata coverage reports &lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;exception&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt; at&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;add_exception&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;exception&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;at&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;add_mapping&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_regexp string_regexp_classic string_regexp_classic_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;spec&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\/&lt;/span&gt;app_spec_helper.rb&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;_&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;,&lt;/span&gt; &lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;m&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;br /&gt;at&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;files_matching &lt;span class="string string_regexp string_regexp_mod-r string_regexp_mod-r_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%r%&lt;/span&gt;^spec/&lt;span class="string string_regexp string_regexp_group string_regexp_group_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_group punctuation_definition_group_ruby"&gt;(&lt;/span&gt;controllers|helpers|lib|models|views&lt;span class="punctuation punctuation_definition punctuation_definition_group punctuation_definition_group_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;/.*&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\.&lt;/span&gt;rb$&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;%&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;And here's part of my site-wide .autotest file, mostly cribbed from David's blog, where I'm ignoring other kinds of cruft that pile up in projects.  Also note the mapping for spec/defaults.rb, a file I commonly setup in my specs containing default parameters for different models.&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;&lt;span class="support support_class support_class_ruby"&gt;Autotest&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;add_hook &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;initialize&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;at&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;br /&gt;&lt;span class="string string_quoted string_quoted_other string_quoted_other_literal string_quoted_other_literal_lower string_quoted_other_literal_lower_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%w{&lt;/span&gt;.hg .git .svn stories tmtags Rakefile Capfile README spec/spec.opts spec/rcov.opts vendor/gems autotest svn-commit .DS_Store &lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;each &lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;{&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;exception&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;at&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;add_exception&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;exception&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;at&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;add_mapping&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;(&lt;/span&gt;&lt;span class="string string_regexp string_regexp_classic string_regexp_classic_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;spec&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\/&lt;/span&gt;defaults.rb&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby"&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby"&gt;)&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby"&gt;do &lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;f&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;,&lt;/span&gt; &lt;span class="variable variable_other variable_other_block variable_other_block_ruby"&gt;_&lt;/span&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby"&gt;|&lt;/span&gt;&lt;br /&gt; at&lt;span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby"&gt;.&lt;/span&gt;files_matching &lt;span class="string string_regexp string_regexp_mod-r string_regexp_mod-r_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;%r%&lt;/span&gt;^spec/&lt;span class="string string_regexp string_regexp_group string_regexp_group_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_group punctuation_definition_group_ruby"&gt;(&lt;/span&gt;controllers|helpers|lib|models|views&lt;span class="punctuation punctuation_definition punctuation_definition_group punctuation_definition_group_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;/.*&lt;span class="constant constant_character constant_character_escape constant_character_escape_ruby"&gt;\.&lt;/span&gt;rb$&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;%&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737165" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737165/autotest-with-verbose-flag-on.html" title="Autotest with verbose flag on" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=3452629994397315639" title="2 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/3452629994397315639" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/3452629994397315639" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/01/autotest-with-verbose-flag-on.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-2516296522314989983</id><published>2008-01-08T08:50:00.000-05:00</published><updated>2008-01-08T09:35:57.451-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="presenters" /><title type="text">Presenter classes help with Rails complexity</title><content type="html">A few weeks back I gave a talk at a &lt;a href="http://ruby.meetup.com/85/"&gt;Bmore on Rails&lt;/a&gt; meeting all about Presenter classes, which I learned about from &lt;a href="http://blog.jayfields.com/"&gt;Jay Fields&lt;/a&gt;.  I can't claim any authorship of this idea, but it's been very helpful to me, so I thought I'd share some of my examples here plus a bit of extra code I wrote to make Presenter integration with ActiveRecord a bit more fun.&lt;div&gt;&lt;br /&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;Presenters allow you to extract the logic needed for complex views (especially views that require the use of more than one model) into a separate, easily testable class.  This helps you write clean code and &lt;a href="http://www.therailsway.com/2007/6/1/railsconf-recap-skinny-controllers"&gt;skinny controllers&lt;/a&gt;, among other benefits. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;div&gt;1) The key background material is here:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://martinfowler.com/eaaDev/ModelViewPresenter.html"&gt;http://martinfowler.com/eaaDev/ModelViewPresenter.html&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://blog.jayfields.com/2007/02/rails-presenters-additional-layer.html"&gt;http://blog.jayfields.com/2007/02/rails-presenters-additional-layer.html&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://blog.jayfields.com/2007/03/rails-presenter-pattern.html"&gt;http://blog.jayfields.com/2007/03/rails-presenter-pattern.html&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://blog.jayfields.com/2007/10/rails-rise-fall-and-potential-rebirth.html"&gt;http://blog.jayfields.com/2007/10/rails-rise-fall-and-potential-rebirth.html&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;2) I extended Jay Fields' code by adding methods to combine error messages from different models:&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://pastie.caboo.se/127573"&gt;http://pastie.caboo.se/127573&lt;/a&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;3) An example Presenter, combining a User object and an Account object into a Preference presenter, is here:&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://pastie.caboo.se/127575"&gt;http://pastie.caboo.se/127575&lt;/a&gt;&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;4) An example controller, using the Preference presenter, is here:&lt;/div&gt;&lt;div&gt; &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://pastie.caboo.se/127577"&gt;http://pastie.caboo.se/127577&lt;/a&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Also, Jay wrote an excellent recipe for &lt;a href="http://pragprog.com/titles/fr_arr"&gt;Advanced Rails Recipes&lt;/a&gt; that covers this technique.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737166" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737166/presenter-classes-help-with-rails.html" title="Presenter classes help with Rails complexity" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=2516296522314989983" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/2516296522314989983" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/2516296522314989983" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/01/presenter-classes-help-with-rails.html</feedburner:origLink></entry><entry><id>tag:blogger.com,1999:blog-6369418367411691447.post-3258606489050155681</id><published>2008-01-03T09:32:00.000-05:00</published><updated>2008-01-03T09:35:38.293-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="caching" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><title type="text">Dynamic Content Caching Recipe</title><content type="html">hello everyone,&lt;br /&gt;&lt;br /&gt;Pragmatic Programmers just released an updated beta version of &lt;a href="http://pragprog.com/titles/fr_arr"&gt;Advanced Rails Recipes&lt;/a&gt; which contains another recipe that I contributed, this one about dynamic content caching.  I've built a few sites that had a lot of static content, with only bit of dynamic content on each page (usually a signout button, or an admin link).  In these cases, I was able to use page caching with a little bit of Javascript that looks for a cookie in the client browser and alters the page accordingly.  The book is shaping up great and I'm learning a lot by reading other recipes, so definitely check it out!&lt;img src="http://feeds.feedburner.com/~r/subelskyblog/~4/298737167" height="1" width="1"/&gt;</content><link rel="alternate" type="text/html" href="http://feeds.feedburner.com/~r/subelskyblog/~3/298737167/dynamic-content-caching-recipe.html" title="Dynamic Content Caching Recipe" /><link rel="replies" type="text/html" href="http://www.blogger.com/comment.g?blogID=6369418367411691447&amp;postID=3258606489050155681" title="0 Comments" /><link rel="replies" type="application/atom+xml" href="http://feeds.feedburner.com/subelskyblog" title="Post Comments" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/3258606489050155681" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6369418367411691447/posts/default/3258606489050155681" /><author><name>Mike Subelsky</name><uri>http://www.blogger.com/profile/03590094055236393140</uri><email>noreply@blogger.com</email></author><feedburner:origLink>http://www.subelsky.com/2008/01/dynamic-content-caching-recipe.html</feedburner:origLink></entry></feed>
