/hquery

Unobtrusive Server Script Implementation for Ruby on Rails

Primary LanguageRubyMIT LicenseMIT

hquery

(Now supports Rails3! See “Rails3” section below)

Uses pure HTML as “template” for rendering views a Hpricot sequence (in the .hquery counter-part file) is executed to modify the pure HTML and the resulting HTML is output to the browser.

Video: www.vimeo.com/1836815

Layout

If your controller is “Hello”, and your action is “World”, then you will need

app/views/hello
            |-- world.hquery
            |-- world.hquery.html

“world.hquery.html” is the vanila HTML file your designers worked on. “world.hquery” contains the ruby code to manipulate data.

Example 1

This hquery declaration:

hquery.select ".users .vcard", User.find(:all) do |ele, user|
  ele.html ".email",       user.email
  ele.html ".tel",         user.telephone_no
  ele.html ".photo[@src]", user.photo
end

Can render this html template:

<ol class="users">
  <li class="vcard">
    <img class="photo" src="/images/no-picture.png" />
    <div>
      E-mail: <span class="email">foo@bar.com</span>
      Contact: <span class="tel">+1 222 333 4444</span>
    </div>
  </li>
  <!-- repeat your li.vcard here as many times u need printed -->
</ol>

Example 2 Google example

Given an array of Hash results, the following hquery declaration uses Google’s results page HTML as-is

hquery.select "li.g[@style='']", @result_list do |ele, result|
  # each iterated html element, and its matching iterated data
  ele.html "a.l",         result['title']
  ele.html "a.l[@href]",  h(result['url']) 
end

Example 3 Compiling conditionally removed elements

This hquery declaration:

hquery.remove ".nav.superuser" unless current_user && current_user.superuser?

Compiled with this html template:

<ul class="main_nav">
  <li class="nav"><a href="/">Home</a></li>
  <li class="nav superuser"><a href="/admin">Admin</a></li>
  <li class="nav"><a href="/logout">Logout</a></li>
</ul>

Gives you this html.erb file:

<ul class="main_nav">
  <li class="nav"><a href="/">Home</a></li>
  <% if current_user && current_user.superuser? %><li class="nav superuser"><a href="/admin">Admin</a></li><% end %>
  <li class="nav"><a href="/logout">Logout</a></li>
</ul>

More examples

See examples directory

Compile

When running in production mode (or with environment variable HQUERY_COMPILE set) the .hquery template will compile itself to an equivalent .html.erb file so the subsequent request onward will be served through the faster .html.erb template.

The compiler is Regexp based (see the examples above for syntax reference) and fragile. e.g. you can’t use double-quote “ in the last argument to ”ele.attr“ because of the way Hpricot spits out attribute and we can’t tell Hpricot that <a id=”<%= result %>“> is really ok.

But when the compiler does work, it really works.

Offline compile

If the “compile on first request” behavior brings you bad JSP memories, you can run a Rake command to trigger a compile anytime e.g. in your deployment steps:

$ rake hquery
Compiling app/views/search/google.hquery -> app/views/search/google.html.erb ...

Running it too many times won’t hurt either

$ rake hquery
Skipping app/views/search/google.hquery (app/views/search/google.html.erb is newer)

If Rake is absent, this is the equivalent command line:

$ ruby -rconfig/environment vendor/plugins/hquery/lib/hquery/compiler.rb app/views

Rails3

Hquery has been refactored to better support Rails3. As such, the “hquery” instance variable will need to be explicitly referenced in the .hquery files, i.e. The old syntax is

select "h1" do |ele|
  ele.html "title"
end

The new syntax is

hquery.select "h1" do |ele|
  ele.html "title"
end

This avoids clashes with methods defined by ActionView itself, e.g. “h”, “url_for”, etc…

License

Copyright © 2008 Chew Choon Keat, released under the MIT license