ice

This project allows user-submitted templates to be written in the javascript programming language. It is similar to Liquid in terms of safety, but uses javascript to leverage the powers of a language most developers are familiar with.

It runs the templates through an erb-ish parser and then uses the therubyracer to interpet the javascript using Google's V8 javascript engine. Your users can then write ice templates like:

<table>
    <tr><th>Name</th><th>Email</th></tr>
    <% for (i = 0; i < users.length; i++) { %>
        <tr>
            <td><%= user.name %></td><td><%= mail_to(user.email) %></td>
        </tr>
    <% } %>
</table>

Why another templating engine when there is Liquid

Liquid is excellent but has several disadvantages

  • Hard to extend without knowing Liquid internals
  • Introduces yet-another-language, whereas many designers are already familiar with javascript
  • Doesn't allow template editors to use a rich object model and create their own functions
  • Doesn't have a rich set of support libraries like javascript brings to the table.

Note that we're still big fans of Liquid. In fact, we call this project "ice" as a tribute (keeping the metaphor alive, we use "Cubes" where they have "Drops").

Laminate uses the Lua language, which is a slight improvement, but still is unfamiliar to most developers.

to_ice

Every object is revealed to the templates via its to_ice method. This helps filter the objects that are passed into the javascript, so people editing the page only have access to a sanitized version of your data.

Instances of some classes like String and Numeric just return themselves as the result of to_ice. Hashes and Arrays run to_ice recursively on their members.

ActiveRecord modifications

To make life easy, since most complex objects passed to the templates will be subclasses of ActiveRecord::Base, the default to_ice behaviour of ActiveRecord is to pass itself in to a class with the same name, but followed by the word "Cube".

Therefore calling to_ice on instance of a User class will invoke

UserCube.new self

BaseCube Class

In order for everything to work easily, you can have your cubes inherit from our Ice::BaseCube class. Your cubes inheriting from it can then determine what additional attributes they want to reveal. For example

class BookCube < Ice::BaseCube
  revealing :title, :author_id, :genre_id
end

would provide a cube with access to the title, author_id and genre properties of the underlying ActiveRecord.

These cubes also have belongs_to and has_many associations, so you can write things like:

class ArticleCube < Ice::BaseCube
  has_many :comments, :tags
  belongs_to :author, :section
end

This brings in association helper functions such as comment_ids, num_comments, has_comments, comments, author_id, and author.

Note that all revealed functions and associations are also sanitized via to_ice.

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add spec for it. This is important so I don't break it in a future version unintentionally. In fact, try to write your specs in a test-first manner.
  • Commit
  • Send me a pull request.

Todo

  • Allow .ice view files
  • Add in form builders from clots project
  • Break form builders and helpers out into separate javascript project that can be included in other frameworks like CakePHP
  • Allow mappings for other ORMs than ActiveRecord
  • Haml support

Copyright (c) 2010 Nate Kidwell. See LICENSE for details.