My end goal is to create several static HTML files for hand-off to other folks.
But for my workflow, I’d like to have HAML as the basic source files. In doing so, I’d hope to DRY up the process at least on my side.
Now I have a lot of pages that will ultimately be sharing a common layout, and I’m wondering how to incorporate the layouts.
Here’s my current code:
./compile.rb
#!/usr/bin/env ruby
require 'rubygems'
require 'rake'
require 'haml'
FileList.new('./src/*.html.haml').each do |filename|
if filename =~ /([^\/]+)\.haml$/
File.open($1, 'w') do |f|
f.write Haml::Engine.new(File.read(filename)).render
end
end
end
./src/layout.html.haml
!!!
%html
%head
%title Yay
%body
= yield
./src/home.html.haml
= render :layout => 'header' do
%p This is awesome
Now this clearly doesn’t work because the render method is undefined out of the context of Rails, but I hope it gets the point across what I’m trying to do.
Any suggestions?
You’re mixing up two distinct Rails feature: partials (using
render) and layouts (usingyield).You can add a rails-like version of either (or both) of them to a Haml only program.
Partials
In a rails view, you can use
render :partial_nameto cause the file_partial_name.html.hamlto be rendered at that point in the containing view (actually Rails allows you to use any templating language supported and it will find to correct filename extension to use, but I’ll stick to just Haml here). Outside of Railsrenderisn’t available, but it can be added fairly easily.A simple
rendermethod would just find the appropriate haml file, render it, and return the html string for inclusion in the parent:The first argument to
Haml::Engine.renderis a scope object, which we can use to add methods available inside the haml template. It defaults toObject.new. In a simple case like this, however, we can define therendermethod in the top level, and it will be available in the scope of the Haml template. We simply put ourrendermethod in the script before the call toHaml::Engine.new(...).render, and call it like this in our template:Now the file
_the_partial.html.hamlwill appear rendered at the appropriate point of the output.Local variables
We can take this a step further. Rails allows you to pass in a hash of local variables to a partial. Haml will also accept a hash of variables to be passed as local variables, as the second argument to the Haml
rendermethod. So if we expand our render method to look like:we can use a partial that looks something like:
and call it from our template with:
which will render
Layouts
In Rails, you can specify a layout for your views, so that all your pages can share the same
header, menu area etc. This is done by specifying a layout file, within which you call
yieldto render the actual view in question. Layouts are slightly more tricky to add to haml, but can still be done.Hamls
rendermethod also accepts a block, so a simple solution would be to render the layout file, and pass a block that renders the view file:This would give the contents of
layout.html.hamlrendered with the contents ofview.html.hamlrendered where the layout file contained=yield.content_for
Rails is a bit more flexible than that though. It allows you to call
yieldmultiple times in your layout file, naming a specific region in each case, and to specify the contents to be added at each region using thecontent_formethod within your views. So in your layout file:and in your view:
The way Rails actually works is to render the view part first, storing all the different sections, and then rendering the layout, passing a block that provides the appropriate chunk whenever
yieldis called in the layout. We can replicate this using a little helper class to provide thecontent_formethod and keep track of the rendered chunks for each region:Here we’re using the
capture_hamlmethod to get the rendered haml without it going direct to the output. Note that this doesn’t capture the unnamed part of the view.We can now use our helper class to render the final output.
Now the variable
outputcontains the final rendered output.Note that the code here doesn’t provide all the flexibility that’s included with rails, but hopefully it’s enough to show you where to start customising Haml to meet your needs.