<?xml version="1.0" encoding="UTF-8"?>
<posts>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2009-12-01T01:41:53-05:00</created-at>
    <id type="integer">27</id>
    <posted-by>steve</posted-by>
    <posting>This is a skeletal way to implement autocompletion where candidates are chosen according to whether the letters (independent of order) are present in the search string and the candidate completion. Textmate does this extremely well in the Cmd+T file picker.

Someplace, implement:

&lt;pre&gt;&lt;code&gt;
  def unique_chars_match(partial, candidates)
    candidates.select{|candidate| partial.count(candidate) == partial.length}.sort
  end

  def completion_list_for(target, candidates)
    unique_chars_match(target, candidates)
  end
&lt;/code&gt;&lt;/pre&gt;

In your window delegate, implement:

&lt;pre&gt;&lt;code&gt;
  def control(control, 
              textView: view, 
              completions: completions, 
              forPartialWordRange: range, 
              indexOfSelectedItem: index)

    target = view.textStorage.string[range.location, range.length]
    completion_list_for(target, Strings::AutocompletionsFor[:keywords])
  end
&lt;/code&gt;&lt;/pre&gt;

Someplace else, create a Strings module and put a hash in there for custom autocompletions:

&lt;pre&gt;&lt;code&gt;
  module Strings
    AutocompletionsFor = {
      :animals =&gt; ['dog', 'cat', 'elephant', 'llama']
      :plants  =&gt; ['fern', 'tree', 'rosebush']
    }
  end
&lt;/code&gt;&lt;/pre&gt;
</posting>
    <title>Simple Autocomplete For MacRuby</title>
    <updated-at type="datetime">2009-12-01T01:41:53-05:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2009-06-18T15:08:24-04:00</created-at>
    <id type="integer">25</id>
    <posted-by>steve</posted-by>
    <posting>So it's been a while since "Hampton Catlin":http://haml.hamptoncatlin.com/docs/ first announced Haml -- a templating language originally anticipated primarily as a drop-in replacement for ERB in Rails. The attactive part about Haml for me was that semantic markup in HTML looks and feels different from how it is represented in the DOM and that difference leads to confusion creating selectors in stylesheets and Javascript. What a time waster.

How Hampton originally conceived Haml, and how it remains to this day, is as a whitespace-sensitive syntax. This is something you either love or you hate. There isn't much middle ground. Indentation implies containment. Here's an example of some Haml markup:

&lt;pre&gt;&lt;code&gt;
#header-block
  Haml is cool!
  Can't you just dig it?
&lt;/code&gt;&lt;/pre&gt;

The text is contained inside a DIV with an id of @header-block@. To me, this is natural, as I am obsessive about indenting my code anyhow. Just for the record, the output (which I can compile from the command line) is:

&lt;pre&gt;&lt;code&gt;
$ haml foo.haml
&lt;div id='header-block'&gt;
  Haml is cool!
  Can't you just dig it?
&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;

Now to Sass and only just superficially. Let's assume I have a stylesheet called foo.sass (I know @foo@ is a tremendously meaningful word, but stick with me). Then, to style this header, I will just:

&lt;pre&gt;&lt;code&gt;
#header-block
  :font
    :family   Arial, sans-serif
    :weight   bold
    :color    #311
  :text-align center
&lt;/code&gt;&lt;/pre&gt;

which visually relates exactly to the @#header-block@ in my markup. Here's the output:

&lt;pre&gt;&lt;code&gt;
$ sass foo.sass
#header-block {
  font-family: Arial, sans-serif;
  font-weight: bold;
  font-color: #311;
  text-align: center; }
&lt;/code&gt;&lt;/pre&gt;

Notice how the font attributes have been expanded into their proper CSS attributes? This is a trivial example and doesn't even begin to scratch the surface of why Haml and Sass are cool, but let's install them.

h2. Installing Haml and Sass

The only prerequisite for Haml and Sass is Ruby. If you are on a Mac, you will already have Ruby installed. Many Linux distros have Ruby or you can get it through one of the various package managers. If you are on Linux, you probably already know how to do this. On a PC, check out the "Windows Installer":http://rubyinstaller.rubyforge.org/wiki/wiki.pl. Not the very latest version of Ruby but it will do just fine.

Now that you have Ruby installed and added to your path, verify that by typing:

@ruby -v@

in a console window. You should get something like:

&lt;pre&gt;&lt;code&gt;
$ ruby -v
ruby 1.8.6 (2007-09-23 patchlevel 110) [i686-darwin9.1.0]
&lt;/code&gt;&lt;/pre&gt;

See, my Ruby installation isn't the latest and greatest either!

On to installing Haml and Sass.

&lt;pre&gt;&lt;code&gt;
gem install haml
&lt;/code&gt;&lt;/pre&gt;

That's it. If you don't have administrative privileges for the binary directory (say, on a Mac), just do:

&lt;pre&gt;&lt;code&gt;
sudo gem install haml
&lt;/code&gt;&lt;/pre&gt;

and type in your administrator password. If you ain't the administrator of your computer, you probably don't want to install software anyhow.

h2. What About My Legacy Code?

You almost certainly have plenty of HTML, CSS, and maybe RHTML laying around. How about that? Well, there are one-step converters:

@css2sass css-file@ outputs a neatly-formatted Sass file to the console. So, just do:

@css2sass foo.css &gt; foo.sass@ and you're off and running.

There is a parallel tool called @html2haml@. Same deal:

@html2haml foo.html &gt; foo.haml@ and you're ready to go.

For RHTML, which embeds Ruby, your mileage may vary. In particular, @html2haml@ may miss the subtlety of @begin@/@end@ code blocks. So, in an example containing embedded Ruby:

&lt;pre&gt;&lt;code&gt;
&lt;% content_for :analytics do -%&gt;MY_FINE_GOOGLE_ANALYTICS&lt;% end -%&gt;
&lt;/code&gt;&lt;/pre&gt;

and the result is:

&lt;pre&gt;&lt;code&gt;
$ html2haml foo.rhtml
- content_for :analytics do
MY_FINE_GOOGLE_ANALYTICS
- end
&lt;/code&gt;&lt;/pre&gt;

Not exactly right, as indentation signifies containment (remember?) and Haml considers Ruby blocks as containing code. The correct way to write this is:

&lt;pre&gt;&lt;code&gt;
- content_for :analytics do
  MY_FINE_GOOGLE_ANALYTICS
&lt;/code&gt;&lt;/pre&gt;

A fairly trivial edit.

h2. Ok, So You Have Another Templating Language. Big Deal.

The big deals are multiple. First, over time you will discover that Haml makes you more productive. More than that it does what those in the Ruby community call "make programmers happy." Wow! What a claim. But really, that's the effect it has on me and on other developers I work with. One guy hired me to take on part of a project and I showed him Haml. His response the next day was "where have you been all my life?".

But Sass is the place where the greatest clarification of your intent happens. Hampton and "Nathan Wiezenbaum":http://nex-3.com/ have driven out Sass well beyond an alternative syntax for CSS. The best way to show this is by example. Say you have an indecisive client. I know that seldom happens, but suppose it did. You sit down with the client and decide that the background of the site should be pink and the links almost red.

&lt;pre&gt;&lt;code&gt;
body
  :background-color #FB77F8
  :color            #000
  a
    &amp;:link
      :color        #FF182D
&lt;/code&gt;&lt;/pre&gt;

This kind of stuff tends to percolate throughout your styles, so you might have @td &gt; a@ that also had to be that attractive color red. So, using Sass variables, you can do a bit of refactoring. Refactoring in stylesheets! That's a big deal. Think about it:

&lt;pre&gt;&lt;code&gt;
!body_background_color =    #FB77F8
!body_text_color =          #000
!active_link_color =        #FF182D
!body_text_color =          #000

body
  :background-color= !body_background_color
  :color           = !body_text_color
  a
    &amp;:link
      :color       = !active_link_color
  td
    a
      &amp;:link
        :color     = !active_link_color
&lt;/code&gt;&lt;/pre&gt;

This compiles down to:

&lt;pre&gt;&lt;code&gt;
body {
  background-color: #fb77f8;
  color: black; }
  body a:link {
    color: #ff182d; }
  body td a:link {
    color: #ff182d; }
&lt;/code&gt;&lt;/pre&gt;

Notice how I dropped in the @td@ I could reuse the variable? Another thing to notice is the specificity of the selectors. In CSS the most specific rule wins. The more accurately you describe the element you want to affect, the more reliably the browser applies the rule. Who hasn't been bitten by specifying a rule that is too general and affects elements other than those intended? But Sass encourages the nesting of elements to be quite specific about what you intend to style.

h2. Sass Looks Like a Lot of Code and Syntax

At first blush, the number of lines of Sass it takes to generate a small amount of CSS, but the flexibility and clarity of this approach to describing styles, plus its reusability make it far easier to leverage some more advanced concepts like mixins. Here's a flavor of those, building on the above example:

&lt;pre&gt;&lt;code&gt;
!body_background_color =    #FB77F8
!body_text_color =          #000
!active_link_color =        #FF182D
!hover_link_color =         !active_link_color - #303030
!body_text_color =          #000

=link_color_set
  a
    &amp;:link
      :color       = !active_link_color
    &amp;:hover
      :color       = !hover_link_color

body
  :background-color= !body_background_color
  :color           = !body_text_color
  +link_color_set
  td
    +link_color_set
&lt;/code&gt;&lt;/pre&gt;

Now, any place a set of link colors needs to be specified, I just invoke the mixin @link_color_set@ and presto! It adds the styles defined in the @link_color_set@ module.

A couple of other things of note in the example above: First, I used arithmetic to create a slightly different but related hover link color. You don't have to use this, but arithmetic is handy for this use case. Second, with almost no work at all, I redefined every @link_color_set@ to have a hover pseudo-class.

By separating the variable and mixin module definitions into separate files, you can import them and reuse them across all the stylesheets in your application. Heck, if you really like them, reuse them across multiple projects!

h2. Some Places to Go From Here

Not discussed here is the integration between Haml/Sass and various Ruby Web frameworks such as Rails, Sinatra, Ramaze, merb, etc. You don't need to take a separate step to compile your Haml to HTML or your Sass to CSS. This happens on the fly as the first page is rendered. Only when you change your Haml or Sass does the file get recompiled.

Further Reading:

* "Haml on hamptoncatlin.com":http://haml.hamptoncatlin.com/
* "Sass on hamptoncatlin.com":http://haml.hamptoncatlin.com/docs/rdoc/classes/Sass.html
* "Chris Eppstein's Compass":http://acts-as-architect.blogspot.com/2008/11/introducing-compass.html</posting>
    <title>Haml and Sass: A Winning Combination</title>
    <updated-at type="datetime">2009-06-18T15:08:24-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2009-01-28T14:31:18-05:00</created-at>
    <id type="integer">24</id>
    <posted-by>steve</posted-by>
    <posting>I've been monkeying around with "god":http://god.rubyforge.org/ for process monitoring. Regardless of how you feel about religious issues, this tool is a pure-Ruby way to accomplish some of what "monit":http://mmonit.com/monit/ does. I'm not totally grokking certain aspects of either tool, but monit has a broad base of support. However, the script is of a proprietary form and ... well ... it felt sort of funny coming from a Ruby environment to have to hard code as much as I had to with monit.

By contrast, with god, I can DRY things up and account for environmental differences among the various servers (development, staging, production). I'm also able to define constants like RAILS_ROOT or RAILS_ENV that are natural to use coming from a Rails app. They're not baked in, but by simply setting:

  RAILS_ENV = `hostname` =~ /\.local/ ? 'development' : 'production'
  
I can approximate a development/production environment selector. I see no way to do this in one script using monit.

h2. Things Left Out of God

There are some things monit does that are not baked into god. Perhaps the biggest omission, and perhaps it's deliberate, is the lack of a web-hosted control panel. I personally don't miss it and think it's something of a security risk. Other things missing are mostly features that are baked into monit but that can be emulated in using god.

h2. God Is Configurable

Although the god mantra is fully-configurable, it's not always clear how to do this. I did a bunch of source code reading, and I'm pretty sure I have it wrong. But here are two places where I got things to work that I thought couldn't be done with this tool:

h3. Restart Process on File Mod

This is not so much a "configurable" option as it is an undocumented one. Take the case of an important batch process that's supposed to run every four hours. If it doesn't, the first option is restart and hope for the best. Here's the code:

  w.restart_if do |start|
    start.condition(:file_mtime) do |c|
      c.interval = 5.minutes
      c.path     = IMPORTANT_PROCESS_STATUS_FILE
      c.max_age  = 4.hours
    end
  end
  
The process itself is set to log to or touch the logfile when it finishes the process (because we want to make sure it didn't crash in the middle). What we're telling god is check every 5 minutes and if the log file is older than 4 hours, restart the process. Really, we don't have to check that often. It's just paranoia on my part.

h3. Restart the Process on File Not Exist

Ok, the above scenario works if the log file exists, but borks if not. We can't have that, so we use what I feel is the biggest hammer: lambdas. Here's the code:

  w.restart_if do |start|
    start.condition(:lambda) do |c|
      c.interval = 5.minutes
      c.lambda = lambda{!File.exist?(IMPORTANT_PROCESS_STATUS_FILE)}
    end
  end
  
Just as easy, and I've coded my condition in Ruby. The code inside the lambda is completely arbitrary, so it *is* a big hammer. Use with caution and test.

h3. Send Meaningful Email Notifications

The default email setup is described in the "god":http://god.rubyforge.org/ documentation, but the email is pretty unhelpful. It just says what the condition was and ends there. Here's a more helpful version:

  w.restart_if do |start|
    start.condition(:lambda) do |c|
      c.interval = 5.minutes
      c.lambda = lambda{!File.exist?(IMPORTANT_PROCESS_STATUS_FILE)}
      c.notify = {
        :contacts =&gt; ['developers'],
        :subject  =&gt; 'The World Bank -- Restarting Account Posting for Everybody!',
        :message  =&gt; 'The posting status log appeared to be missing -- restarting it so the economy will recover.',
        :priority =&gt; 1,
        :category =&gt; 'crisis'
        }
    end
  end

I hope this stuff is useful and if there are better ways, I'd sure like to hear them.</posting>
    <title>Using God for Process Monitoring</title>
    <updated-at type="datetime">2009-01-28T14:31:18-05:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2008-11-12T15:36:05-05:00</created-at>
    <id type="integer">23</id>
    <posted-by>steve</posted-by>
    <posting>Many Rails developers will create a default layout in application.html.erb and use it as a consistent wrapper for all pages rendered on a site. This is one of the cool features of Rails - consistent rendering of the site's layout. But what if you want to change things for certain controllers or actions.

h2. Layouts By Controller

This is the trivial case because all you need to do is:

&lt;code&gt;&lt;pre&gt;
  class AdminController &lt; Application
    layout 'admin'
    
    def some_action
    end
  end
&lt;/pre&gt;&lt;/code&gt;

and every action within AdminController uses admin.html.erb instead of application.html.erb. But how about a controller that handles some public-facing and some administrative aspects?

h2. Layouts With Exceptions

At first blush, this would also appear to be trivial. Just modify the code above as follows:

&lt;code&gt;&lt;pre&gt;
  class AdminController &lt; Application
    layout 'admin', :only =&gt; [:some_action]
    
    def some_action
    end
    
    def some_public_facing_action
    end
  end
&lt;/pre&gt;&lt;/code&gt;

At first glance this is flawless, and of course you're testing the action you changed, so you got suckered in. One day, you go to /some_public_facing_action and WTF?? There is no layout at all.

It turns out that what the line

  layout 'admin', :only =&gt; [:some_action]
  
really means is apply the 'admin' layout to @some_action@ and don't apply any layout to anything else. So you think, well, How's about:

&lt;code&gt;&lt;pre&gt;
  class AdminController &lt; Application
    layout 'admin', :only =&gt; [:some_action]
    
    def some_action
    end
    
    def some_public_facing_action
      render :layout =&gt; 'application'
    end
  end
&lt;/pre&gt;&lt;/code&gt;

Bzzzt! Wrong answer. Rails already believes the public facing action is exempt from layout.

h2. Using More Than One Layout in A Controller

The best way I've found to do this is to write a helper that determines on an individual basis which methods require which layout. Here's how:

&lt;code&gt;&lt;pre&gt;
  class AdminController &lt; Application
    layout :smart_layout
    
    def some_action
    end
    
    def some_public_facing_action
      render :layout =&gt; 'application'
    end
    
    protected
    def smart_layout
      admin_actions =  [:some_action]
      admin_actions.include?(action_name) ? 'admin' : 'application'
    end
  end
&lt;/pre&gt;&lt;/code&gt;

You may notice that I have only one action in my array, but more commonly, there will be multiple actions.

h3. Further Reading

See "Rails Guides":http://guides.rubyonrails.org/ for an in depth discussion of how layouts are inherited and controlled.</posting>
    <title>Rails Layouts on a Per-Method Basis</title>
    <updated-at type="datetime">2008-11-12T15:36:05-05:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2008-07-31T20:35:57-04:00</created-at>
    <id type="integer">22</id>
    <posted-by>steve</posted-by>
    <posting>Not that *you* would ever do this, but have you ever known anyone who wrote code like:

&lt;pre&gt;
&lt;code&gt;
&lt;%= form_tag(:action =&gt; 'inaction') do |f| %&gt;
&lt;/code&gt;
&lt;/pre&gt;

Well, that's the function call signature for form_for, and sometime muscle-memory is a bad thing. Adding the |f| parameter produces the odd error:

Multiple values for block parameter

Just in case you were doing some head scratching. And by the way, it's a benign warning so you won't get any code breakage unless you really use the parameter as the object for your form helpers.</posting>
    <title>multiple values for block parameter</title>
    <updated-at type="datetime">2008-07-31T20:35:57-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2008-07-07T23:06:45-04:00</created-at>
    <id type="integer">21</id>
    <posted-by>steve</posted-by>
    <posting>Didja ever wonder how to send a particular HTTP header as part of your functional test or controller spec? Ever wonder who would care about something like that? Read this spec:

&lt;pre&gt;
- PostsController receiving Ajax requests  
  - Should send the information back as JSON
&lt;/pre&gt;

Ok, spot quiz: How the heck to you emulate an Ajax call correctly from your rSpec code (and the answer is not "use post")?

Answer. You probably already guessed. Use the HTTP headers to inform Rails what you had in mind.

Here's a snippet:

&lt;pre&gt;
  &lt;code&gt;
describe PostsController, "receiving Ajax calls" do
  it "Should send the information back as JSON" do
    request.env['HTTP_ACCEPT'] = 'application/json, text/javascript, */*'
    request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
    get :index, :id =&gt; 666
  end
end
  &lt;/code&gt;
&lt;/pre&gt;

See, my Ajax call happens using the GET method but it's still an Ajax request. Why? Because I said so. No, actually because the request was made using XmlHttpRequest.

I also get JSON back if I have a respond_to that responds to json.

This is a great way to make sure your controllers are responding the the protocol as you expect and that they are shipping back the desired data.</posting>
    <title>rSpec: Sending Headers to Controllers</title>
    <updated-at type="datetime">2008-07-07T23:08:22-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2008-04-27T17:48:28-04:00</created-at>
    <id type="integer">20</id>
    <posted-by>steve</posted-by>
    <posting>Today I posted a couple of simple jQuery plugins on github. They are:

jquery.focus_first.js
jquery.rails_ajax_hook.js

You can clone them by doing:

&lt;code&gt;
  &lt;pre&gt;
git clone git://github.com/sxross/jquery_plugins.git
  &lt;/pre&gt;
&lt;/code&gt;

The first one simply sets the focus on the first INPUT element in a form, if such a form exists. Usage:

&lt;code&gt;
  &lt;pre&gt;
$(document).ready(function(){
  $(this).focusFirstInput();
}
  &lt;/pre&gt;
&lt;/code&gt;

That's it!

The second, ajaxLinkBind, is more complicated. Its purpose is to bind to an 'a' element and invoke some Ajax action in a Rails controller. Here's how it works.

(X)HTML

&lt;code&gt;
  &lt;pre&gt;
    &lt;div class='linkable-by-ajax'&gt;
      hey &lt;a href="/some/place"&gt;click here&lt;/a&gt;.
      &lt;span id="update-me"&gt;&lt;/span&gt;
    &lt;/div&gt;
  &lt;/pre&gt;
&lt;/code&gt;

Clearly, this is just a thing that links using an HTTP GET request, right? But add the following Javascript and this plugin:

&lt;code&gt;
  &lt;pre&gt;
    $('.linkable-by-ajax').ajaxLinkBind(
      {
        success: function(json){
          $('#update-me').html(json['results']);
        }
      }
    )
  &lt;/pre&gt;
&lt;/code&gt;

...and presto! You have Ajax. The GET is replaced by an Ajax POST with an Accept-Type of Application/json, and the response is interpreted as JSON. Because the options hash maps directly onto the options hash of _$.ajax()_, you can use any of the options available, although I would recommend constraining yourself to dealing with success and error. Additionally, because this is designed to decay gracefully into an HTTP GET if Javascript is not enabled, stuffing things into _data_ is a "really bad idea."

Finally, a word about your Rails controller. Use a snippet like this:

&lt;code&gt;
  &lt;pre&gt;
    def my_method
      respond_to do |wants|
        # Expected case, the Ajax request. Just set the JSON variable "results" and let the Javascript render it.
        wants.json {
          render :json =&gt; {:results =&gt; 'the magic number is 42!'}
        }
        # Downlevel result where browser Javascript is turned off. Set the flash to our message and go back
        # whence we came.
        wants.html {
          flash['info'] = 'the magic number is 42!'
          redirect_to request.referer
        }
      end
    end
  &lt;/pre&gt;
&lt;/code&gt;</posting>
    <title>jQuery Plugins</title>
    <updated-at type="datetime">2008-04-27T17:54:10-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2007-04-08T14:41:56-04:00</created-at>
    <id type="integer">11</id>
    <posted-by>steve</posted-by>
    <posting>Recently (like, yesterday), I decided to create a Haml filter to wrap inline Javascript. If you don't know about Haml, see "here":http://haml.hamptoncatlin.com.

What Haml is, essentially, is a drop-in replacement for Rails' rhtml. What a filter is, essentially, is a chunk of reusable code that filters an arbitrary block of text, performs some transformation and inserts it into the generated (X)HTML stream. An example of a filter is markdown. E.g.:

&lt;pre&gt;
  &lt;code&gt;
    :markdown
      This is **bold** and *who knows* what this is?
  &lt;/code&gt;
&lt;/pre&gt;

Ok, with that introduction out of the way, the filter I needed would allow me to insert Javascript inline with a minimum of muss and fuss.

The steps required to create such a filter are (thanks to Hampton, Nathan, and Evgeny):

Create a file that implements the filter (in this case /lib/inline_javascript.rb):

&lt;pre&gt;
  &lt;code&gt;
  module Haml
    module Filters
      class InlineJavascript
        def initialize(text)
          @text =&lt;&lt;EOS
  &lt;script type="text/javascript"&gt;
    //&lt;![CDATA[
      #{text.chomp}
    //]]&gt;
  &lt;/script&gt;
  EOS
        end

        def render
          Haml::Helpers.find_and_preserve(@text)
        end
      end
    end
  end  
  &lt;/code&gt;
&lt;/pre&gt;

That all there is to the implementation. The next thing is to inform Haml of the presence of this filter. That is done by setting @Haml::Template.options[:filters]@. I did this by adding the following lines to the bottom of my /config/environment.rb:

&lt;pre&gt;
  &lt;code&gt;
  require 'inline_javascript'

  # define an additional filter to create inline javascript
  Haml::Template.options = {
    :filters =&gt; {
      'inline_javascript' =&gt; Haml::Filters::InlineJavascript
    }
  }
  &lt;/code&gt;
&lt;/pre&gt;

Now, I can do this in my Haml template:

&lt;pre&gt;
  &lt;code&gt;
:inline_javascript
  function onLoad()
  {
    // do something
  }
%p back to regular Haml
  &lt;/pre&gt;
&lt;/code&gt;

And the result is:

&lt;pre&gt;
  &lt;code&gt;
  &lt;script type="text/javascript"&gt;
    //&lt;![CDATA[
      window.onload = function () { applesearch.init(); }
    //]]&gt;
  &lt;/script&gt;
  &lt;p&gt;back to regular Haml&lt;/p&gt;
  &lt;/code&gt;
&lt;/pre&gt;

So the natural question I asked myself is: Why is this better than a helper? I'm not sure I have a good answer for this, but the occasion for inline javascript across an application can be vast and putting helpers for each specific instance of javascript could be unduly burdensome. On the other hand, if you have the same inline javascript that's shared all over the place, a shared partial with the inline_javascript filter would be DRY.</posting>
    <title>Creating New Haml Filters</title>
    <updated-at type="datetime">2008-03-31T23:31:52-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2008-02-26T13:04:30-05:00</created-at>
    <id type="integer">19</id>
    <posted-by>steve</posted-by>
    <posting>h3. 911 The Depot App in AWDROR Won't Work Without Scaffolding!

As of Rails 2.0, the deprecation warnings came out and so did a number of features present in earlier versions. One of the greatest pain points has been the removal of dynamic scaffolding. There have been some extensive discussions on the Rails mailing list regarding the "removal of scaffolding":http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/2e95e738ad82a602/dbf4eca81377993a?#dbf4eca81377993a (other threads exist as well).

I want to be completely clear that scaffolding still exists in Rails as a one-shot generator. If you create a migration, run it, then generate a scaffold, you will be rewarded with a proper RESTful chunk of generated code in the expected places. What is now missing is the ability to define a controller class thusly:

&lt;pre&gt;
  &lt;code&gt;
    class PeopleController
      scaffold :person
    end
  &lt;/code&gt;
&lt;/pre&gt;

It's gone, extracted to its own plugin. Bear with me while I break the discussion down a bit further, then I promise to give you the short solution.

There have been several central themes, as far as I can tell:

# Removing dynamic scaffolding breaks almost all existing learning information. Creating the Depot application described in AWDROR (Thomas, et. al.) simply doesn't work with Rails 2.0 and there's no obvious way to get unstuck. There's no obvious way to know what went wrong.
# Removing dynamic scaffolding makes it more difficult to integrate new Rails code with legacy databases that could involve numerous tables and columns, and the number of form fields quickly get ugly.
# Removing dynamic scaffolding is great for you seasoned Rails vets but it sucks for us n00bs who are trying to learn.

In a world devoid of alternative solutions I would agree with these points and also with the comment made on the mailing list that the Rails core team was "out of touch." But there are tons of alternatives and nothing really went away. I'll get to that later. First, cut to the chase.

h3. How To Get Depot Back On the Rails

Follow along in the book and where they say to type @rails depot@, don't. Instead, type:

@$ rails depot --database=mysql@

The reason for this is that the new Rails default database is SQLite instead of MySQL. Personally, I think this was a good decision because even though it wasn't a big deal, creating 3 MySQL databases and then remembering to blow them away was a PITA when I was just creating a project to test assumptions. With SQLite, when I do a @rm -rf depot@, everything including my dev and test database vaporizes.

Next, remember how I said none of the functionality was gone, it was simply extracted? Well, let's plug it back in.

Do this:

&lt;pre&gt;
  &lt;code&gt;
    cd depot
    ruby script/plugin install scaffolding
    ruby script/plugin install svn://errtheblog.com/svn/plugins/classic_pagination
  &lt;/code&gt;
&lt;/pre&gt;

Note: This last bit installs the Rails pagination code which scaffolding's list action relies on.

At this point, you should be ready to continue on with the Depot tutorial.

h3. For Your Consideration

In days gone by, we relied on a "vendor" to supply us all the system-level plumbing we needed as we developed applications. I was stunned when I started looking at Rails and discovered there was such a nicely formed framework with no thought given to authentication. This, I was sure, was such a commonly performed implementation detail that there had to be a standard Rails way to get users logged in. Right? Wrong. Several different authentication thingies were floating around, complete with the authors' caveats that they knew there was cruft in their solution or your needs might vary. Now there a numerous different authentication solutions ranging from model-based to role-based to RESTful, and lots of others. See, there really isn't a one-size-fits-all authentication solution.

Why is this even remotely relevant? Because where a feature was perceived as useful, people made it available as open source and you could judge it on its merits. The same goes for scaffolding and pagination. Rails scaffolding and pagination have been the punching bags of the codebase for a long while, and people only miss them now that they're gone.

I would encourage you to finish your Depot application, learn to love Rails, but also to consider what you might choose as alternatives for scaffolding and pagination.

A few I would point to are:

"ActiveScaffold":http://activescaffold.com/  &lt;br /&gt;
"will_paginate":http://errtheblog.com  &lt;br /&gt;
"paginating_find":http://cardboardrocket.com/pages/paginating_find</posting>
    <title>Getting Depot to Work in Rails 2.0</title>
    <updated-at type="datetime">2008-02-26T13:07:06-05:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2008-01-21T23:03:22-05:00</created-at>
    <id type="integer">18</id>
    <posted-by>Steve</posted-by>
    <posting>Nope. This is not an ad for some technical school. Fooled you, huh? This is more about the technique of learning to program. In the olden dayes when computers had core memory and dinosaurs still roamed the earth, there was a high cost associated with computing cycles. So, people who burned those cycles were selected from the (about) 7 who knew how to write code.

Now the cost of computing cycles has dropped asymptotic to zero, and everybody is a programmer. Right? Well, not so much. Even though the barrier to entry has dropped dramatically, the fact still remains that some people know how to write code and some don't. If you're in the latter category but want to transition to the former, you have to *learn* how. Let me suggest a few really obvious ways to fail:

* Pick up a book called "[anything] for Dummies" and start reading. Won't work. Programming is not for dummies.
* Pick up a book about something complicated, start typing in their code and become frustrated when you don't understand the errors you're getting.
* Join a mailing list and ask 100 questions at once.

These might seem like, duh, simple observations, but observed behavior shows that these are patterns people repeat and wonder why their success rate is so poor. Let me finish venting about the "Dummies" books. I don't just hate them. I feel any book on computer programming, nuclear physics, cellular genetics, etc. that contains words like, "made easy" or "quick start," is just insulting. These are serious pursuits. Heck, I probably wouldn't even buy "Quilting for Dummies," and I have no idea whether smart or dumb people make quilts -- I just don't think I'm a dummy. Ok, I guess I've made my position on demeaning book titles clear.

The rest of this is a bit more complicated. There are a ton of really, *really* cool books out there that people with the correct level of expertise can pick up and learn from. People without that expertise will be totally lost, frustrated, or misguided. So, let's take my favorite complicated task made easy: Developing Web applications. Say you haven't really tried your hand at this programming gig, but you threw a few pages together with Dreamweaver or something like that. Yesterday in the bookstore, you happened across a book by this fellow Dave Thomas that had a title filled with all kinds of impressive buzzwords like "agile" and "web development" and even more compelling, "Ruby on Rails"! A couple of titles to the left was the book you really should have gotten - also by Dave Thomas - but no, you just had to go right out and build a Web site, right?

So you lug the book home, open it up, read the clever little intro and skim a few more pages before you realize you aren't understanding a whole lot of this. But wait, you think, there are examples in here and I can try them and all will become clear. And at that moment, you start into a spin from which you will not recover soon. You see, what you just did was to take on a programming task before learning to program.

Now, the right thing to do when faced with this situation is to head back to the bookstore and pick up "Programming Ruby: The Pragmatic Programmer's Guide," which was what you intended to get in the first place, had you just known. But that's not going to happen. First, you have to go through the other phases of being a n00b programmer.

Phase 1 - Denial: You can get this. Just work through a few more examples in the book and you'll become an expert. It worked when you learned HTML, right?

Phase 2 - Resentment: You're not getting this. Nothing works. This book isn't worth a s&amp;!t.

Phase 3 - Blame: You've got the wrong computer. All the cool kids have Macs and that's why they write beautiful code that I can't understand. It's your computer's fault. Oh, yeah, and the fault of that guy who wrote the book.

Phase 4 - Spam: Aha! There's a mailing list. A *public* mailing list. How cool is that. Now, I'll just put all my code out there with a descriptive subject line like "please diagnose my error" and all those nice Open Sourcies who have nothing better to do will figure this out for me.

Phase 5 - Public Humiliation: Someone on the list finally tires of translating what that nice Dave Thomas wrote in the book into something you understand and tells you to go back and reread it until you've grasped at least one chapter.

Somewhere along this path, you get enough information to realize your quest is not about a Web site but about knowing how to program enough to build one. And if you internalize that wisdom, you'll now head back to the bookstore and buy Dave Thomas's "Programming Ruby" book (aka: Pickaxe).

I'm picking on Ruby, Rails, and most of all Dave Thomas (sorry, Dave). I should note that Dave's books are among the best I have on my shelf and when you are ready for them, read them in the right order. This could just as easily have been written about PHP, ASP.Net, or any other hot technology.

At this point, you're probably fed up with me and you might even be wondering whether I have anything positive to contribute here (or is this another one of those blog rants). I think I do. Here it is:

* Learn to walk before you try to run. If you can't make write a program to add 2 + 2, you're not a programmer. If you can't write a program to print "hello, world," you're not a programmer. You need to understand the facilities offered by the language, its grammar, and perhaps more importantly, its idioms. Don't do anything complicated until you can demonstrate to yourself that you've mastered these things.
* Learn to walk before you try to run. Even if you know how the language you've selected works, do you know how to model a simple problem using that language? For example, storing an arbitrary number of states/provinces and their associated abbreviations for quickest retrieval. Printing a sorted list of those states and provinces.

You see where I'm going with this? The first part is rote memorization of keywords and syntax, sort of like multiplication tables; the second is an application of what you've learned sort of like solving your first word problem.

So now you are a programmer. At least you read the book cover to cover and wrote some programs that work, right? Just a word about the mailing lists and forums (or is that fora?).

* Before you are tempted to post a question, be sure you have used Google or some search engine likely to succeed at finding the information. Far too many posts are answered with the advice (correct) to type a particular string into Google.
* Consider sharing your hard-won wisdom before you ask for someone else's. Some people actually won't ask a question unless they have found three they can answer first. The say they often answer their own question in the interim. In any event, no matter what multiplier you choose, the point is to give back to the community and to give yourself an incentive to figure things out yourself.

If you agree, disagree, think it's the pot calling the kettle black, or if you're Dave Thomas and think I should have picked a different example, feel free to chime in.</posting>
    <title>Learn to Program</title>
    <updated-at type="datetime">2008-01-21T23:03:22-05:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2008-01-02T00:10:44-05:00</created-at>
    <id type="integer">17</id>
    <posted-by>steve</posted-by>
    <posting>h1. Real quick. What's Gonna Break When I Upgrade to Rails 2.0.2?

I'm sure I don't know the answer to this question, but if you are upgrading an application from a 1.x version of Rails to 2.0.2, something sure will break. Guaran-effing-teed. So, let's see what those things might be (and these are just the ones I tripped over yesterday):

h2. Session Store Changes

If you were using ActiveRecord based sessions, you can continue to do that. I recommend you change to the new cookie-based session store. Here's why:

* It's faster. No database hit.
* It scales better. No dependency on pages being served from the same computer.
* It cleans up better. No more deleting files in tmp or aging off session records in the database. Automagically, it's taken care of.

Concerns? Everyone screamed that this was a gaping security hole. But the cookie data is 512-bit encrypted, and really how much sensitive material do you store in the session? If the answer is anything greater than "none," then you're the one opening the security hole.

Preparations: You have to generate a "secret" and put it in the configuration part of environment.rb. Here's a sample:

&lt;code&gt;
  &lt;pre&gt;
    Rails::Initializer.run do |config|
      # stuff...
      config.action_controller.session = {
        :session_key =&gt; '_my_app_session',
        :secret      =&gt; '241b740a2f480d9776e6ce0c36b51f9df46ecf1d25814cd03b4d14dbb6ba7cd92'
      }
      #stuff...
    end
  &lt;/pre&gt;
&lt;/code&gt;

This isn't too tricky. The session manaager is going to use this to name your session cookie and authenticate it. Suit yourself regarding naming and what sort of secret passphrase you want to choose. A random string of hex digits seems pretty ok to me.

The important thing that's been biting people is that if you don't change your session_key from the one you *were* using, a TamperedWithCookie exception will be raised for returning visitors. Not a seamless user experience so take care out there.

h2. Dynamic Scaffolding Is Gone. Period.

Scaffolding is officially extracted to a plugin, and that's pretty keen because you can tell the "we didn't take any functionality away" story. But that's not the whole story. Scaffolding depends on other stuff that also has been extracted to another plugin, like "classic_pagination". Now, before I go any further down this path, let me emphasize.

&lt;strong&gt;DYNAMIC SCAFFOLDING IS GONE&lt;/strong&gt;

But you can still do the @script/generate scaffold person@ you've grown to know and love. You can also use one of the cool scaffold plug-ins like ActiveScaffold.

My recommendation is that you avoid scaffolding where possible. It's a great way to show CRUD in a hurry, but doesn't buy you much in the long term. If you want to DRY up common usage patterns, look at something like make_resourceful ("there's a post on nex3's blog":http://nex-3.com/posts/7). Sure, you have to code a few views, but what the hey?

h2. Um, Did I Mention Pagination

If you are using pagination, guess what? Rails "classic pagination" has been extracted to a plugin (I think I already said that). I believe this is more of a death sentence for pagination, as evidenced by the comments in the code recommending will_paginate which you can pick up at @svn://errtheblog.com/svn/plugins/will_paginate@. It won't take you long to get in the swing of paginating err's way.

h2. Singular Model, Plural Controller

Rails is opinionated, but it took a while before the opinion was unanimous regarding whether controllers should be singular or plural. The vote's in and your controllers should be plural if you want to play nice with @map.resources@. You can read more about this on "Ryan's Scraps":http://ryandaigle.com/; point is, Rails will like you better if you have @PeopleController@ instead of @PersonController@.

Models, of course, are mappings to a single row of data, so they typically are singular. There is, of course, the ongoing debate regarding whether models should be so tightly coupled to the data layer, but we won't get into that. Rails will like you better if you have a @Country@ model rather than a @Countries@ model.

h2. Capistrano Is v.2 Now, Too!

Well, sigh, no sense enduring the pain of a major version upgrade of your platform if you don't get the added joy of upgrading your deployment tools. If you aren't using Capistrano for deployment, then shame on you (kidding... it's just too easy). If you are using 1.x, there are some things to make note of. Look "here":http://www.capify.org/upgrade for information about upgrading, but for heaven's sake, deploy to a test server before you totally hose up your production box.

h2. Semi-Wrapup

This is getting a little long and it's not supposed to be a list of changes -- more a few of the things that bite first when you move to Rails 2.x from an earlier version. If you decide to take an action-based Rails app and change it to a RESTful architecture, you'll be spending more time on that, but it's not a gotcha. You don't have to be RESTful. You'll just be made to feel guilty sitting in the corner all by yourself.

Well that's all for now. Hope this was useful and feel free to chime in any inaccuracies or glaring omissions.</posting>
    <title>Upgrading to Rails 2.0</title>
    <updated-at type="datetime">2008-01-02T00:11:17-05:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2007-10-25T14:26:31-04:00</created-at>
    <id type="integer">16</id>
    <posted-by>Steve</posted-by>
    <posting>This is an old topic, but one worth revisiting occasionally. Most of us use some commercial software. Perhaps not the Linux-only devs, but on a PC or Mac it's the norm to purchase some critical applications. For example, although some of the new word processing and spreadsheet applications are pretty good, Microsoft Word and Excel really are better. Honest. While GIMP is ok, Photoshop really is better. Honest. When there is a need for Flash ... um ... you need Flash.

So that brings me to the crux of the issues: Terms of the license, and compliance checking.

h1. Terms of the License

I'm totally ok with paying people for their work. I expect to be paid for mine and others should be paid for theirs. My beef is with licensing terms that inhibit my use of software I *pay* for. Let's take the "Single CPU" license agreement. I use agreement in the loosest sense of the word, because you really have no choice but to agree other than not using the software.

The Single CPU agreement essentially says I can use a piece of software I purchased on exactly one computer and if I have, say, a laptop and a desktop computer, I need to buy an extra copy. I understand the spirit of the license; it is to prevent people from buying one copy of the software and passing it around the office, loaning it to friends, and so on. While agreeing with the spirit of it, I find the reality is to cause the software to be less useful to me because it simply doesn't fit my workflow. I think that sucks. If I'm pounding away on some development project on my desktop computer, then go to a client site with a copy and my laptop, I don't want to license yet another copy of all my commercial tools just so I can make a couple of on-site changes.

The software industry can and should do better.

h1. Electronic Activation

This is such a bad idea that I can't even begin to describe it. If you purchase the software, you are required to register over the Internet. A magic cookie is exchanged between the vendor's server and the installation program. That installation program scribbles some veiled piece of data somewhere in the filesystem of your computer without your permission. That piece of data is the key to unlock the software. Yeah, it can be hacked, but that's not the point. Here *is* the point. I have tons of software, some of it shrink-wrap, some electronic download. If I do an OS upgrade, or screw up my disk, or (perish the thought) get a new computer, I get the delightful chore of remembering each piece of software I have and begging each vendor individually to have mercy on my license and give me a new key. I shouldn't have to do this. In some cases, I can dredge up the old key, and in some cases it even works. Actually, Microsoft has done an ok job of this, but at the expense of storing information about my computer on their servers. I'm ok with that but you might not be.

Not to name names, but Adobe is particularly bad about this. To "move" an Adobe application from one machine to the other, you have to deactivate it on the first computer, then install it on the new computer and activate it. But what if the old computer is DOA. Adobe is no help at all. I have deceased versions of very expensive, licensed Adobe software that I have simply given up on. And that's unforgivable.

h1. Network Probing

This is the practice of putting out a ping over the network to see if other copies of the same software are running. The notion is that if another copy is found, then one copy should be prevented from running. Clearly, if you follow the Single CPU argument, then you agree that this is an ok idea. But it, again, prevents me from having two computers that I own running similar software without licensing it twice. Microsoft did this with Mac Office.

Well rant off. I just had to get this off my chest.</posting>
    <title>Why Copy Protection Is Not Ok</title>
    <updated-at type="datetime">2007-10-25T14:26:31-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2007-07-18T01:52:12-04:00</created-at>
    <id type="integer">15</id>
    <posted-by>steve</posted-by>
    <posting>Often the programming pattern "set this to such-and-such unless it already has a value" pops up. It's what default parameters were invented for, but the problem is not limited to function calls. Ruby has a nifty idiom to handle this.

Here's the expanded version

&lt;pre&gt;
  &lt;code&gt;
    if options[:title].nil?
      options[:title] = options[:alt]
    end
  &lt;/code&gt;
&lt;/pre&gt;

We could make this a bit more terse by compressing it thusly:

&lt;pre&gt;
  &lt;code&gt;
    options[:title] = options[:alt] if options[:title].nil?
  &lt;/code&gt;
&lt;/pre&gt;

Looking better, but there's a more idiomatic way to express this:

&lt;pre&gt;
  &lt;code&gt;
    options[:title] ||= options[:alt]
  &lt;/code&gt;
&lt;/pre&gt;

The @||=@ operator is called the "conditional assignment" operator. In fact, what's happening in the expression @lhs ||= rhs@ is this:

&lt;pre&gt;
  &lt;code&gt;
    lhs = lhs || rhs
  &lt;/code&gt;
&lt;/pre&gt;

So lhs is evaluated to find out whether it produces a @true@ value. Remember, @nil@ evaluates to @false@ in a boolean test. If it does evaluate to @true@ the boolean OR short-circuit kicks in and the assignment is made (i.e., the variable @lhs@ remains unchanged). However, if @lhs@ is @nil@, it evaluates to @false@, forcing the evaluation of @rhs@ and assignment of that evaluation to @lhs@.

Mind you, we haven't saved any machine cycles, but the next time you see

&lt;pre&gt;
  &lt;code&gt;
    @title ||= 'myfinesite.com'
  &lt;/code&gt;
&lt;/pre&gt;

You'll know what it does!</posting>
    <title>Using Conditional Assignments</title>
    <updated-at type="datetime">2007-07-18T01:52:12-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2007-03-27T12:04:18-04:00</created-at>
    <id type="integer">7</id>
    <posted-by>steve</posted-by>
    <posting>If you read my "post":http://calicowebdev.com/blog/show/2 on rSpec, you may infer that I am trying to track its development. Recently, there have been some changes in trunk worthy of mention.

In particular the context/specify syntax has changed to describe/it. The old specs won't break, but the new syntax is more about telling and not asking. The contrived example is:

&lt;pre&gt;
  &lt;code&gt;
      describe "A BlogController" do
        it "should load index page successfully"
          get :index
          response.should_be_success
        end
      end
  &lt;/code&gt;
&lt;/pre&gt;
      
I updated the earlier post to reflect the new syntax, restating the example, here's how it would read:

&lt;pre&gt;
  &lt;code&gt;
    describe "Given a request to change quantity, the CartController should" do
        include Stubs
        controller_name "carts"
        integrate_views

        setup do
            Cart.stub!(:new).and_return(stub_cart)
            LineItem.stub!(:find_by_id).and_return(stub_line_item)

            @cart = stub_cart
            @line_item = stub_line_item

            post :change_quantity, {:id =&gt; 1, :quantity =&gt; 1}
        end

          it "respond w/ success" do
            response.should be_success
          end

          it "assign extension_id" do
            assigns[:extension_id].should == "extension1"
          end

          it "assign line_item" do
            assigns[:line_item].should equal(@line_item)
          end

          it "update the html (using rjs)" do
            controller.should have_rjs(:replace_html,
              'cartstatus',
              /1 item/)
            controller.should have_rjs(:replace_html,
              'cartstatus',
              /\$35\.00/)
          end
    end
    &lt;/code&gt;
&lt;/pre&gt;

Note that the code reads more like natural language. I am telling the code that "it should respond w/success". Having said what the controller (or model) should do, I then write code to make it so. 

Of particular note to those who've tried rSpec is the removal of some syntactic sugar. That means where we used to say

&lt;pre&gt;
  &lt;code&gt;
foo.should_be(bar)
  &lt;/code&gt;
&lt;/pre&gt;

we now say

&lt;pre&gt;
  &lt;code&gt;
foo.should be(bar)
  &lt;/code&gt;
&lt;/pre&gt;

The key is that there is a space after "should." Same for:

&lt;pre&gt;
  &lt;code&gt;
foo.should_not be(baz)
  &lt;/code&gt;
&lt;/pre&gt;

Also note that "be" is not the same as "eql." If you are intending the __same__ object, then use "be", for example:

&lt;pre&gt;
  &lt;code&gt;
foo.should be(true)
  &lt;/code&gt;
&lt;/pre&gt;

If you are expecting equality, say

&lt;pre&gt;
  &lt;code&gt;
foo.should eql('hello')
  &lt;/code&gt;
&lt;/pre&gt;

Give it a try!</posting>
    <title>rSpec Redux</title>
    <updated-at type="datetime">2007-05-11T12:57:32-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2007-02-09T18:55:25-05:00</created-at>
    <id type="integer">2</id>
    <posted-by>steve</posted-by>
    <posting>"rSpec":http://rspec.rubyforge.org/documentation/index.html is my favorite tool du jour. Test Driven Development is all good and it works, but Behavior Driven Development (BDD) seems far more natural to me. What's the difference? As much as anything it's one of attitude. With TDD, you are saying "run this thing and let's see if it's broken." But there is no implicit description about what "this thing" is supposed to do.

With BDD, you are actually spec'ing in executable code. These specs are detailed enough to verify that the code that meets the spec does what you want. Here's an example. Say you are creating a shopping cart. Yes, another frikken shopping cart. Yanking out one part of the functionality of the controller -- the part where you change the quantity of a particular 
item -- your spec might read, in part:

&lt;pre&gt;&lt;code&gt;
  describe "Given a request to change quantity, the CartController should" do
      include Stubs
      controller_name "carts"
      integrate_views

      setup do
          Cart.stub!(:new).and_return(stub_cart)
          LineItem.stub!(:find_by_id).and_return(stub_line_item)

          @cart = stub_cart
          @line_item = stub_line_item

          post :change_quantity, {:id =&gt; 1, :quantity =&gt; 1}
      end

        it "respond w/ success" do
          response.should be_success
        end

        it "assign extension_id" do
          assigns[:extension_id].should == "extension1"
        end

        it "assign line_item" do
          assigns[:line_item].should equal(@line_item)
        end

        it "update the html (using rjs)" do
          controller.should have_rjs(:replace_html,
            'cartstatus',
            /1 item/)
          controller.should have_rjs(:replace_html,
            'cartstatus',
            /\$35\.00/)
        end
  end
&lt;/code&gt;&lt;/pre&gt;

You'll have to take my word for it that I created mock objects that describe @Cart@ and @LineItem@. But, yipee, skipee, when I write the code that makes this come true, I have a cart in which I can change quantity. The point is, if you read this right (or run the specdoc task), you get something along these lines:

&lt;pre&gt;&lt;code&gt;
Given a request to change quantity, the CartController should

- respond w/ success
- assign extension_id
- assign line_item
- update the html (using rjs)
&lt;/code&gt;&lt;/pre&gt;

Now that's a plain English version of the same thing. Pretty cool, huh?</posting>
    <title>rSpec -- Behavior Driven Development</title>
    <updated-at type="datetime">2007-05-11T12:48:05-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2007-05-03T15:54:10-04:00</created-at>
    <id type="integer">14</id>
    <posted-by>steve</posted-by>
    <posting>Ruby is a great language and the various test frameworks that support it make writing solid code easier. But... Ruby is a magical language and testing magical things can be a bit ... shall we say ... interesting. One goal of testing is to predict the future and then watch happily when your prediction comes true. That means maintaining tight and relevant control over the kind of data you are testing with and how your program interacts with that data.

Enough of the totally abstract, here's a more concrete example. When testing Rails controllers, it's best not to confuse your tests with ActiveRecord behavior, even though you are almost certainly using ActiveRecord to retrieve your data. The typical Test::Unit methodology is to:

# Load up a bunch of fixtures with fake data -- one fixture for each unit under test
# Specify fixtures :foo for each unit that needs foo's
# Drink copious amounts of coffee while the database is emptied, populated with the fixture data, rolled back, and so on, and so on.

This works great because your controller is working with real ActiveRecord objects. However, it relies on your having put reasonable test data in the fixtures -- fixtures that can quickly become out of sync with your model and your test requirements.

h3. Mocking and Stubbing

A better way to approach much of your testing is to use mock objects or to stub certain functionality. I'm not sure I have my head wrapped completely around this and opinions vary on how best to approach it. Here's how I think of mocking and stubbing.

__Mock__ when you know what you expect your controller (from our example) to do with an object (like call it once with three arguments)
__Stub__ when you don't much care what the controller does but you want to provide the controller certain data

So, for example, say we have controller code such as:

&lt;code&gt;
  &lt;pre&gt;
    def display_people
      @person = Person.find_by_name('Bob Smith')
    end
  &lt;/pre&gt;
&lt;/code&gt;

Straightforward. Now let's look at how to test this. Assuming the "Mocha mock framework":http://mocha.rubyforge.org/:

&lt;code&gt;
  &lt;pre&gt;
    def test_display_people_should_find_bob_smith
      Person.stubs(:find_by_name).returns({:name =&gt; 'bob smith', :address =&gt; '123 Main St.'})
      get :display_people
      assert_not_nil assigns(:person)
    end
  &lt;/pre&gt;
&lt;/code&gt;

Hardly earthshaking code, but it illustrates one key point: You don't even need a functioning model to test a controller. In fact, you probably want to isolate the tests such that such reliance doesn't crop up in your code. Beyond testing a controller method in the absence of a real model, we've also accomplished a few other neat tricks:

* eliminated all the database setup/takedown
* sped up the test run

Now for the fun part. Let's modify the controller to have a success and a conditions path. First the test:

&lt;code&gt;
  &lt;pre&gt;
    def test_display_people_should_find_bob_smith
      Person.stubs(:find_by_name).returns({:name =&gt; 'bob smith', :address =&gt; '123 Main St.'})
      get :display_people
      assert_not_nil assigns(:person)
      assert_nil flash[:error]
    end
    
    def test_display_people_should_set_flash_if_bob_goes_missing
      Person.stubs(:find_by_name).returns(nil)
      get :display_people
      assert_nil assigns(:person)
      assert_equal 'no bob smith here. look next door', flash[:error]
    end
  &lt;/pre&gt;
&lt;/code&gt;

Ok, if you're following along, you have your test failing because of the new feature you are about to add. Let's fix the controller to provide that feature.

&lt;code&gt;
  &lt;pre&gt;
    def display_people
      @person = Person.find_by_name('Bob Smith')
      flash[:error] = 'no bob smith here. look next door' unless @person
    end
  &lt;/pre&gt;
&lt;/code&gt;

All of this works equally well in "rSpec":http://rspec.rubyforge.org, which I prefer:

&lt;code&gt;
  &lt;pre&gt;
    describe "A DummyController displaying people" do
      it "should find bob smith" do
        Person.stub!(:find_by_name).and_return({:name =&gt; 'bob smith', :address =&gt; '123 Main St.'})
        get :display_people
        assigns[:person].should_not be_nil
        flash[:error].should be_nil
        end
      end
      
      it "should set a flash if bob smith goes missing" do
        Person.stub!(:find_by_name).and_return(nil)
        get :display_people
        assigns[:person].should be_nil
        flash[:error].should eql('no bob smith here. look next door')
      end
    end
  &lt;/pre&gt;
&lt;/code&gt;

Mocha and rSpec's built-in mock frameworks have similar syntax and capability, but if you have to settle on one, it could be that Mocha - because it works across testing frameworks - is the better choice. Fortunately, it's as simple as this.

In Test::Unit

@require 'mocha'@

In rSpec spec_helper.rb

@config.mock_with :mocha@

Note that any time you change your version of rSpec and do a script/generate rspec, you will have to readd this to your spec_helper.</posting>
    <title>Testing: Mocking, Stubbing, and Rails, Oh My!</title>
    <updated-at type="datetime">2007-05-03T15:54:10-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2007-04-17T21:17:03-04:00</created-at>
    <id type="integer">13</id>
    <posted-by>steve</posted-by>
    <posting>For existing projects, I find myself spec'ing ex-post-facto (which I know is not the *true* spirit of BDD :). I go through iterations like:

# read the code and find all the methods
# put them in a new spec file
# try to say something interesting about their expected behavior
# get the specs to pass
# run rcov
# go back to 3

I decided to write a tool to do very crude parsing of Ruby files to yank out public methods to be spec'ed (my own presumption being that behavior can be spec'ed by describing the public methods). Because it is so Rails-biased, It also makes the assumption that the code to be spec'ed is expressed as class methods rather than at the module level.

The tool is "here":http://www.calicowebdev.com/downloads/spec_todo.rb.gz.

Usage is:

&lt;pre&gt;
  &lt;code&gt;
ruby spec_todo.rb &lt;files&gt;
  &lt;/code&gt;
&lt;/pre&gt;

So, for example, I might use it as follows:

&lt;pre&gt;
  &lt;code&gt;
ruby spec_todo.rb app/models/* app/controllers/*
  &lt;/code&gt;
&lt;/pre&gt;

Here is a brief example of the output of this tool:

&lt;pre&gt;
  &lt;code&gt;
#------------------------------------------------------------
# File: app/controllers/contact_controller_spec.rb
#------------------------------------------------------------

require File.dirname(__FILE__) + '/../spec_helper'

describe "A ContactController" do
  controller_name :contact
  integrate_views    # comment out if you spec views separately

  it "should do something sensible with index." do
    # Your spec here
  end

  it "should do something sensible with thank_you." do
    # Your spec here
  end
end
  &lt;/code&gt;
&lt;/pre&gt;

This is somewhat fashioned after ZenTest's ability to generate test scaffolding, but makes no attempt to integrate the scaffolding with existing specs, preferring to echo results to stdout.

At present, this "spec-todo" tool does not create any specs for validations. It completely ignores mix-in and inherited methods. Why? Well, try this exercise:

&lt;code&gt;
  &lt;pre&gt;
&gt;&gt; Cart.public_methods(false).length
=&gt; 254
&gt;&gt; Cart.public_methods(true).length
=&gt; 389
  &lt;/pre&gt;
&lt;/code&gt;

As you can see, even excluding methods that are not considered "in the receiver," I have 254 methods in my Cart model. So, using Ruby's introspection to yank methods out seemed like more of a noise generator than a time saver.

See if you like it.</posting>
    <title>Bootstrapping RSpec Generation</title>
    <updated-at type="datetime">2007-04-17T21:24:56-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2007-03-30T01:35:01-04:00</created-at>
    <id type="integer">10</id>
    <posted-by>steve</posted-by>
    <posting>Haml has made my Rails development far more precise and the number of display glitches far fewer. But, templating emails remained the exclusive domain of rhtml and its ilk. The challenge has been how to get ActionMailer to recognize what ActionView already did: That other templating languages besides rhtml, rxml, erb, and builder exist. Turns out the hard-coding was recognized and flagged as a TODO in the code.

I put together a patch ("see the patch":http://dev.rubyonrails.org/ticket/7534) for Rails, and good news it looks like it was accepted. I was overjoyed. Now I could write email templates in Haml! Right? I thought so, but it appears the patch was not committed -- at least in trunk as of this writing (poke, poke, prod, prod). Not one to easily give up, I adopted a different strategy: A plugin.

So, here it is: TemplatedMailer!

You can get it via svn at:

&lt;pre&gt;
  &lt;code&gt;
    http://svn.calicowebdev.com/plugins/templated_mailer
  &lt;/code&gt;
&lt;/pre&gt;

or the normal plugin installation process:

&lt;pre&gt;
  &lt;code&gt;
    ruby script/plugin install http://svn.calicowebdev.com/plugins/templated_mailer
  &lt;/code&gt;
&lt;/pre&gt;

h2. Where Are the Docs?

Well, there really aren't any, but you can run @rake doc:plugins@ to generate an rdoc version of this (and all your other plugins). Here it is in a nutshell.

# Install the plugin
# In your environment.rb, add this line at the bottom:

&lt;pre&gt;
  &lt;code&gt;
    ActionMailer::Base.register_template_extension('haml')
  &lt;/code&gt;
&lt;/pre&gt;

And that's it. Whenever you are tempted to type "rhtml" stop. Type "haml". The view file for the contact mailer for this page is: moderation_ping.plain.text.haml. Yes, I even use it myself.

Enjoy!</posting>
    <title>Using ActionMailer with Haml (and others)</title>
    <updated-at type="datetime">2007-03-30T01:35:01-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2007-03-22T13:22:56-04:00</created-at>
    <id type="integer">6</id>
    <posted-by>steve</posted-by>
    <posting>I've become a true Haml convert. What does that mean? First, what is Haml? Haml is a markup language for Rails that drops in as a plugin and can be used as a substitute for rhtml. Let's jump right in with a quick example.

h2. An Example

__rhtml version__

&lt;pre&gt;
  &lt;code&gt;
    &lt;% for post in @posts %&gt;
      &lt;p&gt;&lt;span class="labels"&gt;title:&lt;/span&gt; &lt;span class="titles"&gt;&lt;%= post.title %&gt;&lt;/span&gt;&lt;/p&gt;
    &lt;% end %&gt;
  &lt;/code&gt;
&lt;/pre&gt;

__Haml version__

&lt;pre&gt;
  &lt;code&gt;
    - for post in @posts
      %p
        %span.labels title:
        %span.titles= post.title
  &lt;/code&gt;
&lt;/pre&gt;

A couple of things to note about Haml:

# It's very concise
# It _autocloses_ tags!
# It _autocloses_ do/end
# It follows the DOM, as you've specified it in your CSS

What you may not see is that the generated HTML is beautiful, with perfect indentation and can't-fail W3C compliance. Well, ok, nothing's guaranteed, but I've never written pure Haml that failed a W3C validation. Why is this cool? Because I spend way less time wrestling with my markup and more time on my Ruby code. I confess, I am not an HTML monkey. Never was, never will be. I'm just a programmer. That's why Haml is such an incredible gift to me.

h2. Your application.haml Layout

Tired of typing a correct (X)HTML header and getting it right? Try this:

&lt;pre&gt;
  &lt;code&gt;
    !!!
    %html
      %head
        = stylesheet_link_tag 'application'
      %body
        = yield
  &lt;/code&gt;
&lt;/pre&gt;

That is a relatively complete layouts/application.haml. The !!! says "spit out a valid (X)HTML header, complete with DOCTYPE." Pretty cool, huh?

h2. Extending Haml's Goodness to CSS: Sass

Haml is great for markup, but what about CSS? It turns out that Sass is to CSS as Haml is to rhtml. Sass is a natural way to write styles, free of some of the syntactic stuff that makes CSS so ... um ... interesting to write. Ok, maybe it's not a challenge to you, but I'm just a programmer. I'm not a Web monkey. Sass helps me get my CSS right the first time and it encourages me to follow better practices, such as using descendent selectors.

Here's an example from this site:

&lt;pre&gt;
  &lt;code&gt;
    !background_color   = #5d3526
    !content_background = #1B1718
    !text_color         = white
    !bold_hilight       = #e1deae
    !link_color         = #e1deae
    !menu_background    = white
    !menu_text_color    = black
    !menu_text_over     = #5d3526
    !row_alt_color      = !content_background + #111111
    
    .buzzword
      :color= !bold_hilight
      :font-size= !buzzword_font_size
      :font-weight bold
  &lt;/code&gt;
&lt;/pre&gt;

Whoa! What's that stuff at the top? Sass allows for named values, and if I want to change the background color everywhere in my CSS, it's one change in one place. You can see how I've used a few of these constants in the buzzword class definition. Just as with Haml, using the equal-sign (=) indicates some code-type stuff is going on, and that's how you need to write your expressions to take advantage of the named constants and the arithmetic (as you can see in row_alt_color).

Sass files are named public/stylesheets/sass/filename.sass, where filename is whatever you want your CSS file to be. The Sass engine compiles the Sass into a CSS file of the same name in the public/stylesheets directory, so typical usage is this (again, stealing from this site):

&lt;pre&gt;
  &lt;code&gt;
    !!!
    %html
      / File: app/views/layouts/application.haml (note that a single slash generates an HTML comment)
      %head
        %meta{"http-equiv"=&gt;"Content-Type", :content=&gt;"text/html; charset=utf-8"}/
        = stylesheet_link_tag('application', :media =&gt; 'all')
        = stylesheet_link_tag('ie', :media =&gt; 'screen') if request.user_agent =~ /msie/i
        = javascript_include_tag(:defaults)
        %title= yield :title
      %body
        #banner= image_tag('banner_l.gif', :size =&gt; '646x136')
        #logo= image_tag('logo.gif', :size =&gt; '159x138', :title =&gt; 'calico web development', :alt =&gt; 'calico web development')
        #menu
          #menu-container
            = render :partial =&gt; '/layouts/shared/nav_links'
        #content
          = yield
        #footer
          %p
            copyright &amp;copy; 1998 -
            = "#{Date.today.year}."
            all rights reserved
  &lt;/code&gt;
&lt;/pre&gt;

Here's a more interesting Sassification from this site's stylesheet:

&lt;pre&gt;
  &lt;code&gt;
    / File: public/stylesheets/sass/application.sass
    #menu
      :background= !menu_background
      :font-size= !menu_font_size
      :max-height 40px
      #menu-container
        :padding 1px 0 12px 164px
        a, a:link, a:visited
          :color= !menu_text_color
          :font-weight bold
          :font-size= !menu_font_size
        a:hover
          :color= !menu_text_over
          :font-weight bold
          :text-decoration none
        ul
          :list-style-type none
          li
            :float left
            :padding 0 23px 0 13px
            :text-indent 0
            :background url(/images/menu_bar.gif) 100% 66% no-repeat
  &lt;/code&gt;
&lt;/pre&gt;

h2. Installation of Haml

This is the part you've all been waiting for. Where to get it.

The svn repository is at svn://hamptoncatlin.com/haml/trunk (for those of you who like the latest and greatest) and svn://hamptoncatlin.com/haml/tags/stable.

If you prefer, you can install the plugin using:

&lt;pre&gt;
  &lt;code&gt;
    script/plugin install svn://hamptoncatlin.com/haml/trunk haml
  &lt;/code&gt;
&lt;/pre&gt;

You'll find complete information and documentation at: "hamptoncatlin.com":http://haml.hamptoncatlin.com/ and lots of good discussion at the "Google group":http://groups.google.com/group/haml.

h2. Performance

This seems to be a big concern to some. Not me. I snipped some log entries from a site that uses Haml. As you might expect, the list action (first entry) actually hits the database, yet I'm still serving up some 52 req/sec. Because the time to process the entire request is less that .02 seconds, the margin of error can be quite high by falling on one side or the other of a timer tick. In any case, ~50 req/sec is over 4 million requests/day. That's on a single Red Hat Linux box with Apache proxying directly to one instance of Mongrel.

The second log entry shows creating a new form. This uses Rails' form_for helper and renders just a bit slower. Not clear why it's slower, but again, these are anecdotal and the throughput is quite adequate for the site. Adding Mongrels would scale this up if (all of a sudden) lots of people fell in love with my site.

&lt;pre&gt;
  &lt;code&gt;
  Processing PostsController#list (for 24.18.43.53 at 2007-03-22 12:33:27) [GET]
    Session ID: db208605296b2fa0eb06cc499aa2dd1c
    Parameters: {"action"=&gt;"list", "controller"=&gt;"posts"}
  Rendering  within layouts/application
  Rendering posts/list
  Completed in 0.01899 (52 reqs/sec) | Rendering: 0.01664 (87%) | DB: 0.00179 (9%) | 200 OK [http://calicowebdev.com/blog/list]


  Processing PostsController#new (for 24.18.43.53 at 2007-03-22 12:33:37) [GET]
    Session ID: db208605296b2fa0eb06cc499aa2dd1c
    Parameters: {"action"=&gt;"new", "controller"=&gt;"posts"}
  Rendering  within layouts/application
  Rendering posts/new
  Completed in 0.02401 (41 reqs/sec) | Rendering: 0.02299 (95%) | DB: 0.00028 (1%) | 200 OK [http://calicowebdev.com/blog/new]
  &lt;/code&gt;
&lt;/pre&gt;</posting>
    <title>Haml -- Great Alternative to Rhtml</title>
    <updated-at type="datetime">2007-03-22T18:28:34-04:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2007-02-11T23:24:46-05:00</created-at>
    <id type="integer">5</id>
    <posted-by>steve</posted-by>
    <posting>A natural question when you look at a site might be, "how did they build that"? Here are the top-line technologies involved in this site:

* Ruby on Rails
* "Haml Template Language":http://haml.hamptoncatlin.com/
* Sass Stylesheets
* "rSpec Behavior Driven Development Tool":http://rspec.rubyforge.org/index.html
* MySQL Database
* Apache Web Server
* Pound Load Balancer (may change this at some point)
* Mongrel Rails HTTP Server

That's it in a nutshell. All page content is dynamically created, so site updates don't require putting new code on the server. The blog is homespun because "we could." Besides, the blog got me motivated enough to create a Rails patch to make ActionMailer and Haml play nicely together.</posting>
    <title>How Was This Site Built?</title>
    <updated-at type="datetime">2007-03-08T16:46:01-05:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2007-02-11T23:06:30-05:00</created-at>
    <id type="integer">4</id>
    <posted-by>steve</posted-by>
    <posting>Contact forms are a way of life on the Web and so we as developers implement them time and again. One nice touch is to do some validation of the data entered in the form to get higher quality data and lower the spam. Rails offers so much magic in how it joins models to views through controllers -- it's a shame to see that all go away when you implement your contact form. The good news is you can have your contact form and validations too!

I've tried several variations on how to perform ActiveRecord validations on non-database backed models, and keep coming back to the one from technoweenie. Here's how it works. You define a model thusly:

&lt;pre&gt;&lt;code&gt;
class Contact &lt; ActiveRecord::Base
  def self.columns() @columns ||= []; end
  def self.column(name, sql_type = nil, default = nil, null = true)
    columns &lt;&lt; ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type.to_s, null)
  end

  column :full_name,          :string
  column :email,              :string
  column :comments,           :string
  column :address,            :string
  column :city,               :string
  column :state,              :string
  column :zip_postal,         :string
  column :phone,              :string

  validates_presence_of     :full_name
  validates_confirmation_of :email
  validates_format_of       :email, 
                            :with =&gt; /^[_a-z0-9-]+(.[_a-z0-9-]+)*@([0-9a-z](-?[0-9a-z])*.)+[a-z]{2}([zmuvtg]|fo|me)?$/i,
                            :message =&gt; 'does not appear to be a valid email'

  validates_presence_of     :address
  validates_presence_of     :city
  validates_length_of       :state, :is =&gt; 2
  validates_format_of       :phone,
                            :with =&gt; /\d(?{3})?[- ]?\d{3}-?\d{4}/,
                            :message =&gt; 'should be ten digit number in the form: 999-999-9999',
                            :on =&gt; :create
  validates_length_of       :zip_postal, :in =&gt; 5..10, 
                            :message =&gt; 'Zip/postal code must be a valid US or Canadian zip/postal code'
  validates_format_of       :zip_postal,
                            :with =&gt; /(\d{5}(-\d{4})?)|([ABCEGHJKLMNPRSTVXY]\d[A-Z] \d[A-Z]\d)/,
                            :message =&gt; 'Zip/postal code matches neither US nor Canadian formats'

  protected                                                  
  def validate
    errors.add(:state, 'unrecognized state name. use two-letter abbreviation.') unless State.valid?(self[:state])
  end
end
&lt;/pre&gt;&lt;/code&gt;

I left all the validations in there in case you want to use simple email and postal-code regex validation.

This model basically creates the columns from your specification on the fly. The key is in the first four lines of code which overrides a couple of ActiveRecord methods. Namely column and columns. You use this model exactly as you would a model that represents a database table.

Just to convince you I really use this, here's my controller code:

&lt;pre&gt;&lt;code&gt;
class ContactController &lt; ApplicationController
  layout 'two-col'

  def index
    @contact = Contact.new
  end

  def thank_you
      @contact = Contact.new(params[:contact])
      if !@contact.valid?
        render(:action =&gt; 'index') and return
      else
        email = ContactMailer.create_sent(@contact)
        ContactMailer.deliver(email)
        email = ContactMailer.create_confirm(@contact)
        ContactMailer.deliver(email)
    end
  end
end
&lt;/pre&gt;&lt;/code&gt;

Now you can create all the forms you like the same way regardless of whether the results of form submission are saved to a database.</posting>
    <title>Validation Without a Database Table</title>
    <updated-at type="datetime">2007-02-11T23:07:18-05:00</updated-at>
  </post>
  <post>
    <approved type="boolean">true</approved>
    <created-at type="datetime">2007-02-11T22:59:40-05:00</created-at>
    <id type="integer">3</id>
    <posted-by>steve</posted-by>
    <posting>After working with Rails for a bit, we form working habits and one of mine is to install the same plugins for each project. You might do the same. I call these my "base plugins." Here's a Rake task that can make this process easier.

Usage:

&lt;pre&gt;&lt;code&gt;
rake plugins:install_base
&lt;/code&gt;&lt;/pre&gt;

Code (goes in lib/tasks/base_plugins.rake or right in your Rakefile)

&lt;pre&gt;&lt;code&gt;
require 'yaml'
namespace :plugins do
  desc "install a known list of plugins, specified in config/base_plugins.yml"
  task 'install_base' do
    f = YAML::load_file(File.join(RAILS_ROOT, 'config', 'base_plugins.yml'))
    f.each_pair do |plugin, options|
      force, svn = '', ''
      force = ' --force' if (options[:force] &amp;&amp; options[:force].downcase == 'yes')
      svn   = ' -X' if (options[:svn] &amp;&amp; options[:svn].downcase == 'yes')
      if force.empty? &amp;&amp; File.exist?(File.join(RAILS_ROOT, "vendor/plugins/#{plugin}"))
        puts "Skipping #{plugin} -- already installed and force options not specified."
      else
        cmd = "ruby #{RAILS_ROOT}/script/plugin install #{svn}#{options['repos']} #{plugin}#{force}"
        puts "*** installing #{cmd}"
        system(cmd)
      end
    end
   end
end
&lt;/code&gt;&lt;/pre&gt;

To use this, just place a file called @base_plugins.yml@ in your @config@ directory and format it as follows:

&lt;pre&gt;&lt;code&gt;
plugin_name: repos: svn://whatever/place/it/points force: yes svn: no nextpluginname: repos: http://another/place/you/like
&lt;/code&gt;&lt;/pre&gt;

The only required entry is "repos", but you can add force: yes to cause the plugin to be installed no matter what. If you want to use svn externals, then use @svn: yes@, which flips the -X switch on script/plugin install.

Bug noted: There seems to be a spurious ping to the script/plugin that makes it spit out an "already installed" message. This doesn't affect the functionality, however.

Enjoy!

n.b., "RaPT":http://nubyonrails.com/articles/2006/07/10/rapt-plugin-manager has a cool "plugin pack" concept that uses yaml files for configuration as well.</posting>
    <title>Installing "Stock" Plugins</title>
    <updated-at type="datetime">2007-02-11T22:59:40-05:00</updated-at>
  </post>
</posts>
