http://blog.tobiascrawley.net/ideas.each(&:post)2011-08-06T00:00:00Zhttp://blog.tobiascrawley.net/posts/2011/08/06/jrubyconf-best-conf-ever/JRubyConf: The Best Conference Ever?2011-08-06T00:00:00ZToby Crawley
This past week, I had the pleasure of attending JRubyConf in Washington, DC on the campus of Gallaudet University. It is possible that this was best conference I've ever attended. What's so good about it? The talks - they were almost all great, especially the keynotes. Normally I skip a talk or two to hang out in the hallway or just to take a break, but not this time. The talks were recorded - I recommend watching them whenever they get published. The people - it was great to talk to so many smart, enthusiastic folks. It gives me great......
<p>This past week, I had the pleasure of attending <a href="http://jrubyconf.com">JRubyConf</a>
in <a href="http://en.wikipedia.org/wiki/Washington_dc">Washington, DC</a> on the campus of
<a href="http://en.wikipedia.org/wiki/Gallaudet_University">Gallaudet University</a>. It is possible
that this was best conference I've ever attended.</p>
<h2>What's so good about it?</h2>
<ul>
<li>The talks - they were almost all great, especially the keynotes. Normally I skip a talk or two to
hang out in the hallway or just to take a break, but not this time. The talks were recorded - I
recommend watching them whenever they get published.</li>
<li>The people - it was great to talk to so many smart, enthusiastic folks. It gives me great hope
for the future of JRuby.</li>
<li>The food - the conference fed us breakfast & lunch both days, and dinner the first day. The
food was top notch - no bag lunches or 'continental' breakfasts.</li>
<li>The wifi - since the conference was on a university campus, the wifi was excellent. Coming home
to my slow DSL was painful :)</li>
<li>the whisky - the organizers brought in <a href="http://twitter.com/whiskycraig">@whiskycraig</a>
from Scotland to run a whisky tasting. It was almost three hours of whisky history, along with
five whiskies to taste. I've never had whisky, and just assumed they were all kind of the same.
It was interesting to see the large variety in flavor across different brands, and the history
of whisky was fascinating.</li>
</ul>
<h2>Thanks</h2>
<p>I'd like to thank <a href="https://twitter.com/objo">Joe O'Brien</a> and the other folks at
<a href="http://edgecase.com/">EdgeCase</a> for knowing how to put on
a conference - I'm already looking forward to the next JRubyConf!</p>
http://blog.tobiascrawley.net/posts/2011/07/10/github-rss/github-rss2011-07-10T00:00:00ZToby Crawley
The commit feeds provided by github only list the files that changed, and do not include the diffs - github-rss fixes that. It is a simple web service that acts as a proxy and uses the github API to fill in the diff for each commit in the feed. Usage To use, simply give the app your feed url: http://github-rss.example.com/?feed=https://github.com/username/project/commits/master.atom You can also use it with private repos, but you'll need to provide your login and token, and you'll need to escape the '?' and '&' in the feed url with '%3f' and '%26' respectively, like so: http://github-rss.example.com/?feed=https://github.com/username/project/commits/master.atom%3flogin=my_login%26token=1adefed234 Use it......
<p>The commit feeds provided by github only list the files that changed, and do not
include the diffs - <a href="https://github.com/tobias/github-rss">github-rss</a> fixes that. It is a simple web service that acts
as a proxy and uses the github API to fill in the diff for each commit in the feed.</p>
<h2>Usage</h2>
<p>To use, simply give the app your feed url:</p>
<pre><code>http://github-rss.example.com/?feed=https://github.com/username/project/commits/master.atom
</code></pre>
<p>You can also use it with private repos, but you'll need to provide your login and <a href="http://help.github.com/set-your-user-name-email-and-github-token/">token</a>,
and you'll need to escape the '?' and '&' in the feed url with '%3f' and '%26' respectively,
like so:</p>
<pre><code>http://github-rss.example.com/?feed=https://github.com/username/project/commits/master.atom%3flogin=my_login%26token=1adefed234
</code></pre>
<h2>Use it now!</h2>
<p>I have an <a href="http://github-rss.heroku.com/">instance running on Heroku</a> that you are free to use.
Here is the feed for github-rss itself as a <a href="http://github-rss.heroku.com/?feed=https://github.com/tobias/github-rss/commits/master.atom">sample</a>. If you are using github-rss with a private repo,
I recommend you run your own instance instead of using mine. It doesn't store your github <a href="http://help.github.com/set-your-user-name-email-and-github-token/">token</a>,
but it does cache commit data in memcached, and do you trust me that much?</p>
<h2>Problems</h2>
<p>The <a href="https://github.com/tobias/github-rss">source</a> is available on github. If you run in to any problems,
<a href="https://github.com/tobias/github-rss/issues">issues</a> and pull requests are always welcome!</p>
http://blog.tobiascrawley.net/posts/2011/07/04/freedom-from-wordpress/Freedom from Wordpress2011-07-04T00:00:00ZToby Crawley
Greetings! I just ported this blog from Wordpress to awestruct, the best static site generator out there (translation: the one with which I'm most familiar). What better way to celebrate independence on this July 4th than freeing my blog from unnecessary and insecure dynamic generation? Maybe this will spur me to post more. Then again, maybe it won't. I am planning to blog the conversion process so you can follow along at home.......
<p>Greetings! I just ported this blog from <a href="http://wordpress.org/">Wordpress</a> to
<a href="http://awestruct.org/">awestruct</a>, the best static site generator out there
(translation: the one with which I'm most familiar). What better way to celebrate
independence on this July 4th than freeing my blog from unnecessary and insecure
dynamic generation?</p>
<p>Maybe this will spur me to post more. Then again, maybe it won't. I am planning
to blog the conversion process so you can follow along at home.</p>
http://blog.tobiascrawley.net/posts/2010/11/11/access-commonly-used-credentials-quickly-in-irb/Access commonly used credentials quickly in irb2010-11-11T00:00:00ZToby Crawley
I often deal with multiple Amazon AWS accounts in irb, and grew tired of copying and pasting my credentials, so I added code to my ~/.irbrc to make them available from a constant. Here is the relevant chunk of my irbrc (explanation follows): I load the credentials from a separate yaml file, with the keys as symbols (I’ll explain why in a sec): The yaml is parsed and loaded in to an OpenCascade from the Hashery gem, which works like ruby’s builtin OpenStruct, but provides deep ‘structing’ of the source hash. Since it requires symbols as keys, I store the......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>I often deal with multiple Amazon <span class="caps">AWS </span>accounts in irb, and grew tired of copying and pasting my credentials, so I added code to my <code>~/.irbrc</code> to make them available from a constant. Here is the relevant chunk of my <code>irbrc</code> (explanation follows):</p>
<script src="https://gist.github.com/672837.js?file=irbrc.rb"></script>
<p>I load the credentials from a separate yaml file, with the keys as symbols (I’ll explain why in a sec):</p>
<script src="https://gist.github.com/672839.js?file=creds.yml"></script>
<p>The yaml is parsed and loaded in to an <code>OpenCascade</code> from the <a href="http://rubyworks.github.com/hashery/">Hashery</a> gem, which works like ruby’s builtin <a href="http://ruby-doc.org/stdlib/libdoc/ostruct/rdoc/classes/OpenStruct.html">OpenStruct</a>, but provides deep ‘structing’ of the source hash. Since it requires symbols as keys, I store the keys as symbols in the yaml to avoid an ugly <code>symbolize_keys</code> step.</p>
<p>Now, inside irb, I can access the credentials with:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style="">EC2.<span style="color:#9900CC;">account_a</span>.<span style="color:#9900CC;">access_key_id</span>
EC2.<span style="color:#9900CC;">account_b</span>.<span style="color:#9900CC;">secret_access_key</span></pre></div></div>
<p>Since I use <a href="http://rvm.beginrescueend.com/"><span class="caps">RVM</span></a> gemsets for almost everything, I’m often switching between gemsets, some of which have not had an irb session. To handle that case, I have the <code>force_require</code> method that will automatically install missing gems. </p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2010/09/23/yank-to-gist-and-insert-the-url-instead-in-emacs/Yank to gist (and insert the url instead) in Emacs2010-09-23T00:00:00ZToby Crawley
On our distributed team, we use IRC constantly to stay in touch, and we often share gists of code/log file chunks/whatever. I use ERC as my IRC client, and use gist.el constantly to turn content in to gists. It works really well when the content you are trying to gistify is already in an emacs buffer. You can gist an entire buffer (or a region of the buffer), and have the url to the gist on your kill-ring (clipboard) ready to yank (paste). But I often have the need to create a gist of content I’ve copied from somewhere outside......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>On our <a href="http://projectodd.org/">distributed team</a>, we use <a href="http://en.wikipedia.org/wiki/Internet_Relay_Chat"><span class="caps">IRC</span></a> constantly to stay in touch, and we often share gists of code/log file chunks/whatever. I use <a href="http://www.emacswiki.org/emacs/ERC"><span class="caps">ERC</span></a> as my <span class="caps">IRC </span>client, and use <a href="http://github.com/defunkt/gist.el">gist.el</a> constantly to turn content in to gists. It works really well when the content you are trying to gistify is already in an emacs buffer. You can gist an entire buffer (or a region of the buffer), and have the url to the gist on your kill-ring (clipboard) ready to yank (paste). But I often have the need to create a gist of content I’ve copied from somewhere outside of emacs – from a terminal, a browser window, wherever. </p>
<p>Until tonight, my workflow was to paste into a temp buffer in emacs, call <code>gist-buffer</code> to create the gist, then yank the gist url into <span class="caps">ERC.</span> This evening, I wrote <code>yank-to-gist</code> to streamline that process a bit. It takes the top of the kill-ring, inserts it into a temp buffer, creates a gist from the buffer, then inserts the url for the new gist at the point. </p>
<script src="http://gist.github.com/593091.js?file=my-defuns.el"></script>
<p>It relies on gist.el being loaded. I Currently only have it bound in erc-mode to <code>C-c y</code>.</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2010/05/28/open_exception-gem-now-with-better-emacs-support/open_exception gem: now with better emacs support!2010-05-28T00:00:00ZToby Crawley
I just released v0.3.1 of the open_exception gem. This release does a better job of handling exceptions that have been munged by Rails, and now provides a tempfile containing the full stack trace to the open command. If you are using emacs, you can use the :emacs_with_trace open command, and get the stack trace as a navigable compilation buffer (next to || below) the source file in a split frame. For this to work, you’ll need to add the following function to your emacs init: See github for the code and README.......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>I just released <a href="http://rubygems.org/gems/open_exception">v0.3.1</a> of the <a href="http://blog.tobiascrawley.net/2010/04/26/open_exception-gem-auto-open-exceptions-in-your-editor/">open_exception gem</a>. This release does a better job of handling exceptions that have been munged by Rails, and now provides a tempfile containing the full stack trace to the open command. </p>
<p>If you are using emacs, you can use the <code>:emacs_with_trace</code> open command, and get the stack trace as a navigable compilation buffer (next to || below) the source file in a split frame. For this to work, you’ll need to add the following function to your emacs init:</p>
<script src="http://gist.github.com/417151.js?file=gistfile1.el"></script>
<p>See github for the <a href="http://github.com/tobias/open_exception">code</a> and <a href="http://github.com/tobias/open_exception/blob/master/README.md"><span class="caps">README</span></a>.</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2010/04/26/open_exception-gem-auto-open-exceptions-in-your-editor/open_exception gem: auto open exceptions in your editor2010-04-26T00:00:00ZToby Crawley
open_exception opens an exception in your favorite editor when developing locally. It works by parsing the backtrace, and opening the offending file at the offending line in your favorite editor (assuming your favorite editor supports remote open commands). You can add filters that allow you to ignore some exceptions, and filters that allow you to scope the backtrace search. The backtrace scoping is useful for opening the last call in your application code when the exception occurs in a framework or lib. If you are on MacOSX and have the growl gem installed, you will get a growl notification with......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>open_exception opens an exception in your favorite editor when developing locally. It works by parsing the backtrace, and opening the offending file at the offending line in your favorite editor (assuming your favorite editor supports remote open commands).</p>
<p>You can add filters that allow you to ignore some exceptions, and filters that allow you to scope the backtrace search. The backtrace scoping is useful for opening the last call in your application code when the exception occurs in a framework or lib.</p>
<p>If you are on MacOSX and have the <a href="http://rubygems.org/gems/growl">growl gem</a> installed, you will get a growl notification with the exception message when the file is opened.</p>
<h3>Editors</h3>
<p>Out if the box, the gem supports three editors (with the following open commands):</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style="">
<span style="color:#ff3333; font-weight:bold;">:emacs</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'/usr/bin/emacsclient -n +{line} {file}'</span>,
<span style="color:#ff3333; font-weight:bold;">:textmate</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'/usr/local/bin/mate -a -d -l {line} {file}'</span>,
<span style="color:#ff3333; font-weight:bold;">:macvim</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'/usr/local/bin/mvim +{line} {file}'</span></pre></div></div>
<p>Note: if using emacs, you will need to be running <code>emacsserver</code>. To start the server: <code>M-x server-start</code><br />
or add <code>(server-start)</code> to your init.</p>
<h3>Configuration</h3>
<p>To configure, pass a block to the configure method:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style="">
OpenException.<span style="color:#9900CC;">configure</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>oe<span style="color:#006600; font-weight:bold;">|</span>
 <span style="color:#008000; font-style:italic;"># open_with can be one of the built in editors (:emacs, :macvim, :textmate)</span>
 <span style="color:#008000; font-style:italic;"># or a command to execute to open the file, where {file} and {line} will be replaced</span>
 <span style="color:#008000; font-style:italic;"># with the file path and line number, respectively. See 'Editors' above for an example.</span>
 <span style="color:#008000; font-style:italic;"># The default editor is :emacs.</span>
 
 oe.<span style="color:#9900CC;">open_with</span> = <span style="color:#ff3333; font-weight:bold;">:emacs</span>
 
 <span style="color:#008000; font-style:italic;"># you can add exclusion filters to ignore exceptions. A filter can be an exception class to </span>
 <span style="color:#008000; font-style:italic;"># ignore, or a proc that is passed the exception, and should evaluate to true if the exception </span>
 <span style="color:#008000; font-style:italic;"># should be ignored. Be careful with using a class - it uses is_a?, so any subclasses of the</span>
 <span style="color:#008000; font-style:italic;"># passed class will be ignored as well. The list of filters is [] by default.</span>
 
 oe.<span style="color:#9900CC;">exclusion_filters</span> <span style="color:#006600; font-weight:bold;"><<</span> SomeErrorClass
 oe.<span style="color:#9900CC;">exclusion_filters</span> <span style="color:#006600; font-weight:bold;"><<</span> <span style="color:#CC0066; font-weight:bold;">lambda</span> <span style="color:#006600; font-weight:bold;">{</span> <span style="color:#006600; font-weight:bold;">|</span>exception<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#0000FF; font-weight:bold;">true</span> <span style="color:#9966CC; font-weight:bold;">if</span> exception_should_be_excluded <span style="color:#006600; font-weight:bold;">}</span>
 
 <span style="color:#008000; font-style:italic;"># you can scope the search for the file:line to open with a filter as well. A filter can be a </span>
 <span style="color:#008000; font-style:italic;"># regular expression that is matched against the line, or a proc that is passed the line and </span>
 <span style="color:#008000; font-style:italic;"># should evaluate to true if the line should be used. The first line that any filter passes for </span>
 <span style="color:#008000; font-style:italic;"># will be the file:line that is opened. This is useful for opening the point in the stack just</span>
 <span style="color:#008000; font-style:italic;"># before control passes out of your app code when the exception occurs in an external </span>
 <span style="color:#008000; font-style:italic;"># lib/framework. The list of filters is [] by default. </span>
 
 oe.<span style="color:#9900CC;">backtrace_line_filters</span> <span style="color:#006600; font-weight:bold;"><<</span> <span style="color:#006600; font-weight:bold;">%</span>r<span style="color:#006600; font-weight:bold;">{</span><span style="color:#006600; font-weight:bold;">/</span>app<span style="color:#006600; font-weight:bold;">/</span>root<span style="color:#006600; font-weight:bold;">/</span><span style="color:#006600; font-weight:bold;">(</span>app<span style="color:#006600; font-weight:bold;">|</span>lib<span style="color:#006600; font-weight:bold;">)</span><span style="color:#006600; font-weight:bold;">}</span> 
 oe.<span style="color:#9900CC;">backtrace_line_filters</span> <span style="color:#006600; font-weight:bold;"><<</span> <span style="color:#CC0066; font-weight:bold;">lambda</span> <span style="color:#006600; font-weight:bold;">{</span> <span style="color:#006600; font-weight:bold;">|</span>backtrace_line<span style="color:#006600; font-weight:bold;">|</span> <span style="color:#0000FF; font-weight:bold;">true</span> <span style="color:#9966CC; font-weight:bold;">if</span> line_should_be_used <span style="color:#006600; font-weight:bold;">}</span>
 
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>
<h3>Rails Integration</h3>
<p>The gem also alias chains in to rails’ <code>ActionController#rescue_action_locally</code> method to automatically open exceptions in development mode. The gem also adds the following filter to the <code>:backtrace_line_filters</code> to scope the opened files to the app:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style="">
<span style="color:#006600; font-weight:bold;">%</span>r<span style="color:#006600; font-weight:bold;">{</span><span style="color:#008000; font-style:italic;">#{Rails.root}/(app|lib)}</span></pre></div></div>
<p>To replace or remove this filter, you will need to reset the <code>:backtrace_line_filters</code> in your configure block:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style="">
OpenException.<span style="color:#9900CC;">configure</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>oe<span style="color:#006600; font-weight:bold;">|</span>
 oe.<span style="color:#9900CC;">backtrace_line_filters</span> = <span style="color:#006600; font-weight:bold;">[</span><span style="color:#006600; font-weight:bold;">]</span>
 oe.<span style="color:#9900CC;">backtrace_line_filters</span> <span style="color:#006600; font-weight:bold;"><<</span> my_new_filter
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>
<p>This has been tested with rails v2.3.5, but should work fine with 2.1 <= rails < 3. It may work with rails 3 as well, I just haven’t yet looked at rails 3.</p>
<h3>Standalone/Other Frameworks</h3>
<div class="wp_syntax"><div class="code"><pre class="ruby" style="">
<span style="color:#008000; font-style:italic;"># To manually open an exception, or wire it up in another framework, you call:</span>
OpenException.<span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">(</span>exception<span style="color:#006600; font-weight:bold;">)</span>
 
<span style="color:#008000; font-style:italic;"># You can override the default (or configured) options by passing a hash as the second arg:</span>
OpenException.<span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">(</span>exception, <span style="color:#006600; font-weight:bold;">{</span>:open_with <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#ff3333; font-weight:bold;">:textmate</span>, <span style="color:#ff3333; font-weight:bold;">:backtrace_line_filters</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">[</span>filter, another_filter<span style="color:#006600; font-weight:bold;">]</span><span style="color:#006600; font-weight:bold;">)</span></pre></div></div>
<p>The source is on <a href="http://github.com/tobias/open_exception">github</a>, and the gem is on <a href="http://rubygems.org/gems/open_exception">rubygems</a>.</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2010/03/19/generate-a-migration-and-open-it-in-a-buffer-in-emacs/Generate a migration and open it in a buffer (in Emacs)2010-03-19T00:00:00ZToby Crawley
Requires rinari......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p><script src="http://gist.github.com/337495.js?file=rails-generate-migration.el"></script><br />
<strong>Requires <a href="http://rinari.rubyforge.org/">rinari</a></strong></p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2010/02/17/commenting-out-blocks-of-ruby-in-emacs/Commenting out blocks of ruby in emacs2010-02-17T00:00:00ZToby Crawley
I’ve been an emacs user for 12+ years, and am ashamed to admit that I’ve never learned emacs lisp (yes, my last post was about emacs lisp code, but it was a copy and paste with a few changes, and I certainly didn’t understand what it was doing). Until now, that is. I started reading the emacs lisp intro, but only got about fifty pages in to it before I got the itch to write some code. So here it is. Its a package that allows you to comment out a block of ruby code from a keybinding (I’m sure......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>I’ve been an <a href="http://www.gnu.org/software/emacs/">emacs</a> user for 12+ years, and am ashamed to admit that I’ve never learned <a href="http://en.wikipedia.org/wiki/Emacs_Lisp">emacs lisp</a> (yes, my last post was about emacs lisp code, but it was a copy and paste with a few changes, and I certainly didn’t understand what it was doing). Until now, that is. I started reading the <a href="http://www.gnu.org/software/emacs/emacs-lisp-intro/">emacs lisp intro</a>, but only got about fifty pages in to it before I got the itch to write some code.</p>
<p>So here it is. Its a package that allows you to comment out a block of ruby code from a keybinding (I’m sure there is code out there to do this already, but it was a fun learning challenge).</p>
<p>The main function is <code>comment-ruby</code>, which I have bound to <code>C-:</code>. If there is a region active, it comments out the region. If that region is less than five lines, each line is commented with ‘# ‘, otherwise the entire region is wrapped in <code>=begin...=end</code>. If the region is not active, the current line is commented out with ‘# ‘.</p>
<p>After a region has been commented out, the point (cursor) is set to the line above or below the region, depending on whether the point was at the beginning or end of the region when called.</p>
<p>Here is the code – it probably isn’t idiomatic lisp. If you have any suggestions on improving the code or making it more idiomatic, please let me know!</p>
<script src="http://gist.github.com/306302.js?file=comment-ruby.el"></script>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2010/02/11/emacs-tip-running-ack-in-the-project-root-wrinari/Emacs tip: running ack in the project root w/rinari2010-02-11T00:00:00ZToby Crawley
This post covers how to combine the awesomeness of ack with rinari in emacs to run ack in the project root by default. (If you aren’t using ack, definitely check it out for searching your codebase. If you aren’t using emacs, this post isn’t going to convince you to switch). I’ve been using Kim van Wyk’s ack.el for a few months now, but was annoyed that I had to tell it the directory where to run ack, when in most cases I wanted it to run in the root of my Rails app. So I copied the ack function from......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>This post covers how to combine the awesomeness of <a href="http://betterthangrep.com/">ack</a> with <a href="http://rinari.rubyforge.org/">rinari</a> in emacs to run ack in the project root by default. (If you aren’t using ack, definitely check it out for searching your codebase. If you aren’t using emacs, this post isn’t going to convince you to switch). </p>
<p>I’ve been using <a href="http://www.rooijan.za.net/">Kim van Wyk’s</a> <a href="http://www.rooijan.za.net/?q=ack_el">ack.el</a> for a few months now, but was annoyed that I had to tell it the directory where to run ack, when in most cases I wanted it to run in the root of my Rails app. So I copied the <code>ack</code> function from ack.el and made one that only asks for the search pattern, then runs in the root of the app (provided by rinari’s <code>rinari-root</code> function). I then bound that function to <code>C-c f a</code>. </p>
<p>Here is the code:<br />
<script src="http://gist.github.com/301205.js?file=ack-in-project.el"></script></p>
<p><strong>Note:</strong> you will need <a href="http://rinari.rubyforge.org/">rinari</a> and <a href="http://www.rooijan.za.net/?q=ack_el">ack.el</a> loaded, and <a href="http://betterthangrep.com/">ack</a> will need to be in your path.</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/12/08/refreshing-an-individual-gemspec/Refreshing an individual gemspec2009-12-08T00:00:00ZToby Crawley
I’m in the process of upgrading a rails app from 2.1 to 2.3, and 2.3 wants me to refresh some of the gemspecs for my vendored gems. Unfortunately, when I run rake gems:refresh_specs I get the dreaded: rake aborted! can't activate , already activated json-1.1.9 I was able to refresh the spec in question outside of rake with (in the console): >> Rails::GemDependency.from_directory_name('vendor/gems/gem_name-0.1.0', false).refresh Hopefully that helps someone else out.......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>I’m in the process of upgrading a rails app from 2.1 to 2.3, and 2.3 wants me to refresh some of the gemspecs for my vendored gems. Unfortunately, when I run <code>rake gems:refresh_specs</code> I get the dreaded:</p>
<pre style="">
rake aborted!
can't activate , already activated json-1.1.9</pre>
<p>I was able to refresh the spec in question outside of rake with (in the console):</p>
<pre style="">
>> Rails::GemDependency.from_directory_name('vendor/gems/gem_name-0.1.0', false).refresh</pre>
<p>Hopefully that helps someone else out.</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/12/05/the-quest-for-a-better-keyboard-layout/The quest for a better keyboard layout2009-12-05T00:00:00ZToby Crawley
The Quest Like most programmers, I type a lot – many hours a day, most days of the week. The keyboard is the primary conduit of my creative expression most of the time, whether I’m writing code or constructing elaborate stories to impress friends, clients, or co-workers (aka email/chat/this blog). For the last couple of years, I’ve been mildly obsessed with making that conduit more efficient. I’ve tried several different keyboards and entirely new keyboard layouts. I stopped the keyboard search with the Kinesis Advantage – it works really well for me, and is the easiest keyboard for touch typing......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<h3>The Quest</h3>
<p> <img class="alignleft size-medium wp-image-249" title="" src="http://blog.tobiascrawley.net/posts/assets/old/AdventureQuest-header5-300x166.jpg" height="166" alt="" width="300" /></p>
<p>Like most programmers, I type a lot – many hours a day, most days of the week. The keyboard is the primary conduit of my creative expression most of the time, whether I’m writing code or constructing elaborate stories to impress friends, clients, or co-workers (aka email/chat/this blog). For the last couple of years, I’ve been mildly obsessed with making that conduit more efficient. I’ve <a href="http://en.wikipedia.org/wiki/IBM_Model_M">tried</a> <a href="http://www.microsoft.com/hardware/mouseandkeyboard/productdetails.aspx?pid=043">several</a> <a href="http://www.kinesis-ergo.com/images/freestyle-solo_690x375.jpg">different</a> <a href="http://www.kinesis-ergo.com/index.htm">keyboards</a> and entirely new <a href="http://en.wikipedia.org/wiki/Dvorak_Simplified_Keyboard">keyboard</a> <a href="http://en.wikipedia.org/wiki/Colemak#Colemak">layouts</a>. </p>
<p>I stopped the keyboard search with the <a href="http://www.kinesis-ergo.com/index.htm">Kinesis Advantage</a> – it works really well for me, and is the easiest keyboard for touch typing that I’ve ever used. But the keyboard layout search continued. The productivity hit during the learning period for <a href="http://en.wikipedia.org/wiki/Dvorak_Simplified_Keyboard">Dvorak</a> or <a href="http://en.wikipedia.org/wiki/Colemak#Colemak">Colemak</a> was too great, and I quickly slid back to <a href="http://en.wikipedia.org/wiki/Qwerty">Qwerty</a>. </p>
<p>I could type as fast as I wanted in Qwerty, so I tried to figure out what was really bugging me about my typing. I realized it was the shift key – I was frustrated with the high percentage of characters I typed that involved shift. I primarily code in Ruby, which uses ‘_’ much more often than ‘-’ (about 14 times more often), ‘:’ more than ‘;’ (about 78 times more often!), and ‘{}’ more than ‘[]‘ (or so I thought – more on that later). </p>
<p>I then decided to create a custom keyboard layout that would reduce the need for the shift key when coding. My goals were:</p>
<ul>
<li>no remapping of the letter keys, since my muscle memory knows where they all are</li>
<li>remap commonly used symbols to be available without the shift key</li>
<li>be easy to learn, so no remapping characters to new keys</li>
</ul>
<p>Using the <a href="http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=Ukelele">Ukelele</a> keyboard layout editing tool (for MacOS), I played around with some layout ideas before settling on the one I’ve been using since May 2009.</p>
<h3>The Layout</h3>
<p><img class="alignright size-medium wp-image-252" title="" src="http://blog.tobiascrawley.net/posts/assets/old/covered-model-railway-layout-300x253.jpg" height="253" alt="" width="300" />
Since I mostly code in Ruby, and mostly use symbols in code vs. email/chat/etc., I remapped the shifted symbols I used more often.<br />
I ‘shift-swapped’ (meaning the symbol you get with or without the shift key depressed are reversed) the following character pairs:</p>
<ul>
<li>{ [</li>
<li>} ]</li>
<li>| \</li>
<li>~ `</li>
<li>: ;</li>
<li>_ -</li>
</ul>
<p>I assumed that I used most of the symbols on the top row number keys more than I used the numbers, so I shift-swapped the 1 – 0 number keys with the corresponding symbol. If caps-lock is on, number keys revert to normal, but all of the other symbol keys remain swapped (meaning when caps-lock is on, pressing the ’1′ key will give you a 1, but pressing the ‘[' key will give you a {). Since the Kinesis keyboard does not have a separate keypad, this makes entering number sequences easier. </p>
<p>The caps-lock key has been moved to the f1 key, and I use the original caps-lock as a control key (for <a href="http://en.wikipedia.org/wiki/Emacs">Emacs</a>). This mapping can't be done by <a href="http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=Ukelele">Ukelele</a>, since it cannot remap function or modifier keys, so I did this using the remapping functionality in the Kinesis keyboard itself.</p>
<h3>Analysis</h3>
<p>After six weeks or so of using the new layout, I decided to analyze a large ruby codebase to see what my shift pair ratios actually were (something I should have done <em>before</em> creating a new layout). Using <a href="http://gist.github.com/133750">this script</a>, I got the following results:</p>
<pre style="">
Analyzed 457 files, 25060 lines
` ~ 25 58 2.320
1 ! 1161 713 0.614
2 @ 564 2700 4.787
3 # 416 1914 4.601
4 $ 264 55 0.208
5 % 359 303 0.844
6 ^ 257 44 0.171
7 & 152 226 1.487
8 * 176 115 0.653
9 ( 196 4479 22.852
0 ) 1761 4485 2.547
- _ 1559 21837 14.007
[ { 1385 1304 0.942
] } 1396 1306 0.936
\ | 144 1480 10.278
; : 108 8446 78.204
= + 5588 729 0.130
‘ " 5585 3909 0.700
, < 4737 791 0.167
. > 10257 2067 0.202
/ ? 1077 1054 0.979</pre>
<p>Columns one and two are the shift pairs. Columns three and four are the occurrence counts for each character in the pair. The last column shows the ratio of the second character (normally shifted) to the first character (normally not shifted). So a higher number in that column indicates an advantage to swapping the shift pair.</p>
<p>I looked at the shift pairs I had swapped, along with the other symbol shift pairs that I did not swap (the last five lines above). There are some big wins here with my current remapping, along with some loses. The '[]'/'{}' swap was a small mistake - looks like I access elements of collections slightly more often than I define inline blocks or explicit hashes (which is kind of obvious in hindsight. In fact, on reflection I would think that collection access would happen considerably more often than inline block creation). And some of the number key remaps are big loses based on the ratios, but the lowest ratio pairs there have generally low volume. After this analysis, I didn't undo any of the remappings, though I should have reversed (and still should reverse) the bracket/brace swap. </p>
<h3>Usage </h3>
<p><img class="alignleft size-medium wp-image-259" title="" src="http://blog.tobiascrawley.net/posts/assets/old/hat-usage-instructions-300x266.jpg" height="266" alt="" width="300" />
The name of this layout is 'rubyist'. If you are interested in giving it a try, download the MacOS keylayout file <a href="http://tobiascrawley.net/rubyist/rubyist.keylayout">here</a>, and put it in ~/Library/Keyboard Layouts/. </p>
<p>I don't expect this layout to work well for everyone, or really anyone other than me. I do think all of us could benefit from evaluating the text we type the most, and seeing if some keyboard layout tweaks could make us more efficient. If you do want to give your own layout a try, check out these platform specific tools:</p>
<ul>
<li>MacOS: <a href="http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=Ukelele">Ukelele</a></li>
<li>Linux: <a href="http://www.linux.com/archive/articles/113715"><span class="caps">XKB</span></a></li>
<li>Windows: <a href="http://msdn.microsoft.com/en-us/goglobal/bb964665.aspx">Microsoft Keyboard Layout Creator</a></li>
</ul>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/11/05/pomodoro-status-updates-and-a-distributed-team/Pomodoro, status updates, and a distributed team2009-11-05T00:00:00ZToby Crawley
For the last few months, I’ve been playing with the pomodoro technique to manage my time and stay focused on the task at hand. It works best for me when I’m stressed and have an overwhelming workload. It helps me focus on the immediate task, and not get distracted too much by all of the other stuff I need to do. One issue with managing the technique is keeping interruptions to a minimum. When I start a pomodoro, I’ll quit email, twitter, and chat. But we are a distributed team, and I work from home 95% of the time. I......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p><img class="aligncenter size-full wp-image-235" title="pomodoro_status" src="http://blog.tobiascrawley.net/posts/assets/old/pomodoro_status.jpg" height="151" alt="pomodoro_status" width="545" /></p>
<p>For the last few months, I’ve been playing with the <a href="http://www.pomodorotechnique.com/">pomodoro technique</a> to manage my time and stay focused on the task at hand. It works best for me when I’m stressed and have an overwhelming workload. It helps me focus on the immediate task, and not get distracted too much by all of the other stuff I need to do. </p>
<p>One issue with managing the technique is keeping interruptions to a minimum. When I start a pomodoro, I’ll quit email, twitter, and chat. But we are a distributed team, and I work from home 95% of the time. I want to let the rest of the team know I’m around, but also let them know that I’m in a pomodoro, and to only interrupt in emergencies. Since we primarily use <a href="http://campfirenow.com">Campfire</a> to communicate, I set up a ‘Status’ room there that allows us to post what we are up to/where we are at/etc. Its not only useful for pomodoro updates, but also ‘off to lunch’, ‘gone for the day’, etc. (And here is a third sentence that ends in etc.) But manually entering those status updates means they won’t happen. So I wrote a simple update script using the lovely <a href="http://tinder.rubyforge.org/">tinder</a> gem. It consists of two files – the script itself:</p>
<script src="http://gist.github.com/227107.js"></script>
<p>and the config file (<code>~/.campfire_status</code>):</p>
<script src="http://gist.github.com/227109.js"></script>
<p>But pomodoro status updates still require a manual step to run the script. Enter <a href="http://pomodoro.ugolandini.com/">Pomodoro</a>, a MacOS pomodoro client by <a href="http://www.ugolandini.com/">Ugo Landini</a>. His client allows integration with growl, twitter, and applescript. So I added the following applescript snippets to update the status for me:</p>
<script src="http://gist.github.com/227129.js"></script>
<p>A couple of gotchas I ran in to:<br />
* the Pomodoro app does not allow copy & paste in the applescript text areas, making it a bit of a pain to enter<br />
* the Pomodoro app also has a file selector next to each applescript text area, but I could not get it to recognize the saved applescripts<br />
* the Campfire <span class="caps">API </span>seems to ignore requests from users that are currently logged in(?), so the status updates come from another account (in our case, we have a ‘service-bot’ account that posts messages from other services). That’s why there is a <code>USER_NAME</code> setting that is displayed with the message.</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/10/13/rails_habitat-a-simple-rails-plugin-to-make-rails_env-a-bit-friendlier/rails_habitat: a simple rails plugin to make RAILS_ENV a bit friendlier2009-10-13T00:00:00ZToby Crawley
I just released a stupid simple plugin based on the idea behind Coda Hale’s rails_environments plugin. This plugin adds the following functionality to the Rails module to help with determining the current enviroment: >> Rails.environment # a convenience alias to Rails.env => "development" >> Rails.development? => true >> Rails.not_development? => false >> Rails.production? => false >> Rails.not_production? => true >> Rails.test? => false >> Rails.not_test? => true Not only does it provide env? and not_env? methods for the standard environments, it also provides those methods for any environment you define in config/environments/ (in fact that is how it learns about......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>I just released a stupid simple plugin based on the idea behind Coda Hale’s <a href="http://blog.codahale.com/2006/04/09/rails-environments-a-plugin-for-well-rails/">rails_environments plugin</a>.</p>
<p>This plugin adds the following functionality to the Rails module to help with determining the current enviroment:</p>
<pre style="">
>> Rails.environment # a convenience alias to Rails.env
=> "development"
>> Rails.development?
=> true
>> Rails.not_development?
=> false
>> Rails.production?
=> false
>> Rails.not_production?
=> true
>> Rails.test?
=> false
>> Rails.not_test?
=> true</pre>
<p>Not only does it provide <code>env?</code> and <code>not_env?</code> methods for the standard environments, it also provides those methods for any environment you define in config/environments/ (in fact that is how it learns about all of the environments, including the standard three). So if you define new environments in config/environments/ they will be picked up automatically. </p>
<p>Install with: <code>script/plugin install git://github.com/tobias/rails_habitat.git</code></p>
<p>It lives on <a href="http://github.com/tobias/rails_habitat">github</a>.</p>
<p><strong>Edit</strong>: see David’s comment below for the built in way to do this (in Rails >= 2.2).</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/10/08/notify-a-campfire-room-on-cap-deploy/Notify a Campfire room on cap deploy2009-10-08T00:00:00ZToby Crawley
We use Campfire for internal communication, and I’ve lately been pushing notifications there for all to see (Zendesk ticket updates, git repo pushes, etc). We decided it would be useful for the support team to know when a deployment occurs. I googled a bit to see if anyone had shared a Capistrano recipe, and did not find one. So I’m sharing mine. Using the tinder gem, its super easy: Enjoy!......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>We use <a href="http://campfirenow.com">Campfire</a> for internal communication, and I’ve lately been pushing notifications there for all to see (<a href="http://zendesk.com">Zendesk</a> ticket updates, git repo pushes, etc). We decided it would be useful for the support team to know when a deployment occurs. I googled a bit to see if anyone had shared a <a href="http://capify.org">Capistrano</a> recipe, and did not find one. So I’m sharing mine.</p>
<p>Using the <a href="http://github.com/collectiveidea/tinder">tinder</a> gem, its super easy:<br />
<script src="http://gist.github.com/205055.js"></script></p>
<p>Enjoy!</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/09/19/zendesk_remote_auth-gem-makes-zendesk-sso-easy/zendesk_remote_auth gem makes Zendesk SSO easy!2009-09-19T00:00:00ZToby Crawley
I extracted how we are doing Zendesk remote authentication from an app at Dealer Ignition, and stuck it in a small gem for your enjoyment. You can find it on GitHub. Installation and Setup Install: gem install tobias-zendesk_remote_auth Setup: You will need to give the gem your token and authentication url, perhaps in an initializer: Zendesk::RemoteAuth.token = 'YOUR-TOKEN' Zendesk::RemoteAuth.auth_url = 'https://yourcompany.zendesk.com/access/remote/' and config the gem in environment.rb (if using rails): config.gem 'tobias-zendesk_remote_auth', :lib => 'zendesk_remote_auth', :source => http://gems.github.com' Usage Mixin the Zendesk::RemoteAuthHelper module wherever needed, then call: zendesk_remote_auth_url(:name => 'user name', :email => 'user email', <optional params>) This will return......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>I extracted how we are doing <a href="http://www.zendesk.com/api/remote_authentication">Zendesk remote authentication</a> from an app at <a href="http://dealerignition.com">Dealer Ignition</a>, and stuck it in a small gem for your enjoyment. You can find it on <a href="http://github.com/tobias/zendesk_remote_auth">GitHub</a>.</p>
<h3>Installation and Setup</h3>
<p>Install:</p>
<pre style="">gem install tobias-zendesk_remote_auth</pre>
<p>Setup:</p>
<p>You will need to give the gem your token and authentication url, perhaps in an initializer:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""><span style="color:#6666ff; font-weight:bold;">Zendesk::RemoteAuth</span>.<span style="color:#9900CC;">token</span> = <span style="color:#996600;">'YOUR-TOKEN'</span>
<span style="color:#6666ff; font-weight:bold;">Zendesk::RemoteAuth</span>.<span style="color:#9900CC;">auth_url</span> = <span style="color:#996600;">'https://yourcompany.zendesk.com/access/remote/'</span></pre></div></div>
<p>and config the gem in environment.rb (if using rails):</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style="">config.<span style="color:#9900CC;">gem</span> <span style="color:#996600;">'tobias-zendesk_remote_auth'</span>, <span style="color:#ff3333; font-weight:bold;">:lib</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'zendesk_remote_auth'</span>, <span style="color:#ff3333; font-weight:bold;">:source</span> <span style="color:#006600; font-weight:bold;">=></span> http:<span style="color:#006600; font-weight:bold;">//</span>gems.<span style="color:#9900CC;">github</span>.<span style="color:#9900CC;">com</span><span style="color:#996600;">'</span></pre></div></div>
<h3>Usage</h3>
<p>Mixin the Zendesk::RemoteAuthHelper module wherever needed, then call:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style="">zendesk_remote_auth_url<span style="color:#006600; font-weight:bold;">(</span><span style="color:#ff3333; font-weight:bold;">:name</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'user name'</span>,
 <span style="color:#ff3333; font-weight:bold;">:email</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'user email'</span>,
 <span style="color:#006600; font-weight:bold;"><</span>optional params<span style="color:#006600; font-weight:bold;">></span><span style="color:#006600; font-weight:bold;">)</span></pre></div></div>
<p>This will return a url you can redirect the user to to log them in to your zendesk account. </p>
<p>As a convenience, you can pass a user object to zendesk_remote_auth_url:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style="">zendesk_remote_auth_url<span style="color:#006600; font-weight:bold;">(</span>user<span style="color:#006600; font-weight:bold;">)</span></pre></div></div>
<p>This user must <code>respond_to?</code> <code>:name</code> and <code>:email</code>, and its <code>:id</code> will be used as the <code>:external_id</code> (making it useless with user objects that return an ephemeral object_id, but works well with ActiveRecord and the like). If the user object responds to <code>:zendesk_organization</code>, that will be used as the <code> <img class="wp-smiley" src="http://blog.tobiascrawley.net/wp-includes/images/smilies/icon_surprised.gif" alt=":o" /> rganization</code> for the call.</p>
<p>This method will generate and include the hash of the parameters for you if necessary. </p>
<h3>Example Auth Controller</h3>
<p>Here is an example controller that handles login and logout for zendesk:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""><span style="color:#008000; font-style:italic;"># Uses restful-authentication style auth. </span>
<span style="color:#008000; font-style:italic;"># </span>
<span style="color:#008000; font-style:italic;"># Define the following in routes.rb:</span>
<span style="color:#008000; font-style:italic;"># map.with_options :controller => 'zendesk_auth' do |zd|</span>
<span style="color:#008000; font-style:italic;"># zd.connect '/zendesk/authorize', :action => 'authorize'</span>
<span style="color:#008000; font-style:italic;"># zd.connect '/zendesk/logout', :action => 'logout'</span>
<span style="color:#008000; font-style:italic;"># end</span>
<span style="color:#9966CC; font-weight:bold;">class</span> ZendeskAuthController <span style="color:#006600; font-weight:bold;"><</span> ApplicationController
 <span style="color:#9966CC; font-weight:bold;">include</span> <span style="color:#6666ff; font-weight:bold;">Zendesk::RemoteAuthHelper</span>
 
 skip_before_filter <span style="color:#ff3333; font-weight:bold;">:login_required</span>, <span style="color:#ff3333; font-weight:bold;">:only</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#ff3333; font-weight:bold;">:logout</span>
 
 <span style="color:#9966CC; font-weight:bold;">def</span> authorize
 redirect_to zendesk_remote_auth_url<span style="color:#006600; font-weight:bold;">(</span>current_user<span style="color:#006600; font-weight:bold;">)</span>
 <span style="color:#9966CC; font-weight:bold;">end</span>
 
 <span style="color:#9966CC; font-weight:bold;">def</span> logout
 redirect_to logout_url
 <span style="color:#9966CC; font-weight:bold;">end</span>
 
 protected
 <span style="color:#9966CC; font-weight:bold;">def</span> login_required
 <span style="color:#9966CC; font-weight:bold;">if</span> !logged_in?
 flash<span style="color:#006600; font-weight:bold;">[</span><span style="color:#ff3333; font-weight:bold;">:notice</span><span style="color:#006600; font-weight:bold;">]</span> = <span style="color:#996600;">'You must log in to access the support site.'</span>
 store_location
 redirect_to login_path
 <span style="color:#9966CC; font-weight:bold;">end</span>
 <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/07/18/rails_rootapp-organization/RAILS_ROOT/app Organization2009-07-18T00:00:00ZToby Crawley
As an app grows, so does the amount of files in app/models. Here is a simple tip to help reduce the clutter: move mailers, observers, and sweepers out of app/models into app/mailers, app/observers, and app/sweepers, respectively. For rails to still load them, you will need to modify config/environment.rb: # clean up app/models a bit %w{mailers observers sweepers}.each do |dir| config.load_paths << "#{RAILS_ROOT}/app/#{dir}" end As a bonus, you can now automatically record your observers with ActiveRecord instead of having to add them individually in environment.rb: config.active_record.observers = Dir.glob("#{RAILS_ROOT}/app/observers/*.rb").collect do |filename| filename.split('/').last.split('.').first.to_sym end One issue with this reorganization is that the generators......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>As an app grows, so does the amount of files in <code>app/models</code>. Here is a simple tip to help reduce the clutter: move mailers, observers, and sweepers out of <code>app/models</code> into <code>app/mailers</code>, <code>app/observers</code>, and <code>app/sweepers</code>, respectively. For rails to still load them, you will need to modify <code>config/environment.rb</code>:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""><span style="color:#008000; font-style:italic;"># clean up app/models a bit</span>
<span style="color:#006600; font-weight:bold;">%</span>w<span style="color:#006600; font-weight:bold;">{</span>mailers observers sweepers<span style="color:#006600; font-weight:bold;">}</span>.<span style="color:#9900CC;">each</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>dir<span style="color:#006600; font-weight:bold;">|</span>
 config.<span style="color:#9900CC;">load_paths</span> <span style="color:#006600; font-weight:bold;"><<</span> <span style="color:#996600;">"#{RAILS_ROOT}/app/#{dir}"</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>
<p>As a bonus, you can now automatically record your observers with <code>ActiveRecord</code> instead of having to add them individually in <code>environment.rb</code>:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style="">config.<span style="color:#9900CC;">active_record</span>.<span style="color:#9900CC;">observers</span> = <span style="color:#CC00FF; font-weight:bold;">Dir</span>.<span style="color:#9900CC;">glob</span><span style="color:#006600; font-weight:bold;">(</span><span style="color:#996600;">"#{RAILS_ROOT}/app/observers/*.rb"</span><span style="color:#006600; font-weight:bold;">)</span>.<span style="color:#9900CC;">collect</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>filename<span style="color:#006600; font-weight:bold;">|</span>
 filename.<span style="color:#CC0066; font-weight:bold;">split</span><span style="color:#006600; font-weight:bold;">(</span><span style="color:#996600;">'/'</span><span style="color:#006600; font-weight:bold;">)</span>.<span style="color:#9900CC;">last</span>.<span style="color:#CC0066; font-weight:bold;">split</span><span style="color:#006600; font-weight:bold;">(</span><span style="color:#996600;">'.'</span><span style="color:#006600; font-weight:bold;">)</span>.<span style="color:#9900CC;">first</span>.<span style="color:#9900CC;">to_sym</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>
One issue with this reorganization is that the generators will continue to create mailers, observers, and sweepers in <code>app/models</code>. For me, that is not a big deal – I don’t create them often, and manually move them after generation. I suspect it would be trivial to adjust the generators to use the new path, but have not looked in to it. <br />
</div>
<p></p>
<!-- end .postmetadata -->
http://blog.tobiascrawley.net/posts/2009/06/11/restarting-a-hobby/Restarting a hobby2009-06-11T00:00:00ZToby Crawley
In my youth (aka when I was 30) I ran a marathon, and had not run since until today. My entire life, running is something I would do for a while and really enjoy, only to walk (ha!) away from it for a while. Life would get it the way (I would move, a new job would keep me too busy, {insert any other excuse here}). But then I would remember that I enjoyed it, and lace up again. This latest break of five years since the marathon has been the longest. I have been considering running again for the......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>In my youth (aka when I was 30) I ran a marathon, and had not run since until today. </p>
<p>My entire life, running is something I would do for a while and really enjoy, only to walk (ha!) away from it for a while. Life would get it the way (I would move, a new job would keep me too busy, {insert any other excuse here}). But then I would remember that I enjoyed it, and lace up again. </p>
<p>This latest break of five years since the marathon has been the longest. I have been considering running again for the last few weeks, but have had reservations: the narrow road I live on isn’t safe for running, I’m too busy with work and a new baby, {insert any other excuse here}. So when a friend called me up and asked me if I wanted to run the <a href="http://www.obxmarathon.org/">Outer Banks Marathon</a> in November, I decided to go for a trial run this morning.</p>
<p>But first, to prepare! I need shoes, and shorts, and a fancy shirt; running socks, a gps, a smaller ipod, a runners log book. A couple of days ago I read Chad Fowler’s <a href="http://chadfowler.com/2009/6/9/the-unexpected-consequences-of-consumerism">article</a> on this exact situation: where we plan a new hobby, and instead of just doing it, we buy all the tools we need as a way to feel like we are making progress, instead of just doing it. I know I’ve done that – in my recent quest to learn to play guitar, I’ve accumulated: a guitar, a gig bag, a stand, two tuners, a capo, and a stack of books, but I don’t yet really know how to play. After reading Chad’s article, I decided to be more mindful of that tendency. I resisted the urge to buy anything for running, at least until I’m actually doing it on a regular schedule (and then all I’ll really need is a new pair of shoes). Last night, I gave in to the urge and started writing a <a href="http://sinatrarb.com/">Sinatra</a> based running log application. I told myself I was doing it to learn Sinatra better, and to learn <a href="http://www.mongodb.org/">MongoDB</a>, but did I really do it to feel like a runner? </p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/03/31/server_remote-gem/server_remote gem2009-03-31T00:00:00ZToby Crawley
I just re-released my server_remote plugin as a gem server_remote on github. I converted it to a gem to make it easier to use in multiple apps, and to make it easier to update (see here for the blog entry on the (now obselete) plugin). It is a gem that provides support for running commands on remote server. Once set up, it provides commands via script/remote: remote shell – same as ssh’ing to the server (this is the default command, so it can be called with just remote) remote console – executes a script/console on the server remote logtail –......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>I just re-released my server_remote plugin as a gem <a href="http://github.com/tobias/server_remote">server_remote</a> on github. I converted it to a gem to make it easier to use in multiple apps, and to make it easier to update (see <a href="http://blog.tobiascrawley.net/2009/01/10/server_remote-a-rails-plugin-for-easily-accessing-servers/">here</a> for the blog entry on the (now obselete) plugin). </p>
It is a gem that provides support for running commands on remote server. Once set up, it provides commands via <code>script/remote</code>:<br />
<ul>
<li><code>remote shell</code> – same as ssh’ing to the server (this is the default command, so it can be called with just <code>remote</code>)</li>
<li><code>remote console</code> – executes a <code>script/console</code> on the server</li>
<li><code>remote logtail</code> – executes <code>tail -f log/<environment>.log</code> on the server</li>
<li><code>remote cmd <some command></code> executes command on the server, displaying the result. It <code>cd</code>‘s to the remote app root first.</li>
<li><code>remote scp <local_file> :<remote_file></code> provides scp. Prefix remote files with ‘:’</li></ul>Configuration is in <code>config/server_remote.yml</code>, and is grouped into <em>profiles</em>.
<p>Here is the output of <code>remote usage</code>:</p>
<div class="wp_syntax"><div class="code"><pre class="html" style="">Executes commands on a remote server over ssh. Configuration is in:
/Users/tobias/customers/DealerIgnition/dealer_ignition/script/../config/server_remote.yml
 
You can override the profile used with -p profile. The default profile is: app
 
Learn more in the readme:
/opt/local/lib/ruby/gems/1.8/gems/tobias-server_remote-0.2.0/lib/server_remote/../../README.textile
 
remote commands are:
 
DEFAULT COMMAND shell
 
cmd executes an arbitrary command on the server after a cd to the app path
commands List all 'remote' commands
console executes remote console
help Provide help documentation for a command
logtail executes remote tail -f on the log
scp copies files over scp (prefix remote files with ':')
shell executes remote shell
usage prints usage message
 
For help on a particular command, use 'remote help COMMAND'.</pre></div></div>
<p>It uses <a href="http://remi.org">remi’s</a> <a href="http://github.com/remi/simplecli">simplecli</a> gem. </p>
<p>I plan to add other commands as needed, or you can open up <code>Remote::Commands</code> and add your own. </p>
<h3>Installation</h3>
<p>You will need to install the gem (only once), then setup any apps where you want to use it.</p>
<pre style="">
sudo gem install tobias-server_remote --source http://gems.github.com/
server_remotify path_to_app</pre>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/03/19/credit_card_validator-gem/credit_card_validator gem2009-03-19T00:00:00ZToby Crawley
I recently published a gem that provides credit card validation. It is basically a ruby port of the javascript credit card validator by Thomas Fuchs (madrobby). Usage: CreditCardValidator::Validator.valid?('1111 2222 3333 4444') # allow test numbers to be valid (for development) CreditCardValidator::Validator.options[:test_numbers_are_valid] = true CreditCardValidator::Validator.valid?('1111 2222 3333 4444') # limit the card types you allow CreditCardValidator::Validator.options[:allowed_card_types] = [:visa, :mastercard] CreditCardValidator::Validator.valid?('1111 2222 3333 4444') Supported card types: :amex, :discover, :diners_club, :master_card, :visa Whitespace is stripped from the number automatically. The following things are tested: 1. does the luhn validation code add up? (see http://en.wikipedia.org/wiki/Luhn_algorithm) 2. does the number range and length seem......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>I recently published a gem that provides credit card validation. It is basically a ruby port of the <a href="http://github.com/madrobby/creditcard_js">javascript credit card validator</a> by <a href="http://mir.aculo.us/">Thomas Fuchs</a> (<a href="http://github.com/madrobby">madrobby</a>).</p>
<p>Usage:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""> <span style="color:#6666ff; font-weight:bold;">CreditCardValidator::Validator</span>.<span style="color:#9900CC;">valid</span>?<span style="color:#006600; font-weight:bold;">(</span><span style="color:#996600;">'1111 2222 3333 4444'</span><span style="color:#006600; font-weight:bold;">)</span>
 
<span style="color:#008000; font-style:italic;"># allow test numbers to be valid (for development) </span>
<span style="color:#6666ff; font-weight:bold;">CreditCardValidator::Validator</span>.<span style="color:#9900CC;">options</span><span style="color:#006600; font-weight:bold;">[</span><span style="color:#ff3333; font-weight:bold;">:test_numbers_are_valid</span><span style="color:#006600; font-weight:bold;">]</span> = <span style="color:#0000FF; font-weight:bold;">true</span>
<span style="color:#6666ff; font-weight:bold;">CreditCardValidator::Validator</span>.<span style="color:#9900CC;">valid</span>?<span style="color:#006600; font-weight:bold;">(</span><span style="color:#996600;">'1111 2222 3333 4444'</span><span style="color:#006600; font-weight:bold;">)</span>
 
<span style="color:#008000; font-style:italic;"># limit the card types you allow</span>
<span style="color:#6666ff; font-weight:bold;">CreditCardValidator::Validator</span>.<span style="color:#9900CC;">options</span><span style="color:#006600; font-weight:bold;">[</span><span style="color:#ff3333; font-weight:bold;">:allowed_card_types</span><span style="color:#006600; font-weight:bold;">]</span> = <span style="color:#006600; font-weight:bold;">[</span><span style="color:#ff3333; font-weight:bold;">:visa</span>, <span style="color:#ff3333; font-weight:bold;">:mastercard</span><span style="color:#006600; font-weight:bold;">]</span>
<span style="color:#6666ff; font-weight:bold;">CreditCardValidator::Validator</span>.<span style="color:#9900CC;">valid</span>?<span style="color:#006600; font-weight:bold;">(</span><span style="color:#996600;">'1111 2222 3333 4444'</span><span style="color:#006600; font-weight:bold;">)</span></pre></div></div>
<p>Supported card types:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""> <span style="color:#ff3333; font-weight:bold;">:amex</span>, <span style="color:#ff3333; font-weight:bold;">:discover</span>, <span style="color:#ff3333; font-weight:bold;">:diners_club</span>, <span style="color:#ff3333; font-weight:bold;">:master_card</span>, <span style="color:#ff3333; font-weight:bold;">:visa</span></pre></div></div>
<p>Whitespace is stripped from the number automatically.</p>
<p>The following things are tested:</p>
<p>1. does the luhn validation code add up? (see <a href="http://en.wikipedia.org/wiki/Luhn_algorithm">http://en.wikipedia.org/wiki/Luhn_algorithm</a>)<br />
2. does the number range and length seem right? (see <a href="http://en.wikipedia.org/wiki/Bank_card_number">http://en.wikipedia.org/wiki/Bank_card_number</a>)<br />
3. is it one of several well-known test numbers?</p>
<p>Note: this only validates that the number is of a valid format, it does not check if it is an actual credit card number. You will need to talk to your payment gateway to learn that.</p>
<p>You can also use the validator to learn about the type of the card:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""> <span style="color:#008000; font-style:italic;"># gives the type back as a string (visa, master_card, etc)</span>
<span style="color:#6666ff; font-weight:bold;">CreditCardValidator::Validator</span>.<span style="color:#9900CC;">card_type</span><span style="color:#006600; font-weight:bold;">(</span>number<span style="color:#006600; font-weight:bold;">)</span>
 
<span style="color:#6666ff; font-weight:bold;">CreditCardValidator::Validator</span>.<span style="color:#9900CC;">is_visa</span>?<span style="color:#006600; font-weight:bold;">(</span>number<span style="color:#006600; font-weight:bold;">)</span>
<span style="color:#6666ff; font-weight:bold;">CreditCardValidator::Validator</span>.<span style="color:#9900CC;">is_master_card</span>?<span style="color:#006600; font-weight:bold;">(</span>number<span style="color:#006600; font-weight:bold;">)</span>
<span style="color:#008000; font-style:italic;"># etc. - works for all of the supported card types</span>
 
<span style="color:#6666ff; font-weight:bold;">CreditCardValidator::Validator</span>.<span style="color:#9900CC;">is_allowed_card_type</span>?<span style="color:#006600; font-weight:bold;">(</span>number<span style="color:#006600; font-weight:bold;">)</span></pre></div></div>
<p>To Install:</p>
<pre style="">
gem install tobias-credit_card_validator --source http://gems.github.com</pre>
<p>The source is available on <a href="http://github.com/tobias/credit_card_validator">github</a></p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/03/13/changing-the-get-satisfaction-widget-tab-text/Changing the Get Satisfaction widget tab text2009-03-13T00:00:00ZToby Crawley
We recently added the Get Satisfaction widget to an app, and it was darn easy (we used the overlay widget). It allows you to customize the location and the background color of the tab, but not the text (the default is ‘Feedback’). The customer wanted the text to be ‘Support’, so I thought I’d share the solution with you in case you want to make the same change. The tab uses a background image for the text, so I grabbed a copy and changed the text (its on a grey background div here so you can see it, since its......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>We recently added the <a href="http://getsatisfaction.com/widgets">Get Satisfaction</a> widget to an app, and it was darn easy (we used the overlay widget). It allows you to customize the location and the background color of the tab, but not the text (the default is ‘Feedback’). The customer wanted the text to be ‘Support’, so I thought I’d share the solution with you in case you want to make the same change.</p>
<p>The tab uses a background image for the text, so I grabbed a copy and changed the text (its on a grey background div here so you can see it, since its white text with a transparent background):</p>
<div style="background-color: #aaa; width: 120px; height: 143px;padding:3px;">
<img class="aligncenter size-full wp-image-156" title="support_trans_tab" src="http://blog.tobiascrawley.net/posts/assets/old/support_trans_tab.png" height="140" alt="support_trans_tab" width="102" />
</div>
<p>and here is the css to apply it (the <code>body</code> in the selector makes it more specific to override the rule from Get Satisfaction’s style; alternatively, you can use <code>!important</code> on the rule):</p>
<pre code="css" style="">body a#fdbk_tab {
 background-image: url(/path/to/support_trans_tab.png);
}</pre>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/03/13/script_finder-gem/script_finder gem2009-03-13T00:00:00ZToby Crawley
I recently published a ruby gem on github that simplifies running scripts from a script/ dir from anywhere in your project (rails or otherwise). script_finder provides a script (called s@) in your path that searches in and up from the current dir for a folder (default: @script/) containing an executable file uniquely identified by the a prefix given as the first argument. It then calls that executable, passing the rest of the arguments to the called executable. If the given prefix is ambiguous, the script suggests unique prefixes. Examples (in a rails app): ~/rails_app/app/views$ s c --> calling '/Users/tobias/rails_app/script/console' Loading......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>I recently published a ruby gem on <a href="http://github.com/tobias/script_finder">github</a> that simplifies running scripts from a <code>script/</code> dir from anywhere in your project (rails or otherwise). </p>
<p>script_finder provides a script (called <code>s@) in your path that searches in and up from the current dir for a folder (default: @script/</code>) containing an executable file uniquely identified by the a prefix given as the first argument. It then calls that executable, passing the rest of the arguments to the called executable. If the given prefix is ambiguous, the script suggests unique prefixes.</p>
<p>Examples (in a rails app):</p>
<pre style="">
~/rails_app/app/views$ s c
--> calling '/Users/tobias/rails_app/script/console'
Loading development environment (Rails 2.1.0)
RowsLogger plugin enables mysql
>> exit
~/rails_app/app/views$ s r 'some ruby'
's r' was too ambiguous. Try:
's ru' for 'script/runner'
's re' for 'script/remote'
~/rails_app/app/views$ s ru 'some ruby'
--> calling '/Users/tobias/rails_app/script/runner some ruby'
...</pre>
<p>The gem is not rails specific – out of the box it will work with any project that has a <code>script/</code> directory. If you want to make your own version of the <code>s@ script that looks for executables in a different dir (I would save this one as @c</code>):</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""> <span style="color:#008000; font-style:italic;">#!/usr/bin/env ruby</span>
 
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'script_finder'</span>
 
<span style="color:#008000; font-style:italic;"># looks for executables in a commands/ dir instead of script/.</span>
ScriptFinder.<span style="color:#9900CC;">find_and_execute</span><span style="color:#006600; font-weight:bold;">(</span>ARGV, <span style="color:#996600;">'commands'</span><span style="color:#006600; font-weight:bold;">)</span></pre></div></div>
<p>Let me know if you have any problems/questions.</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/03/12/method_missing-tip/method_missing tip2009-03-12T00:00:00ZToby Crawley
When using ruby’s method_missing, don’t alter the method parameter before calling super (you are calling super, aren’t you?). Otherwise, you will get a very clear exception: ArgumentError: no id given Thanks to google and Nicholas Schlueter for the tip.......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>When using ruby’s <code>method_missing</code>, don’t alter the <code>method</code> parameter before calling <code>super</code> (you are calling <code>super</code>, aren’t you?). Otherwise, you will get a very clear exception:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""> <span style="color:#CC00FF; font-weight:bold;">ArgumentError</span>: no id given</pre></div></div>
<p>Thanks to google and <a href="http://www.simpltry.com/2007/10/15/hooplas-involving-method_missing-tricks/">Nicholas Schlueter</a> for the tip.</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/03/05/presentation-tools/Presentation Tools2009-03-05T00:00:00ZToby Crawley
Last night, I gave my first presentation in a really long time. It went really well! (I used to have a terrible fear of public speaking, so much so that I changed majors in college to avoid having to take a public speaking class (I switched back, because I realized I was being foolish. I’m glad I did, because I met a nice lady (we went out once, and it was the worst date of my life; but I digress))). The presentation was on Haml & Sass, and is available on github if you are interested. But this post isn’t......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>Last night, I gave my first presentation in a really long time. It went really well! (I used to have a terrible fear of public speaking, so much so that I changed majors in college to avoid having to take a public speaking class (I switched back, because I realized I was being foolish. I’m glad I did, because I met a nice lady (we went out once, and it was the worst date of my life; but I digress))). The presentation was on <a href="http://haml.hamptoncatlin.com/docs/rdoc/classes/Haml.html">Haml</a> & <a href="http://haml.hamptoncatlin.com/docs/rdoc/classes/Sass.html">Sass</a>, and is available on <a href="http://github.com/tobias/haml_sass_presentation">github</a> if you are interested. </p>
<p>But this post isn’t about the presentation, but about the tools I used to build/show it. I spent some time trying to get colorized code samples in to Keynote ’09, but did not have much luck. After a little bit of research, I found Dave Thomas’ <a href="http://github.com/pragdave/codex">codex</a>, an html based presentation builder that uses the <a href="http://meyerweb.com/eric/tools/s5/">s5</a> javascript presentation tool. Codex allows you to reference code files or embed code snippets, which will be pulled in during the build process and wrapped in a <a href="http://alexgorbatchev.com/wiki/SyntaxHighlighter">SyntaxHighlighted</a> div. It processes ‘slide’ files and creates one html page containing the entire presentation. I modified it a bit for this presentation to add support for adding text to the previous slide, and included all of the available SyntaxHighlighter language modules in the output. The modified version is <a href="http://github.com/tobias/codex">here</a>. </p>
<p>To display the presentation, I created a <a href="http://fluidapp.com">Fluid</a> app, set it to me chromeless, and made it draggable from anywhere. I then installed <a href="http://www.filewell.com/iRedLite/">iRed Lite</a>, which allows you to send keystrokes to any app using the Apple infrared remote. Once that was all in place, I hooked up the projector, dragged the Fluid app to the projected display, and gave the presentation.</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/02/22/starting-a-new-project/Starting a new project2009-02-22T00:00:00ZToby Crawley
Back in May of 2008 I got involved in a new project. The client and I had some really fun collaboration sessions to get things started, but then I had to do the inevitable ‘sit and wait’ while the project worked its way through the machinery of the organization. The first couple of months there was some small doubt about the project coming together, but it has been a sure thing since then. I did what I could to prepare for getting down to work, but there is only so much you can do ahead of time. This past Thursday......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>Back in May of 2008 I got involved in a new project. The <a href="http://dirtundermynails.com">client</a> and I had some really fun collaboration sessions to get things started, but then I had to do the inevitable ‘sit and wait’ while the project worked its way through the machinery of the organization. The first couple of months there was some small doubt about the project coming together, but it has been a sure thing since then. I did what I could to prepare for getting down to work, but there is only so much you can do ahead of time.</p>
<p>This past Thursday (the 19th) we got together early for the kick-off meeting. It was an intense session with the client, where I mostly watched, listened, and encouraged. But toward the end of the meeting, the project was delivered in to my waiting hands. This looks to be a long term collaboration with the client, and I plan to use every trick I know (agile or otherwise) to make this successful! I’m still getting to know this project, and like any interesting job, it will certainly be a learning experience. I currently have another similar long term project with this particular client, but every one is different!</p>
<p>I plan to occasionally update this blog with the status of both projects. The client and I whiteboarded a bit of code to capture some metadata about the project as we see it currently:<br />
<span id="more-132"></span></p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style="">family.<span style="color:#9900CC;">children</span> <span style="color:#006600; font-weight:bold;"><<</span> Child.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">(</span> <span style="color:#ff3333; font-weight:bold;">:name</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'Leif Everett Crawley'</span>,
 <span style="color:#ff3333; font-weight:bold;">:gender</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#ff3333; font-weight:bold;">:male</span>,
 <span style="color:#ff3333; font-weight:bold;">:weight</span> <span style="color:#006600; font-weight:bold;">=></span> 8.<span style="color:#9900CC;">pounds</span> <span style="color:#006600; font-weight:bold;">+</span> 14.<span style="color:#9900CC;">ounces</span>,
 <span style="color:#ff3333; font-weight:bold;">:height</span> <span style="color:#006600; font-weight:bold;">=></span> 20.5.<span style="color:#9900CC;">inches</span>,
 <span style="color:#ff3333; font-weight:bold;">:born_at</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'Thu Feb 19 09:36:19 EST 2009'</span>,
 <span style="color:#ff3333; font-weight:bold;">:birth_location</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#ff3333; font-weight:bold;">:home</span> <span style="color:#006600; font-weight:bold;">)</span></pre></div></div>
<p><img class="aligncenter size-medium wp-image-136" title="177-7746_img" src="http://blog.tobiascrawley.net/posts/assets/old/177-7746_img-300x225.jpg" height="225" alt="177-7746_img" width="300" /></p>
<p>So far, things are going great! But projects like this are always easier at the beginning, the hard work comes much later!</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/01/30/collapsing-the-lighthouse-ticket-form/Collapsing the Lighthouse ticket form2009-01-30T00:00:00ZToby Crawley
We’ve been using lighthouse for the last few months to track bugs/features for RestaurantZite. Overall, its a pretty good bug tracker; not great, but good. One thing that bothers me about it is the expansive nature of the ticket entry/edit form: Usually, my browser is sized to where the submit button is off of the bottom of the screen, as well as the tag input. The description box is larger than it needs to be (for our use anyway, since we are describing bugs for ourselves and can usually capture it in sentence or two), and the whitespace to the......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>We’ve been using lighthouse for the last few months to track bugs/features for <a href="http://restaurantzite.com/">RestaurantZite</a>. Overall, its a pretty good bug tracker; not great, but good. One thing that bothers me about it is the expansive nature of the ticket entry/edit form:</p>
<p><img class="aligncenter size-full wp-image-121" title="before" src="http://blog.tobiascrawley.net/posts/assets/old/before.png" height="333" alt="before" width="523" /></p>
<p>Usually, my browser is sized to where the submit button is off of the bottom of the screen, as well as the tag input. The description box is larger than it needs to be (for our use anyway, since we are describing bugs for ourselves and can usually capture it in sentence or two), and the whitespace to the right of the description seems wasted. </p>
<p>To help with this, I wrote a custom stylesheet that turns the above form into:</p>
<p><img class="aligncenter size-full wp-image-128" title="after" src="http://blog.tobiascrawley.net/posts/assets/old/after-1.png" height="238" alt="after" width="520" /></p>
<p>Its not perfect, but works for me. I compacted the header and the subtab row as well, which will be reflected on all of the pages. I also compacted the ticket view page (which has this form at the bottom for updates) to reduce its vertical space usage.</p>
<p>The css is available for Firefox on <a href="http://userstyles.org/styles/14319">userstyles.org</a> for the <a href="https://addons.mozilla.org/en-US/firefox/addon/2108">Stylish</a> plugin, or as a <a href="http://gist.github.com/55066">gist</a>. I haven’t tried it in Safari or an <span class="caps">SSB, </span>so let me know how it works or what changes you had to make if you do.</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/01/10/server_remote-a-rails-plugin-for-easily-accessing-servers/server_remote - A Rails plugin for easily accessing servers2009-01-10T00:00:00ZToby Crawley
Note: this post is out of date. This tool is now a gem instead of a plugin; read all about it here. I just released server_remote on github. It is a plugin for connecting to remote servers. Once installed, it provides commands via script/remote: * remote shell – same as ssh’ing to the server (this is the default command, so it can be called with just remote) * remote console – executes a script/console on the server * remote logtail – executes tail -f log/<environment>.log on the server Configuration is in config/server_remote.yml, and is grouped into profiles. Here is the......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<div style="background-color: #ffc;border: 1px solid #777;padding: 12px;font-size:1.5em;text-align: center;line-height: 1.2em;">
<strong>Note:</strong> this post is out of date. This tool is now a gem instead of a plugin; read all about it <a href="http://blog.tobiascrawley.net/2009/03/31/server_remote-gem/">here</a>.<br />
</div>
I just released <a href="http://github.com/tobias/server_remote">server_remote</a> on github. It is a plugin for connecting to remote servers. Once installed, it provides commands via <code>script/remote</code>:<br />
* <code>remote shell</code> – same as ssh’ing to the server (this is the default command, so it can be called with just <code>remote</code>)<br />
* <code>remote console</code> – executes a <code>script/console</code> on the server<br />
* <code>remote logtail</code> – executes <code>tail -f log/<environment>.log</code> on the server
<p>Configuration is in <code>config/server_remote.yml</code>, and is grouped into <em>profiles</em>. </p>
<p>Here is the output of <code>remote usage</code>:</p>
<div class="wp_syntax"><div class="code"><pre class="html" style=""> Executes commands on a remote server over ssh. Configuration is in:
/Users/tobias/customers/DropZite/restaurantZite/config/server_remote.yml
 
You can override the profile used with -p profile. The default profile is: app
 
Learn more in the readme:
/Users/tobias/customers/DropZite/restaurantZite/vendor/plugins/server_remote/lib/README.textile
 
remote commands are:
 
DEFAULT COMMAND shell
 
commands List all 'remote' commands
console executes remote console
help Provide help documentation for a command
logtail executes remote tail -f on the log
shell executes remote shell
usage prints usage message
 
For help on a particular command, use 'remote help COMMAND'.</pre></div></div>
<p>It uses <a href="http://remi.org">remi’s</a> <a href="http://github.com/remi/simplecli">simplecli</a> gem. <br />
<br /><br />
I plan to add other commands as needed, or you can open up <code>Remote::Commands</code> and add your own. Install with: <code>script/plugin install git://github.com/tobias/server_remote.git</code></p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2009/01/01/generating-a-tags-file-from-a-git-hook/Generating a TAGS file from a git hook2009-01-01T00:00:00ZToby Crawley
Any decent programmer’s text editor provides some form of symbol lookup. With TextMate, the lookup table generation is built in. If you are using vim or emacs, you will need to use an external program to generate the lookup table. This post covers generating the lookup table for emacs (and with some slight modification, vi), and adding a hook to git to regenerate the table after a pull/merge. For more information on using symbol (tag) lookup with emacs or vim, see this wikia entry for vim, or this emacswiki entry for emacs. ctags Traditionally, the ctags/etags executable was used to......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>Any decent programmer’s text editor provides some form of symbol lookup. With <a href="http://macromates.com/">TextMate</a>, the lookup table generation is built in. If you are using vim or emacs, you will need to use an external program to generate the lookup table. This post covers generating the lookup table for emacs (and with some slight modification, vi), and adding a hook to git to regenerate the table after a pull/merge. For more information on using symbol (tag) lookup with emacs or vim, see <a href="http://vim.wikia.com/wiki/Browsing_programs_with_tags">this wikia entry</a> for vim, or <a href="http://www.emacswiki.org/emacs/EmacsTags">this emacswiki entry</a> for emacs.</p>
<h3>ctags</h3>
<p>Traditionally, the <code>ctags/etags</code> executable was used to generate lookup tables for vi/emacs respectively. <code>ctag</code> would create a <code>tags</code> file for vi, and <code>etag</code> would create a <code>TAGS</code> file for emacs. Unfortunately, the <code>etags/ctags</code> that ships with MacOS X does not parse ruby code. For that, you will need to use <a href="http://ctags.sourceforge.net/">Exuberant Ctags</a>. You can install Exuberant Ctags on MacOS via <a href="http://macports.org/">MacPorts</a> with <code>sudo port install ctags</code>. </p>
<h3>git hooks</h3>
<p>There are some nice hooks that you can define for git to call after/before it performs certain actions. You can read the full list <a href="http://www.kernel.org/pub/software/scm/git/docs/githooks.html">here</a>. Hooks are defined by placing properly named executables into <code>.git/hooks/</code> in your repo. The two hooks we care about here are <a href="http://www.kernel.org/pub/software/scm/git/docs/githooks.html#_post_merge">post-merge</a> and <a href="http://www.kernel.org/pub/software/scm/git/docs/githooks.html#_post_commit">post-commit</a> ( <strong>Update:</strong> the script has been modified to register for the <a href="http://www.kernel.org/pub/software/scm/git/docs/githooks.html#_post_checkout">post-checkout</a> hook as well, based on a suggestion from <a href="http://smartic.us/2009/04/03/creating-ctags-with-git-hooks/">Bryan Liles</a>). The <code>post-merge</code> hook will get called after you do a <code>git pull</code> to merge from another repository, and <code>post-commit</code> is called after a local commit. An important thing to remember about these hooks (and anything else in <code>.git</code>) is that they will not be pushed to the remote repo. So if you develop on multiple machines, or want to share hooks with coworkers, you will need to install them in each local repo.</p>
<h3>the kitchen sink</h3>
<p>Here is the script I use to handle generating tags from ruby code explicitly, generating tags from a git hook, and installing the git hooks. It really should be two different scripts, but… well… isn’t.</p>
<script src="http://gist.github.com/42308.js"></script>
<p>You can read it and see what it does. To have it install the hooks in the current repo, call it with the <code>-i@ option. If you use vim instead of emacs, you will need to remove the @-e</code> option and change <code>TAGS</code> to <code>tags</code> on the <code>ctags</code> call.</p>
<p>Once it is installed, your tags will be regenerated after every commit or pull. You can manually regenerate the tags by calling the script from the repo base directory. </p>
<p><strong>Update:</strong> to see a video of this script in action, check out Bryan Liles’ post on <a href="http://smartic.us/2009/04/03/creating-ctags-with-git-hooks/">smartic.us</a>.</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2008/12/22/setting-options-for-webby/Setting options for Webby2008-12-22T00:00:00ZToby Crawley
I’m using Webby to manage the static Hand Built Software site, and had a difficult time finding how to set defaults for the webby rake tasks (specifically the deploy:ssh task in this case). Here is what I figured out: you set the values at the top of your project Sitefile like so: #-*-ruby-*- SITE.user = 'tobias' SITE.host = 'handbuiltsoftware.com' SITE.remote_dir = '/path/to/site/' task :default => :build desc 'deploy the site to the webserver' task :deploy => [:build, 'deploy:ssh'] # EOF For reference, here are the webby defaults which can be overridden (from lib/webby.rb) # call-seq: # Webby.site => struct #......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>I’m using <a href="http://webby.rubyforge.org/">Webby</a> to manage the static <a href="http://handbuiltsoftware.com/">Hand Built Software</a> site, and had a difficult time finding how to set defaults for the webby rake tasks (specifically the <code>deploy:ssh</code> task in this case). Here is what I figured out: you set the values at the top of your project <code>Sitefile</code> like so:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""><span style="color:#008000; font-style:italic;">#-*-ruby-*-</span>
SITE.<span style="color:#9900CC;">user</span> = <span style="color:#996600;">'tobias'</span>
SITE.<span style="color:#9900CC;">host</span> = <span style="color:#996600;">'handbuiltsoftware.com'</span>
SITE.<span style="color:#9900CC;">remote_dir</span> = <span style="color:#996600;">'/path/to/site/'</span>
 
task <span style="color:#ff3333; font-weight:bold;">:default</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#ff3333; font-weight:bold;">:build</span>
 
desc <span style="color:#996600;">'deploy the site to the webserver'</span>
task <span style="color:#ff3333; font-weight:bold;">:deploy</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">[</span><span style="color:#ff3333; font-weight:bold;">:build</span>, <span style="color:#996600;">'deploy:ssh'</span><span style="color:#006600; font-weight:bold;">]</span>
 
<span style="color:#008000; font-style:italic;"># EOF</span></pre></div></div>
<p>For reference, here are the webby defaults which can be overridden (from <a href="http://github.com/TwP/webby/tree/master/lib/webby.rb">lib/webby.rb</a>)</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""> <span style="color:#008000; font-style:italic;"># call-seq:</span>
<span style="color:#008000; font-style:italic;"># Webby.site => struct</span>
<span style="color:#008000; font-style:italic;">#</span>
<span style="color:#008000; font-style:italic;"># Returns a struct containing the configuration parameters for the </span>
<span style="color:#008000; font-style:italic;"># Webby site. These defaults should be overridden as needed in the</span>
<span style="color:#008000; font-style:italic;"># site specific Rakefile.</span>
<span style="color:#008000; font-style:italic;">#</span>
<span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">site</span>
<span style="color:#0000FF; font-weight:bold;">return</span> <span style="color:#0066ff; font-weight:bold;">@site</span> <span style="color:#9966CC; font-weight:bold;">if</span> <span style="color:#9966CC; font-weight:bold;">defined</span>? <span style="color:#0066ff; font-weight:bold;">@site</span>
<span style="color:#0066ff; font-weight:bold;">@site</span> = OpenStruct.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">(</span>
<span style="color:#ff3333; font-weight:bold;">:output_dir</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'output'</span>,
<span style="color:#ff3333; font-weight:bold;">:content_dir</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'content'</span>,
<span style="color:#ff3333; font-weight:bold;">:layout_dir</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'layouts'</span>,
<span style="color:#ff3333; font-weight:bold;">:template_dir</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'templates'</span>,
<span style="color:#ff3333; font-weight:bold;">:exclude</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">%</span>w<span style="color:#006600; font-weight:bold;">(</span>tmp$ bak$ ~$ CVS \.<span style="color:#9900CC;">svn</span><span style="color:#006600; font-weight:bold;">)</span>,
<span style="color:#ff3333; font-weight:bold;">:page_defaults</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">{</span>
<span style="color:#996600;">'layout'</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'default'</span>
<span style="color:#006600; font-weight:bold;">}</span>,
<span style="color:#ff3333; font-weight:bold;">:find_by</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'title'</span>,
<span style="color:#ff3333; font-weight:bold;">:base</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#0000FF; font-weight:bold;">nil</span>,
<span style="color:#ff3333; font-weight:bold;">:create_mode</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'page'</span>,
<span style="color:#ff3333; font-weight:bold;">:blog_dir</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'blog'</span>,
<span style="color:#ff3333; font-weight:bold;">:tumblog_dir</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'tumblog'</span>,
 
<span style="color:#008000; font-style:italic;"># Items for running the heel webserver</span>
<span style="color:#ff3333; font-weight:bold;">:use_web_server</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#0000FF; font-weight:bold;">true</span>,
<span style="color:#ff3333; font-weight:bold;">:heel_port</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006666;">4331</span>,
 
<span style="color:#008000; font-style:italic;"># Items used to deploy the website</span>
<span style="color:#ff3333; font-weight:bold;">:user</span> <span style="color:#006600; font-weight:bold;">=></span> ENV<span style="color:#006600; font-weight:bold;">[</span><span style="color:#996600;">'USER'</span><span style="color:#006600; font-weight:bold;">]</span> <span style="color:#006600; font-weight:bold;">||</span> ENV<span style="color:#006600; font-weight:bold;">[</span><span style="color:#996600;">'USERNAME'</span><span style="color:#006600; font-weight:bold;">]</span>,
<span style="color:#ff3333; font-weight:bold;">:host</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'example.com'</span>,
<span style="color:#ff3333; font-weight:bold;">:remote_dir</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'/not/a/valid/dir'</span>,
<span style="color:#ff3333; font-weight:bold;">:rsync_args</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">%</span>w<span style="color:#006600; font-weight:bold;">(</span><span style="color:#006600; font-weight:bold;">-</span>av<span style="color:#006600; font-weight:bold;">)</span>,
 
<span style="color:#008000; font-style:italic;"># Global options for HAML and SASS</span>
<span style="color:#ff3333; font-weight:bold;">:haml_options</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">{</span><span style="color:#006600; font-weight:bold;">}</span>,
<span style="color:#ff3333; font-weight:bold;">:sass_options</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">{</span><span style="color:#006600; font-weight:bold;">}</span>,
 
<span style="color:#008000; font-style:italic;"># Options passed to the 'tidy' program when the tidy filter is used</span>
<span style="color:#ff3333; font-weight:bold;">:tidy_options</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'-indent -wrap 80'</span>,
 
<span style="color:#008000; font-style:italic;"># List of valid URIs (these automatically pass validation)</span>
<span style="color:#ff3333; font-weight:bold;">:valid_uris</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">[</span><span style="color:#006600; font-weight:bold;">]</span>,
 
<span style="color:#008000; font-style:italic;"># Options for coderay processing</span>
<span style="color:#ff3333; font-weight:bold;">:coderay</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">{</span>
<span style="color:#ff3333; font-weight:bold;">:lang</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#ff3333; font-weight:bold;">:ruby</span>,
<span style="color:#ff3333; font-weight:bold;">:line_numbers</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#0000FF; font-weight:bold;">nil</span>,
<span style="color:#ff3333; font-weight:bold;">:line_number_start</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006666;">1</span>,
<span style="color:#ff3333; font-weight:bold;">:bold_every</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006666;">10</span>,
<span style="color:#ff3333; font-weight:bold;">:tab_width</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006666;">8</span>
<span style="color:#006600; font-weight:bold;">}</span>,
 
<span style="color:#008000; font-style:italic;"># Options for graphviz processing</span>
<span style="color:#ff3333; font-weight:bold;">:graphviz</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">{</span>
<span style="color:#ff3333; font-weight:bold;">:path</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#0000FF; font-weight:bold;">nil</span>,
<span style="color:#ff3333; font-weight:bold;">:cmd</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'dot'</span>,
<span style="color:#ff3333; font-weight:bold;">:type</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'png'</span>
<span style="color:#006600; font-weight:bold;">}</span>,
 
<span style="color:#008000; font-style:italic;"># Options for tex2img processing</span>
<span style="color:#ff3333; font-weight:bold;">:tex2img</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">{</span>
<span style="color:#ff3333; font-weight:bold;">:path</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#0000FF; font-weight:bold;">nil</span>,
<span style="color:#ff3333; font-weight:bold;">:type</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'png'</span>,
<span style="color:#ff3333; font-weight:bold;">:bg</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'white'</span>,
<span style="color:#ff3333; font-weight:bold;">:fg</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'black'</span>,
<span style="color:#ff3333; font-weight:bold;">:resolution</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'150x150'</span>
<span style="color:#006600; font-weight:bold;">}</span>,
 
<span style="color:#008000; font-style:italic;"># Options for ultraviolet syntax highlighting</span>
<span style="color:#ff3333; font-weight:bold;">:uv</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">{</span>
<span style="color:#ff3333; font-weight:bold;">:lang</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'ruby'</span>,
<span style="color:#ff3333; font-weight:bold;">:line_numbers</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#0000FF; font-weight:bold;">false</span>,
<span style="color:#ff3333; font-weight:bold;">:theme</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">'mac_classic'</span>
<span style="color:#006600; font-weight:bold;">}</span>,
 
<span style="color:#008000; font-style:italic;"># XPath identifiers used by the basepath filter</span>
<span style="color:#ff3333; font-weight:bold;">:xpaths</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#006600; font-weight:bold;">%</span>w<span style="color:#006600; font-weight:bold;">(</span>
<span style="color:#006600; font-weight:bold;">/</span>html<span style="color:#006600; font-weight:bold;">/</span>head<span style="color:#006600; font-weight:bold;">//</span>base<span style="color:#006600; font-weight:bold;">[</span>@href<span style="color:#006600; font-weight:bold;">]</span>
<span style="color:#006600; font-weight:bold;">/</span>html<span style="color:#006600; font-weight:bold;">/</span>head<span style="color:#006600; font-weight:bold;">//</span>link<span style="color:#006600; font-weight:bold;">[</span>@href<span style="color:#006600; font-weight:bold;">]</span>
<span style="color:#006600; font-weight:bold;">//</span>script<span style="color:#006600; font-weight:bold;">[</span>@src<span style="color:#006600; font-weight:bold;">]</span>
<span style="color:#006600; font-weight:bold;">/</span>html<span style="color:#006600; font-weight:bold;">/</span>body<span style="color:#006600; font-weight:bold;">[</span>@background<span style="color:#006600; font-weight:bold;">]</span>
<span style="color:#006600; font-weight:bold;">/</span>html<span style="color:#006600; font-weight:bold;">/</span>body<span style="color:#006600; font-weight:bold;">//</span>a<span style="color:#006600; font-weight:bold;">[</span>@href<span style="color:#006600; font-weight:bold;">]</span>
<span style="color:#006600; font-weight:bold;">/</span>html<span style="color:#006600; font-weight:bold;">/</span>body<span style="color:#006600; font-weight:bold;">//</span>object<span style="color:#006600; font-weight:bold;">[</span>@data<span style="color:#006600; font-weight:bold;">]</span>
<span style="color:#006600; font-weight:bold;">/</span>html<span style="color:#006600; font-weight:bold;">/</span>body<span style="color:#006600; font-weight:bold;">//</span>img<span style="color:#006600; font-weight:bold;">[</span>@src<span style="color:#006600; font-weight:bold;">]</span>
<span style="color:#006600; font-weight:bold;">/</span>html<span style="color:#006600; font-weight:bold;">/</span>body<span style="color:#006600; font-weight:bold;">//</span>area<span style="color:#006600; font-weight:bold;">[</span>@href<span style="color:#006600; font-weight:bold;">]</span>
<span style="color:#006600; font-weight:bold;">/</span>html<span style="color:#006600; font-weight:bold;">/</span>body<span style="color:#006600; font-weight:bold;">//</span>form<span style="color:#006600; font-weight:bold;">[</span>@action<span style="color:#006600; font-weight:bold;">]</span>
<span style="color:#006600; font-weight:bold;">/</span>html<span style="color:#006600; font-weight:bold;">/</span>body<span style="color:#006600; font-weight:bold;">//</span>input<span style="color:#006600; font-weight:bold;">[</span>@src<span style="color:#006600; font-weight:bold;">]</span>
<span style="color:#006600; font-weight:bold;">)</span>
<span style="color:#008000; font-style:italic;"># other possible XPaths to include for base path substitution</span>
<span style="color:#008000; font-style:italic;"># /html/body//object[@usemap]</span>
<span style="color:#008000; font-style:italic;"># /html/body//img[@usemap]</span>
<span style="color:#008000; font-style:italic;"># /html/body//input[@usemap]</span>
<span style="color:#006600; font-weight:bold;">)</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>
<p><strong>Note:</strong> this applies to webby 0.9.3 </p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2008/12/21/stepping-off-the-rails-part-2/Stepping off the Rails - adventures with Sinatra (Part 2)2008-12-21T00:00:00ZToby Crawley
In this episode, our trusty adventurer actually runs his Sinatra app, and deploys it to Passenger on shared hosting. See Part 1 for details of building the application. Launching locally: two ways to skin a cat I realized that in Part 1 I did not cover launching the app to hit it from the browser. It’s easy! To launch the app, use ruby app_name.rb. This will fire up a mongrel instance on port 4567 for your viewing pleasure. Once you have defined your rack configuration (see below), you can also run the app inside rack locally with rackup config.ru to......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p><em>In this episode, our trusty adventurer actually runs his Sinatra app, and deploys it to Passenger on shared hosting. See <a href="http://blog.handbuiltsoftware.com/2008/12/18/stepping-off-the-rails-part-1/">Part 1</a> for details of building the application.</em></p>
<h3>Launching locally: two ways to skin a cat</h3>
<p>I realized that in <a href="http://blog.handbuiltsoftware.com/2008/12/18/stepping-off-the-rails-part-1/">Part 1</a> I did not cover launching the app to hit it from the browser. It’s easy! To launch the app, use <code>ruby app_name.rb</code>. This will fire up a mongrel instance on port <code>4567</code> for your viewing pleasure. </p>
<p>Once you have defined your rack configuration (see below), you can also run the app inside rack locally with <code>rackup config.ru</code> to test your rack settings. This will launch rack inside mongrel on port <code>9292</code>. Thanks to @jnunemaker for the <a href="http://railstips.org/2008/12/15/deploying-sinatra-on-dreamhost-with-passenger">tip</a>. In fact, John’s article is what I used as a basis for my deployment, with a few changes to support file based view templates.</p>
<h3>Rack Configuration</h3>
<p>To configure the application to run on rack under Passenger, you need to define a rack configuration file. Passenger expects that file to be named <code>config.ru</code> (see <a href="http://www.modrails.com/documentation/Users%20guide.html#_deploying_a_rack_based_ruby_application">Deploying a Rack-based Ruby application</a> in the Passenger documentation). Here is a minimum <code>config.ru</code> to run the application:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'rubygems'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'sinatra'</span>
 
disable <span style="color:#ff3333; font-weight:bold;">:run</span>
 
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'urlunwind.rb'</span>
run Sinatra.<span style="color:#9900CC;">application</span></pre></div></div>
<p>The only real configuration there is <code>disable :run</code>. This prevents Sinatra from starting a mongrel on port <code>4567</code> when the app file is required. This configuration would work for an app that uses no file based templates, and does not reference anything in <code>public/</code>. If you run this config with rackup on url_unwind (<code>rackup config.ru</code>), you’ll see errors like:</p>
<p><code>Errno::ENOENT: No such file or directory - /opt/local/bin/views/index.haml</code><br />
<br /><br />
<br /><br />
This is because rack by default sets its base directory to be the path to the called executable (and on my machine, <code>rackup</code> lives in <code>/opt/local/bin/</code>). So we’ll need to explicitly set the paths:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'rubygems'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'sinatra'</span>
 
disable <span style="color:#ff3333; font-weight:bold;">:run</span>
set <span style="color:#ff3333; font-weight:bold;">:views</span>, <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">dirname</span><span style="color:#006600; font-weight:bold;">(</span><span style="color:#0000FF; font-weight:bold;">__FILE__</span><span style="color:#006600; font-weight:bold;">)</span> <span style="color:#006600; font-weight:bold;">+</span> <span style="color:#996600;">'/views'</span>
set <span style="color:#ff3333; font-weight:bold;">:public</span>, <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">dirname</span><span style="color:#006600; font-weight:bold;">(</span><span style="color:#0000FF; font-weight:bold;">__FILE__</span><span style="color:#006600; font-weight:bold;">)</span> <span style="color:#006600; font-weight:bold;">+</span> <span style="color:#996600;">'/public'</span>
set <span style="color:#ff3333; font-weight:bold;">:app_file</span>, <span style="color:#0000FF; font-weight:bold;">__FILE__</span>
 
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'urlunwind.rb'</span>
run Sinatra.<span style="color:#9900CC;">application</span></pre></div></div>
<p>Now the app should run properly with <code>rackup</code>. </p>
<h3>Logging</h3>
<p>Sinatra uses rack’s built in logging to log requests, and these log messages get printed to standard out. It would be nice to log these to a file, and we can do that as well in <code>config.ru</code> (based on <a href="http://www.gittr.com/index.php/archive/logging-with-sinatra-and-passenger-another-try/">this tip</a> from Chris Schneider). We’ll also need to turn error raising back on, since by default Sinatra swallows errors in production mode:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'rubygems'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'sinatra'</span>
 
disable <span style="color:#ff3333; font-weight:bold;">:run</span>
set <span style="color:#ff3333; font-weight:bold;">:env</span>, <span style="color:#ff3333; font-weight:bold;">:production</span>
set <span style="color:#ff3333; font-weight:bold;">:raise_errors</span>, <span style="color:#0000FF; font-weight:bold;">true</span>
set <span style="color:#ff3333; font-weight:bold;">:views</span>, <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">dirname</span><span style="color:#006600; font-weight:bold;">(</span><span style="color:#0000FF; font-weight:bold;">__FILE__</span><span style="color:#006600; font-weight:bold;">)</span> <span style="color:#006600; font-weight:bold;">+</span> <span style="color:#996600;">'/views'</span>
set <span style="color:#ff3333; font-weight:bold;">:public</span>, <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">dirname</span><span style="color:#006600; font-weight:bold;">(</span><span style="color:#0000FF; font-weight:bold;">__FILE__</span><span style="color:#006600; font-weight:bold;">)</span> <span style="color:#006600; font-weight:bold;">+</span> <span style="color:#996600;">'/public'</span>
set <span style="color:#ff3333; font-weight:bold;">:app_file</span>, <span style="color:#0000FF; font-weight:bold;">__FILE__</span>
 
log = <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">(</span><span style="color:#996600;">"log/sinatra.log"</span>, <span style="color:#996600;">"a"</span><span style="color:#006600; font-weight:bold;">)</span>
STDOUT.<span style="color:#9900CC;">reopen</span><span style="color:#006600; font-weight:bold;">(</span>log<span style="color:#006600; font-weight:bold;">)</span>
STDERR.<span style="color:#9900CC;">reopen</span><span style="color:#006600; font-weight:bold;">(</span>log<span style="color:#006600; font-weight:bold;">)</span>
 
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'urlunwind.rb'</span>
run Sinatra.<span style="color:#9900CC;">application</span></pre></div></div>
<p>This allows you to add your own logging messages as well, just <code>puts</code>, <code>print</code>, or <code>p@ whatever you want to log. *Note:* you will need to create the @log/</code> directory for this to work.</p>
<h3>Deploy with Capistrano</h3>
<p>I used Capistrano to deploy to Dreamhost, and based my Capfile of off John’s directions <a href="http://railstips.org/2008/12/15/deploying-sinatra-on-dreamhost-with-passenger">here</a>. I modified it a bit to pull from github, and to create the <code>tmp/</code> and <code>log/</code> directories if they do not exist. Here is my Capfile:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""><span style="color:#008000; font-style:italic;">#-*-ruby-*-</span>
<span style="color:#CC0066; font-weight:bold;">load</span> <span style="color:#996600;">'deploy'</span> <span style="color:#9966CC; font-weight:bold;">if</span> respond_to?<span style="color:#006600; font-weight:bold;">(</span><span style="color:#ff3333; font-weight:bold;">:namespace</span><span style="color:#006600; font-weight:bold;">)</span> <span style="color:#008000; font-style:italic;"># cap2 differentiator</span>
 
default_run_options<span style="color:#006600; font-weight:bold;">[</span><span style="color:#ff3333; font-weight:bold;">:pty</span><span style="color:#006600; font-weight:bold;">]</span> = <span style="color:#0000FF; font-weight:bold;">true</span>
 
<span style="color:#008000; font-style:italic;"># be sure to change these</span>
set <span style="color:#ff3333; font-weight:bold;">:user</span>, <span style="color:#996600;">'app_user'</span>
set <span style="color:#ff3333; font-weight:bold;">:domain</span>, <span style="color:#996600;">'urlunwind.com'</span>
set <span style="color:#ff3333; font-weight:bold;">:application</span>, <span style="color:#996600;">'url_unwind'</span>
set <span style="color:#ff3333; font-weight:bold;">:git_path_prefix</span>, <span style="color:#996600;">"git@github.com/tobias/"</span>
 
<span style="color:#008000; font-style:italic;"># the rest should be good</span>
set <span style="color:#ff3333; font-weight:bold;">:repository</span>, <span style="color:#996600;">"#{git_path_prefix}#{application}.git"</span>
set <span style="color:#ff3333; font-weight:bold;">:deploy_to</span>, <span style="color:#996600;">"/home/#{user}/#{domain}"</span>
set <span style="color:#ff3333; font-weight:bold;">:deploy_via</span>, <span style="color:#ff3333; font-weight:bold;">:remote_cache</span>
set <span style="color:#ff3333; font-weight:bold;">:scm</span>, <span style="color:#996600;">'git'</span>
set <span style="color:#ff3333; font-weight:bold;">:branch</span>, <span style="color:#996600;">'master'</span>
<span style="color:#008000; font-style:italic;">#set :git_shallow_clone, 1</span>
set <span style="color:#ff3333; font-weight:bold;">:scm_verbose</span>, <span style="color:#0000FF; font-weight:bold;">true</span>
set <span style="color:#ff3333; font-weight:bold;">:use_sudo</span>, <span style="color:#0000FF; font-weight:bold;">false</span>
 
server domain, <span style="color:#ff3333; font-weight:bold;">:app</span>, <span style="color:#ff3333; font-weight:bold;">:web</span>
 
namespace <span style="color:#ff3333; font-weight:bold;">:deploy</span> <span style="color:#9966CC; font-weight:bold;">do</span>
task <span style="color:#ff3333; font-weight:bold;">:restart</span> <span style="color:#9966CC; font-weight:bold;">do</span>
run <span style="color:#996600;">"test -d #{current_path}/tmp || mkdir #{current_path}/tmp"</span>
run <span style="color:#996600;">"test -d #{current_path}/log || mkdir #{current_path}/log"</span>
run <span style="color:#996600;">"touch #{current_path}/tmp/restart.txt"</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>
<p>Since the Sinatra gem is not installed on Dreamhost, I put it in <code>vendor/</code> within the app. Since it is not a gem, it must be required with the full path to the base <code>.rb</code> file, both in <code>config.ru</code> and in the app file itself (<code>urlunwind.rb</code> in this case). Here is the final <code>config.ru</code>:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""><span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'rubygems'</span>
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'vendor/sinatra/lib/sinatra.rb'</span>
 
disable <span style="color:#ff3333; font-weight:bold;">:run</span>
set <span style="color:#ff3333; font-weight:bold;">:env</span>, <span style="color:#ff3333; font-weight:bold;">:production</span>
set <span style="color:#ff3333; font-weight:bold;">:raise_errors</span>, <span style="color:#0000FF; font-weight:bold;">true</span>
set <span style="color:#ff3333; font-weight:bold;">:views</span>, <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">dirname</span><span style="color:#006600; font-weight:bold;">(</span><span style="color:#0000FF; font-weight:bold;">__FILE__</span><span style="color:#006600; font-weight:bold;">)</span> <span style="color:#006600; font-weight:bold;">+</span> <span style="color:#996600;">'/views'</span>
set <span style="color:#ff3333; font-weight:bold;">:public</span>, <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">dirname</span><span style="color:#006600; font-weight:bold;">(</span><span style="color:#0000FF; font-weight:bold;">__FILE__</span><span style="color:#006600; font-weight:bold;">)</span> <span style="color:#006600; font-weight:bold;">+</span> <span style="color:#996600;">'/public'</span>
set <span style="color:#ff3333; font-weight:bold;">:app_file</span>, <span style="color:#0000FF; font-weight:bold;">__FILE__</span>
 
log = <span style="color:#CC00FF; font-weight:bold;">File</span>.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">(</span><span style="color:#996600;">"log/sinatra.log"</span>, <span style="color:#996600;">"a"</span><span style="color:#006600; font-weight:bold;">)</span>
STDOUT.<span style="color:#9900CC;">reopen</span><span style="color:#006600; font-weight:bold;">(</span>log<span style="color:#006600; font-weight:bold;">)</span>
STDERR.<span style="color:#9900CC;">reopen</span><span style="color:#006600; font-weight:bold;">(</span>log<span style="color:#006600; font-weight:bold;">)</span>
 
<span style="color:#CC0066; font-weight:bold;">require</span> <span style="color:#996600;">'urlunwind.rb'</span>
run Sinatra.<span style="color:#9900CC;">application</span></pre></div></div>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2008/12/18/stepping-off-the-rails-part-1/Stepping off the Rails - adventures with Sinatra (Part 1)2008-12-18T00:00:00ZToby Crawley
In this episode, our trusty adventurer leaves the warm and fuzzy confines of Rails, and explores an ‘alternative’ Ruby web framework. Part 1 will cover the app itself, and Part 2 will cover deployment. I must admit it: I’m one of those folks that came to Ruby because of Rails. And don’t get me wrong – I like Rails, but I frickin’ love Ruby. I’m not a clever person, but Ruby makes me feel clever every day. Ruby is a good friend, and I want to get to know it better outside of its relationship with Rails. I’m also interested......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p><em>In this episode, our trusty adventurer leaves the warm and fuzzy confines of Rails, and explores an ‘alternative’ Ruby web framework. Part 1 will cover the app itself, and <a href="http://blog.handbuiltsoftware.com/2008/12/21/stepping-off-the-rails-part-2stepping-off-the-rails-part-2/">Part 2</a> will cover deployment.</em></p>
<p>I must admit it: I’m one of those folks that came to Ruby because of Rails. And don’t get me wrong – I like Rails, but I frickin’ <strong>love</strong> Ruby. I’m not a clever person, but Ruby makes me <em>feel</em> clever every day. Ruby is a good friend, and I want to get to know it better outside of its relationship with Rails. I’m also interested in building simple web apps that don’t need the full weight of Rails. So I turned to <a href="http://sinatra.rubyforge.org">Sinatra</a>.</p>
<p>For those of you that don’t know all about it, Sinatra is a lightweight Ruby web application framework that takes a different approach than Rails. With Sinatra, you can write an entire web app in one file, with all of your templates inline (you can also have your templates in separate files instead, as we will see in a minute). Sinatra is rackable, and can be deployed in a <a href="http://rack.rubyforge.org">Rack</a> container, making it straightforward to deploy under <a href="http://modrails.com/">Passenger</a> (deployment is covered in <a href="http://blog.handbuiltsoftware.com/2008/12/21/stepping-off-the-rails-part-2stepping-off-the-rails-part-2/">Part 2</a>). There are lots of other good intros out there on Sinatra, and I’ll list a few at the bottom of this post.</p>
<h3>The Controller</h3>
<p>Let’s get started! The sample application here is <span class="caps">URLU</span>nwind. You can see it in operation at <a href="http://urlunwind.com/">urlunwind.com</a>, and see the full source on <a href="http://github.com/tobias/url_unwind">github</a>. It is a simple short <span class="caps">URL </span>unwinder, using <a href="http://www.ruby-doc.org/stdlib/libdoc/net/http/rdoc/index.html">Net::HTTP</a> to make a <span class="caps">HEAD </span>request and then pulling out the ‘Location:’ header.</p>
<p>Sinatra apps are based around one controller file. You can break out your controller actions into separate files, but will need to manually require them into the primary controller. For this app, the controller is <a href="http://github.com/tobias/url_unwind/tree/master/urlunwind.rb">urlunwind.rb</a>. Right now, we are just interested in the actions:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style="">get <span style="color:#996600;">'/'</span> <span style="color:#9966CC; font-weight:bold;">do</span>
haml <span style="color:#ff3333; font-weight:bold;">:index</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
 
post <span style="color:#996600;">'/unwind'</span> <span style="color:#9966CC; font-weight:bold;">do</span>
<span style="color:#0066ff; font-weight:bold;">@url</span>, <span style="color:#0066ff; font-weight:bold;">@unwound_url</span>, <span style="color:#0066ff; font-weight:bold;">@unwind_error</span> = unwind<span style="color:#006600; font-weight:bold;">(</span>params<span style="color:#006600; font-weight:bold;">[</span><span style="color:#ff3333; font-weight:bold;">:url</span><span style="color:#006600; font-weight:bold;">]</span><span style="color:#006600; font-weight:bold;">)</span>
haml <span style="color:#ff3333; font-weight:bold;">:index</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
 
get <span style="color:#996600;">'/unwind.json'</span> <span style="color:#9966CC; font-weight:bold;">do</span>
content_type <span style="color:#996600;">'application/json'</span>
 
<span style="color:#0066ff; font-weight:bold;">@url</span>, <span style="color:#0066ff; font-weight:bold;">@unwound_url</span>, <span style="color:#0066ff; font-weight:bold;">@unwind_error</span> = unwind<span style="color:#006600; font-weight:bold;">(</span>params<span style="color:#006600; font-weight:bold;">[</span><span style="color:#ff3333; font-weight:bold;">:url</span><span style="color:#006600; font-weight:bold;">]</span><span style="color:#006600; font-weight:bold;">)</span>
<span style="color:#006600; font-weight:bold;">{</span> <span style="color:#ff3333; font-weight:bold;">:from_url</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#0066ff; font-weight:bold;">@url</span>, <span style="color:#ff3333; font-weight:bold;">:to_url</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#0066ff; font-weight:bold;">@unwound_url</span>, <span style="color:#ff3333; font-weight:bold;">:error</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#0066ff; font-weight:bold;">@unwind_error</span> <span style="color:#006600; font-weight:bold;">}</span>.<span style="color:#9900CC;">to_json</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
 
get <span style="color:#996600;">'/stylesheets/style.css'</span> <span style="color:#9966CC; font-weight:bold;">do</span>
content_type <span style="color:#996600;">'text/css'</span>
 
sass <span style="color:#ff3333; font-weight:bold;">:style</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>
<p>To define an action, you use a simple <acronym title="Domain Specific Language">DSL</acronym>. It starts with the method (one of: ‘get’, ‘post’, ‘put’, ‘delete’, where ‘put’ and ‘delete’ are handled with a ‘_method’ parameter on a post), followed by the route that should trigger the action. The routes are searched in order they are defined until a match is found. You can include named parameters (with <code>:symbol</code>) or splat parameters (with *) in the routes as well (see the <a href="http://sinatra.rubyforge.org/">Sinatra page</a> for examples of this). In a similar fashion to Rails, parameters matched in the route, provided in the post body, or included in the url all end up in a <code>params</code> hash available to your action. </p>
<p>If a request fails to match any route, Sinatra looks for a matching file path in a <code>public/</code> directory in the same directory as the called executable (<code>$0@) (this path can be overridden). I use that feature to provide a "SASS":http://haml.hamptoncatlin.com/docs/rdoc/classes/Sass.html stylesheet, but I have other stylesheets in @public/stylesheets/</code> that are served statically. </p>
<p>After the action does it’s business, whatever it returns is given to the client. </p>
<h3>Rendering Views</h3>
<p>View templates can be defined in four ways: inline on the render call, embedded in the controller, using the <code>template</code> method, or in individual files. I prefer the cleanliness of having a separate file for each view, so used that approach. Sinatra will look for file based views in a <code>views/</code> directory in the same directory as the called executable (<code>$0@) (this path can also be overridden). You render a template by calling a method for the type of template it is. This app has only two templates: @index.haml</code> and <code>style.sass</code> (rendered with <code>haml :index</code> and <code>sass :style</code>, respectively). </p>
<p>As in Rails, ivars defined in the action are available within the template. You can also pass locals on the render call. </p>
<p>You can override the content-type for a particular action. I do that in the stylesheet and json actions with <code>content_type</code>. </p>
<h3>Testing</h3>
<p>Sinatra provides helpers for Test::Unit, Test::Spec, and RSpec. Here is a snippet from my Test::Unit <a href="http://github.com/tobias/url_unwind/tree/master/test/urlunwind_test.rb">tests</a>:</p>
<div class="wp_syntax"><div class="code"><pre class="ruby" style=""> <span style="color:#9966CC; font-weight:bold;">def</span> test_index
get_it <span style="color:#996600;">'/'</span>
assert_match <span style="color:#006600; font-weight:bold;">/</span>Unwind It<span style="color:#006600; font-weight:bold;">/</span>, <span style="color:#0066ff; font-weight:bold;">@response</span>.<span style="color:#9900CC;">body</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
 
<span style="color:#9966CC; font-weight:bold;">def</span> test_unwind_with_blank_url
post_it <span style="color:#996600;">'/unwind'</span>, <span style="color:#ff3333; font-weight:bold;">:url</span> <span style="color:#006600; font-weight:bold;">=></span> <span style="color:#996600;">''</span>
assert_match <span style="color:#006600; font-weight:bold;">/</span>Please enter<span style="color:#006600; font-weight:bold;">/</span>, <span style="color:#0066ff; font-weight:bold;">@response</span>.<span style="color:#9900CC;">body</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>
<p>Sinatra provides helpers to call the actions: <code>get_it</code>, <code>post_it</code>, <code>delete_it</code>, <code>put_it</code>. After calling any of these, the response is available in the <code>@respose</code> ivar. The test helpers have a little growing to do – I was only able to assert_match against the body of the response. It would be nice to have access to the assigned ivars as well (this may be changed in edge, I built all of this against the 0.3.2 gem version of Sinatra). </p>
<p>Since Sinatra looks for views relative to the executable, calling the tests with <code>ruby test/urlunwind_test.rb</code> had it looking for <code>test/views/</code>, which did not exist. I linked <code>test/views/</code> to <code>../views/</code>, and all was good. You could also probably define a <code>:test</code> environment configuration that set the path to the views as well. I’ll cover overriding the default paths in <a href="http://blog.handbuiltsoftware.com/2008/12/21/stepping-off-the-rails-part-2stepping-off-the-rails-part-2/">Part 2</a>, and you can read about configurations on the <a href="http://sinatra.rubyforge.org/">Sinatra</a> site.</p>
<h3>Project Structure</h3>
<p>Here is a snap of the project structure: <br />
<img class="size-full wp-image-34" title="layout" src="http://blog.tobiascrawley.net/posts/assets/old/layout.jpg" height="270" alt="layout" width="153" />
I’ll discuss the purpose of the <code>vendor/</code> and <code>config.ru</code> entries in <a href="http://blog.handbuiltsoftware.com/2008/12/21/stepping-off-the-rails-part-2stepping-off-the-rails-part-2/">Part 2</a> as part of my deployment discussion.</p>
<h3>Resources</h3>
<p>There are some good references out there for Sinatra (this list is by no means exhaustive):<br />
* <a href="http://sinatra.rubyforge.org/">The Sinatra Homepage</a> – In case you didn’t see the dozen links to it above<br />
* <a href="http://sinatra-book.gittr.com/">The Sinatra Book</a> – Which I discovered <strong>after</strong> writing this app. Wish I had seen it earlier.<br />
* Chris Schneider’s <a href="http://gittr.com/">blog</a> – A good resource of Sinatra tips. Chris also maintains the Sinatra Book.<br />
* #sinatra on irc.freenode.net – Folks there were quick to answer my deployment questions, and prodded me to provide a web service from the app.<br />
* The Sinatra <a href="http://groups.google.com/group/sinatrarb">mailing list</a><br />
* faithfulgeek’s ’10 Minute Web App’ <a href="http://www.vimeo.com/2374819">screencast</a><br />
* <strong>Update:</strong> Ruby Inside article – <a href="http://www.rubyinside.com/sinatra-29-links-and-resources-for-a-quicker-easier-way-to-build-webapps-1371.html">Sinatra: 29 Links and Resources For A Quicker, Easier Way to Build Webapps</a></p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2008/12/18/i-hate-ruby/I hate ruby2008-12-18T00:00:00ZToby Crawley
I love to read. In college, I had no social life for the first two years because I lived within walking distance of a 9-floor library. I always had a book in my pocket or in my hand, and read constantly. Sometimes I would read while walking to class. Then I got busy with college life, harder classes that required more coding and less reading. So reading became a hobby rather than an obsession. After college, I took a job working on a large app written in C at a company 3000 miles from home. I had time to read......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>I love to read. In college, I had no social life for the first two years because I lived within walking distance of a 9-floor library. I always had a book in my pocket or in my hand, and read constantly. Sometimes I would read while walking to class. Then I got busy with college life, harder classes that required more coding and less reading. So reading became a hobby rather than an obsession.</p>
<p>After college, I took a job working on a large app written in C at a company 3000 miles from home. I had time to read again! Not only was there no homework, there was no social life, since it was a new town. I also had a bit of time to read at work while the app was building and tests were running. </p>
<p>After the C project, I moved onto a team doing Java. Now, in addition to the building/testing time for reading, I was forced to read! Everything I wanted to do required reading 2-3 javadoc pages, with a ‘choose your own adventure’ element. I would have an object of class <code>A@, and what I really needed was an object of class @B</code>. Starting at the doc for each end, I would try different paths to get to the other end, often backtracking at dead ends. </p>
<p>Then I moved into web development, and started with good ole’ <span class="caps">PHP.</span> I lost a lot of the api adventure from Java and lost the build/test reading breaks (testing?). But I gained more time for reading! ‘How?’ you ask? Job security! The code I wrote lacked cohesion, followed few standards, and was unmaintainable by anyone else. I became an essential part of the organization, and could come and go as I pleased. So I read in the morning, came in late, read at lunch, and left early to read back at home.</p>
<p>And then it all went to shit. I started programming in ruby. </p>
<p>No more api reading – I would guess at method names, try them out in <code>irb</code>, and be right most if the time. No more compile breaks. Testing? Yes, but with autotest, it was <em>quick</em>. I could barely find my place on the page before the tests were done. No more job security – I was writing code the ‘ruby way’, or the ‘rails way’, and any competent ruby/rails programmer could pick it up. So no more leaving early/arriving late. And coding was fun again! All those other languages felt too much like work. So no more reading at home either – just sitting in front of my laptop, hacking away on crap. Hell, I even started doing the opposite of reading; I started writing about ruby.</p>
<p>F you ruby.</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->
http://blog.tobiascrawley.net/posts/2008/12/17/idle-hands-are-the-coders-tools/Idle hands are the coder's tools2008-12-17T00:00:00ZToby Crawley
After being busy for what seems like forever, things have slowed down the last couple of weeks, and I’ve been able to get a few things done. Like putting up a terribly ugly placeholder site for Hand Built Software, and starting this blog. I’ve also been trying to learn some new things and improve on some things I already kind of know. Last week I built a rails app from scratch, testing all the way. It was nice to truly be the boss of the project and call all of the shots. It was also nice to get back to......
<div class="padding">
</div>
<!-- end .padding -->
<div class="border-gray"></div>
<div class="padding">
<p>After being busy for what seems like forever, things have slowed down the last couple of weeks, and I’ve been able to get a few things done. Like putting up a terribly ugly placeholder site for <a href="http://handbuiltsoftware.com/">Hand Built Software</a>, and starting this blog.</p>
<p>I’ve also been trying to learn some new things and improve on some things I already kind of know. Last week I built a rails app from scratch, testing all the way. It was nice to truly be the boss of the project and call all of the shots. It was also nice to get back to basics with <a href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html">Test::Unit</a> and do <span class="caps">TDD </span>from the start. It was nice to build most of the application without hitting it with the browser; the context switch of switching from Emacs to FireFox wears me out sometimes, and I really dislike using the mouse when I’m coding. The app is a simple secret gift exchange name chooser, with a twist. You can play with it at <a href="http://hatfullofnames.com/">HatFullOfNames.com</a>.</p>
<p>Last night and today I built an app using <a href="http://sinatra.rubyforge.org/">Sinatra</a>, the lightweight Ruby web framework that is all the rage with the kids these days. It was a fun adventure – most of my Ruby experience so far has been within the Rails bubble. I plan to write a couple of posts about the experience – one covering working with Sinatra, the second covering deploying a Sinatra app to <a href="http://modrails.com/">Passenger</a> on shared hosting (<a href="http://dreamhost.com/">Dreamhost</a> in this case). This app is a short url unwinder, allowing you to see the destination of a short url <strong>before</strong> clicking on it. It also provides a web service to handle the lookups that returns <span class="caps">JSON.</span> Use it at <a href="http://urlunwind.com/"><span class="caps">URLU</span>nwind.com</a>.</p>
<p>I’ll get started on that Sinatra post right now…</p>
<!-- end .postmetadata -->
</div>
<!-- end .padding -->