2010-07-29

HTML Templating in Ruby

(or “Why I moved a project to Python”)

I have a relatively simple project that requires me to scrape off a few paragraphs from a website, then print ‘em out in a nice HTML page. Well, right now it’s not so nice:

which is why I decided to make an actual full-fledged HTML page, with <body> tags and everything!

Since I didn’t really want to output HTML directly from Ruby, I went looking for a nice, simple HTML templating system.

First up was mustache. It was a nice and simple Mustache.render IO.read("funi.html"), :entries => entries until I remembered that Mustache doesn’t allow any logic in templates, which meant that I couldn’t iterate over my entries in a loop and do whatever to them. Out.

Second was haml. I got my template all coverted over, and then plugged in a line similar to what I was using in another project: puts haml :index, :entries => entries. NameError? Huh?

So, it appears that the Sinatra folks added a haml method. That’s fine, I can just call haml programmatically, and… what the hell is this? How do I freakin’ call haml?

You see, all of the haml documentation covers how to write templates in haml, with none of it describing how to actually render the damn things. Any docs I could find on that were Rails-specific, which is utterly unhelpful for a script like this. I spent a while digging through the haml source before giving up in frustration. Seriously, guys. No.

Ah, liquid, my Smarty-like friend. Put the template back to HTML and throw in a puts Liquid::Template.parse(IO.read "funi.html").render('entries' => entries), and we’re good to go.

Liquid error: undefined method 'to_liquid' for #<Nokogiri::XML::NodeSet:0x9baf0c0>? But I’m not printing out anything from a NodeSet; I throw it into a loop, and make the appropriate calls to get a string for you to digest. Oh, that’s right - now I remember why I gave up on you on another project.

You see, liquid bills itself as being a “secure” templating system, which means that it’s fucking annoying to use. You end up with shit like this:

# a bunch of bullshit liquid requires
module Nokogiri
	module XML
		class NodeSet
			def to_liquid
				self
			end
		end
		class Element
			def to_liquid
				self
			end
		end
	end
end

just so you can use freakin’ NodeSets in your template. I’m not taking any of that.

Well, let’s see if the ruby toolbox has anything else interesting. Hmm, there’s erector:

require 'erector'

class Hello < Erector::Widget
	def content
		html do
			head do
				title "Hello"
			end
			body do
				text "Hello, "
				b @target, :class => 'big'
				text "!"
			end
		end
	end
end

Hello.new(:target => 'world').to_html

Lol no.

So yeah, I got fed up with this nonsense and ported over to Python so that I could use Jinja, which is a shame, because I really like Nokogiri. But hey, do what works, right?

(As a side note, one of the reasons I like Nokogiri is that it has actual documentation, rather than just API docs slapped up, like most Ruby projects. The Python community tends to treat documentation very seriously (while Rubyists feel the same vigor towards unit tests), which makes it rather difficult to use anything that’s not well-documented after having programmed in Python for a bit. That was one of my main problems with Android (and Rails, a few years ago), and it’s gotten to the point that I almost automatically dismiss any framework or library that doesn’t have pages of well-written documentation.)