Auto-removing all newlines from Haml output

I'm using Haml in a Rails 3 app, and its newlines drive me nuts! For example,

%span
  foo

renders as

<span>
foo
</span>

But I'd much rather want

<span>foo</foo>

The reason (apart from being cleaner XML) is that extra newlines are a problem for my Selenium tests because they mess up the ability to do XPath queries like "//span[.='foo']". So I'd have to write '\nfoo\n' instead (ew!), or use //span[contains(text(), 'foo')], which matches too broadly.

I know I could use the alligator operators ("<" and ">") to strip whitespace, but since I don't ever have a case where I want the newlines to appear in the output, I'd just end up adding them mechanically at the end of each line. And that just seems very unDRY.

So now I see two solutions:

  1. Force Haml to never emit newlines unless they come from a Ruby expression. I see some nuke_inner_whitespace / nuke_outer_whitespace variables spread around the Haml code that might do the job, but I'm not sure how to change them without resorting to gratuitous monkey-patching.
  2. Hook into Rails to apply a gsub!("\n", "") to all rendered HTML. (For textarea's and pre's, I could still use ~ "foo\nbar" to make Haml emit foo&#x000A;bar.) But where's the right place to hook into Rails? I'm a little lost in the code.

Any pointers or other suggestions appreciated!

Update: I've used Jason's monkey patch below for a while now and I'm beginning to think that it's not worth it. E.g. if I want to get <span>[del]</span> <span>foo</span>, it's difficult to not have the blank space in between nuked. Even the following will render as [del]foo on the page:

%span
  = '[del] '
%span
  foo

So I think I'm going back to adding alligator operators manually (see my self-answer down below). Live and learn.

Thanks again to Jason! :)

Answers


If you place a less-than sign at the end of the element name the whitespace around the content will be suppressed:

%span<
  foo

See whitespace removal in the Haml reference for more details.

There doesn't appear to be any clean way to force these flags on for all tags but the following monkey patch works fine with Haml 3.0.24:

module Haml::Precompiler
  def parse_tag_with_nuked_whitespace(line)
    result = parse_tag_without_nuked_whitespace line
    unless result.size == 9 && [false,true].include?(result[4]) && [false,true].include?(result[5])
      raise "Unexpected parse_tag output: #{result.inspect}"
    end
    result[4] = true # nuke_outer_whitespace
    result[5] = true # nuke_inner_whitespace
    result
  end
  alias_method_chain :parse_tag, :nuked_whitespace
end

It probably wouldn't be hard to fork Haml and add an option to the Engine options to always nuke whitespace. The parse_tag method could check this option if enabled and set the inner and outer flags to true. I'll leave this as an exercise for the reader. :)


Need Your Help

Update rows in mysql from one table to another

mysql phpmyadmin

I'm trying to run a query that updates rows from one table to another. I want to take the values from shopping_cat_id and put them into existing rows in the table merchants where the ids match.

Filterable autocomplete, using ajax in Flask

javascript jquery ajax autocomplete flask

So, I'm designing an html form, which has two input fields.