<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/stylesheets/rss.css" type="text/css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>OnRails.org: Rake Command Completion Using Rake</title>
    <link>http://onrails.org/articles/2006/11/17/rake-command-completion-using-rake</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Ruby On Rails and related matters.</description>
    <item>
      <title>Rake Command Completion Using Rake</title>
      <description>&lt;p&gt;This is an update of a &lt;a href="http://onrails.org/articles/2006/08/30/namespaces-and-rake-command-completion"&gt;previous&lt;/a&gt; post.&lt;/p&gt;
&lt;p&gt;I just watched &lt;a href="http://onestepback.org/"&gt;Jim Weirich's&lt;/a&gt; talk on &lt;a href="http://rake.rubyforge.org/"&gt;Rake&lt;/a&gt; at the &lt;a href="http://pragmaticstudio.com/therailsedge/denver.html"&gt;Rails Edge Studio&lt;/a&gt; and decided to update the command completion script to use Rake itself for caching the tasks.  &lt;a href="http://errtheblog.com/post/33"&gt;Err the Blog&lt;/a&gt; did an update on my script last month to include caching for a nice speedup, so I took that and made sure the cache is regenerated when the Rakefile or any rake tasks found in your rails app have been updated.  I added this with just some straight ruby code, but Jim's talk made me realize that this type of thing is exactly is what rake is for.  So, here is the updated version:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;notextile&gt;  &lt;span class="comment"&gt;#!/usr/bin/env ruby&lt;/span&gt;

  &lt;span class="comment"&gt;# Complete rake tasks script for bash&lt;/span&gt;
  &lt;span class="comment"&gt;# Save it somewhere and then add&lt;/span&gt;
  &lt;span class="comment"&gt;# complete -C path/to/script -o default rake&lt;/span&gt;
  &lt;span class="comment"&gt;# to your ~/.bashrc&lt;/span&gt;
  &lt;span class="comment"&gt;# Nicholas Seckar &amp;lt;nseckar@gmail.com&amp;gt;&lt;/span&gt;
  &lt;span class="comment"&gt;# Saimon Moore &amp;lt;saimon@webtypes.com&amp;gt;&lt;/span&gt;
  &lt;span class="comment"&gt;# http://www.webtypes.com/2006/03/31/rake-completion-script-that-handles-namespaces&lt;/span&gt;
  &lt;span class="comment"&gt;# http://errtheblog.com/post/33&lt;/span&gt;

  &lt;span class="ident"&gt;exit&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt; &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;file?&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;Dir&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;pwd&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Rakefile&lt;/span&gt;&lt;span class="punct"&gt;'))&lt;/span&gt;

  &lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;rubygems&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;rake&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
  &lt;span class="constant"&gt;DOTCACHE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;expand_path&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;~&lt;/span&gt;&lt;span class="punct"&gt;'),&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.rake_task_cache&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Dir&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;pwd&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;hash&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="constant"&gt;RAKE_FILES&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;FileList&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="constant"&gt;__FILE__&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Rakefile&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;lib/tasks/**/*.rake&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;vendor/plugins/*/tasks/**/*.rake&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt;
  &lt;span class="ident"&gt;file&lt;/span&gt; &lt;span class="constant"&gt;DOTCACHE&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;RAKE_FILES&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
    &lt;span class="ident"&gt;tasks&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; `&lt;span class="ident"&gt;rake&lt;/span&gt; &lt;span class="punct"&gt;--&lt;/span&gt;&lt;span class="ident"&gt;silent&lt;/span&gt; &lt;span class="punct"&gt;--&lt;/span&gt;&lt;span class="ident"&gt;tasks`&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;split&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="escape"&gt;\n&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;).&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;line&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;line&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;split&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
    &lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;fileutils&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
    &lt;span class="ident"&gt;dirname&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;dirname&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;DOTCACHE&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="constant"&gt;FileUtils&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;mkdir_p&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;dirname&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;exists?&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;dirname&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;open&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;DOTCACHE&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;w&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;tasks&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="constant"&gt;Rake&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Task&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="constant"&gt;DOTCACHE&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;invoke&lt;/span&gt;
  &lt;span class="ident"&gt;tasks&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;File&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;read&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;DOTCACHE&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

  &lt;span class="ident"&gt;exit&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt; &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;&lt;span class="escape"&gt;\b&lt;/span&gt;rake&lt;span class="escape"&gt;\b&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="constant"&gt;ENV&lt;/span&gt;&lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;COMP_LINE&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;

  &lt;span class="ident"&gt;after_match&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="global"&gt;$'&lt;/span&gt;
  &lt;span class="ident"&gt;task_match&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;after_match&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;empty?&lt;/span&gt; &lt;span class="punct"&gt;||&lt;/span&gt; &lt;span class="ident"&gt;after_match&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;&lt;span class="escape"&gt;\s&lt;/span&gt;$&lt;/span&gt;&lt;span class="punct"&gt;/)&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;after_match&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;split&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;last&lt;/span&gt;
  &lt;span class="ident"&gt;tasks&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;tasks&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;select&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;^&lt;span class="expr"&gt;#{Regexp.escape task_match}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;task_match&lt;/span&gt;

  &lt;span class="comment"&gt;# handle namespaces&lt;/span&gt;
  &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;task_match&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;^([-&lt;span class="escape"&gt;\w&lt;/span&gt;:]+:)&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt;
    &lt;span class="ident"&gt;upto_last_colon&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="global"&gt;$1&lt;/span&gt;
    &lt;span class="ident"&gt;after_match&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="global"&gt;$'&lt;/span&gt;
    &lt;span class="ident"&gt;tasks&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;tasks&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;^&lt;span class="expr"&gt;#{Regexp.escape upto_last_colon}&lt;/span&gt;([-&lt;span class="escape"&gt;\w&lt;/span&gt;:]+)$&lt;/span&gt;&lt;span class="punct"&gt;/)&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{$1}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;tasks&lt;/span&gt;
  &lt;span class="ident"&gt;exit&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;&lt;/notextile&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I fixed the bug that &lt;a href="http://onrails.org/articles/2006/11/17/rake-command-completion-using-rake#comment-227"&gt;janfri&lt;/a&gt; pointed out.  The bug caused the first task to be missed.  I also changed it so it won't abort if rake isn't the first command on the command line.  This will allow stringing multiple commands together.  For instance:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;&lt;notextile&gt;rake db:migrate VERSION=0 &amp;amp;&amp;amp; rake db:migrate&lt;/notextile&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="http://onrails.org/files/rake-completion.rb"&gt;Enjoy&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Fri, 17 Nov 2006 15:57:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:0f1eb26e-8f30-4c04-91f9-04e10a6e7cfb</guid>
      <author>Lee Marlow</author>
      <link>http://onrails.org/articles/2006/11/17/rake-command-completion-using-rake</link>
      <category>Ruby</category>
      <category>Rails Tips</category>
    </item>
    <item>
      <title>"Rake Command Completion Using Rake" by Lee</title>
      <description>&lt;p&gt;Thanks, janfri&lt;/p&gt;


	&lt;p&gt;I updated the post and added a new feature, too!&lt;/p&gt;</description>
      <pubDate>Wed, 11 Apr 2007 16:31:57 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:b58aeb0d-72a9-4de2-acbd-f64b3190be42</guid>
      <link>http://onrails.org/articles/2006/11/17/rake-command-completion-using-rake#comment-344</link>
    </item>
    <item>
      <title>"Rake Command Completion Using Rake" by janfri</title>
      <description>&lt;p&gt;Line 19 is not correct, change it to:&lt;/p&gt;


	&lt;pre&gt;&lt;code&gt;tasks = `rake --silent --tasks`.split("\n").map { |line| line.split[1] }&lt;/code&gt;&lt;/pre&gt;


	&lt;p&gt;The warning is written to standarderr not standardout.&lt;/p&gt;</description>
      <pubDate>Wed, 31 Jan 2007 11:37:35 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:2cff70da-1bb3-475b-aaa8-6167047c674b</guid>
      <link>http://onrails.org/articles/2006/11/17/rake-command-completion-using-rake#comment-227</link>
    </item>
  </channel>
</rss>
