Focusing autotest

August 24th, 2008

The usual autotest workflow goes something like this:

  • Edit and save
  • Autotest runs associated specs
  • Are there failures? Fix and start over
  • Autotest runs the entire suite

Sometimes though, you want autotest to just ignore most of your specs and focus on a few specs.

Last week, while Kevin, Rick, and Yossef (OG) were here, they shared an autotest tweak that does exactly that.

The tweak allows you to specify a regular expression to limit the files which autotest watches; for example, to autotest only files matching *user*.rb you would (atest is an alias):

% atest user

Here is the (lightly modified) code to do this; in your .autotest file add:

if ENV['AUTOTEST'] and not ENV['AUTOTEST'].empty?
  only_these_files_re = Regexp.new(ENV['AUTOTEST'])

  Autotest.send(:alias_method, :real_find_files, :find_files)
  Autotest.send(:define_method, :find_files) do |*args|
    real_find_files.reject do |k, v|
      !only_these_files_re.match(k)
    end
  end
end

And in your .bash_profile add:

# Autotest
  function fn_autotest() {
    AUTOTEST=$1 autotest
  }
  alias atest='fn_autotest'

Now use the alias to invoke autotest. For standard autotest behavior:

% atest

To limit what autotest is watching, pass a regular expression (which can be a simple string):

% atest user.*html

Control your layout

April 22nd, 2008

Recently, I added jQuery ajax tabs to an application. To reuse the existing views, I moved the relevant view code to partials for each required action:

render :partial => "entry", :object => journal_entry

and using something like the following in all the relevant controller methods:

format.html { render :partial => 'index' if request.xhr? }

As I added more features to the ajax tabs, I was conditionally rendering partials in every relevant action, as well as creating a partial. Not DRY.

layout provides a much DRY-er solution without the need for the partials. In application.rb:

layout proc { |controller| controller.request.xhr? ? false : 'application' }

When a controller action is invoked, if it is an XHR, no layout will be used. Otherwise the default Rails layout, ‘application’, will be used1.

1 layout expects the name of a layout to be returned from the proc; in this case, I am returning the name of the default. Returning false indicates that no layout should be used.

Monkey Patch!

February 22nd, 2008

So after missing the wisdom[1] of this:

http://xkcd.com/386/

And responding to this:

http://b.lesseverything.com/2008/2/19/haml-doesn-t-like-javascript

I went to bed.

This morning I wrote my first Rails (really Haml) Monkey Patch[2]. This adds some of what Steve wanted: undisturbed inline javascript with variable interpolation. I am not sure what else he wanted as I did not read his blog carefully :)

Throw this into lib/inline_javascript.rb

module Haml
  module Filters
    class InlineJavascript
      HEAD =<<EOH
<script type="text/javascript">
//<![CDATA[
EOH

      FOOT =<<EOF
//]]>
</script>
EOF

      def initialize(text)
        @text = HEAD + text + FOOT
      end

      def render
        @text
      end
    end
  end

  module Precompiler
    def close_filtered(filter)
      @flat_spaces = -1
      filtered = filter.new(@filter_buffer).render

      if filter == Haml::Filters::Preserve
        push_silent("_hamlout.buffer << #{filtered.dump} << \"\\n\";")
      elsif filter == Haml::Filters::InlineJavascript
        # suppress eval option does not apply to us
        flush_merged_text
        js = unescape_interpolation(filtered)
        @precompiled  << "_hamlout.buffer << #{js};"
      else
        push_text(filtered.rstrip.gsub("\n", "\n#{'  ' * @output_tabs}"))
      end

      @filter_buffer = nil
      @template_tabs -= 1
    end
  end
end

Throw this at the bottom of your environment.rb, taken from here http://groups.google.com/group/haml/msg/2d890cf1ede761ea

require 'inline_javascript'

Haml::Template.options = {
   :filters => {
     'javascript' => Haml::Filters::InlineJavascript
   }
}

And then do this in your Haml:

:javascript
  function oh_yea() {
    alert('Hello' + '#{@message}')
  }
%a{ :href =>"javascript:oh_yea()" } Oh Yea!

Update

I decided to make a patch and submit it to the Haml folks directly. This gave me the ‘opportunity’ to get git going.

Nathan Weizenbaum took the time to put in a more comprehensive fix to expose the interpolation functionality to all filters – look for it in an upcoming release.

[1] It’s turtles all the way down.

[2] You do not want to know what my subconscious originally thought up as the way to do this – that was twisted.