Effigy
Create usable views in Ruby with HTML and CSS selectors.
Synopsis
In Effigy, your view is a Ruby class that performs transformation on an HTML template. The template is passed to a render method, which calls a private #transform method to apply the transformations. The transformed template is then returned as a string of HTML.
template = %{ <html> <head> <title></title> </head> <body> <h1></h1> <p class="body"></p> <div class="comment"> <h2></h2> <p></p> <a>View more</a> </div> <p id="no-comments">There aren't any comments for this post.</p> </body> </html> } class PostView < Effigy::View attr_reader :post def initialize(post) @post = post end def transform text('h1', post.title) text('title', "#{post.title} - Site title") text('p.body', post.body) replace_each('.comment', post.comments) do |comment| text('h2', comment.title) text('p', comment.summary) attr('a', :href => url_for(comment)) end remove('#no-comments') if post.comments.any? end end view = PostView.new(post) document = view.render_html_document(template) # Result document: # <html> # <head> # <title>Post title - Site title</title> # </head> # <body> # <h1>Post title</h1> # <p class="body">Post body</p> # <div class="comment"> # <h2>First comment title</h2> # <p>First comment body</p> # <a href="/comments/1">View more</a> # </div> # <div class="comment"> # <h2>Second comment title</h2> # <p>Second comment body</p> # <a href="/comments/2">View more</a> # </div> # </body> # </html>
See the documentation for more information on available transformations.
Chaining
If you prefer, you can select elements and then apply tranformations in a chain. The previous example could have been written like this:
class PostView < Effigy::View attr_reader :post def initialize(post) @post = post end def transform find('h1').text(post.title) find('title').text("#{post.title} - Site title") find('p.body').text(post.body) find('.comment').replace_each(post.comments) do |comment| find('h2').text(comment.title) find('p').text(comment.summary) find('a').attr(:href => url_for(comment)) end find('#no-comments').remove if post.comments.any? end end
#find is also aliased as #f for brevity, if youโre into that sort of thing.
Rails
Effigy integrates with Rails. It provides a view subclass that copies instance variables from the controller, a template handler to find Effigy views and templates, and a generator to create skeleton view files.
Example:
# app/controllers/magic_controller.rb class MagicController < ApplicationController def index @spell = 'hocus pocus' end end
# app/views/magic/index.html.effigy class MagicIndexView < Effigy::Rails::View def transform text('h1', @spell) end end
# app/templates/magic/index.html <h1>Spell name goes here</h1>
View this example in your browser and youโll see โhocus pocus.โ
Install
Effigy is distributed as a gem through gemcutter:
sudo gem install effigy -s http://gemcutter.org
Effigy requires Nokogiri.
Why?
Effigy is based on the idea that putting behavior in your templates is confusing and makes them difficult to maintain, and that the closer an ERB template gets to 50% Ruby, 50% HTML, the closer it gets to total chaos. Complicated views require unintuitive concepts (ERB buffers, capture blocks, etc). ERB also has the constant threat of unescaped user input slipping into a view.
Effigy was created because I have never liked interpolation-based templating languages like ERB and because XSLT requires introducing another language (and I like Ruby just fine).
Author
Effigy was written by Joe Ferris. See LICENSE for license info.