An Introduction to Haml and Sinatra

Twice a month, we revisit some of our readers’ favorite posts from throughout the history of Nettuts+. This tutorial was first published in October, 2010.

This tutorial will introduce Haml and Sinatra. Haml is a markup language that produces clean, well-structured HTML. Sinatra is a simple but powerful Ruby framework for creating websites or web services. The two work very well together and provide a powerful tool for quick and simple web development. I find them ideal for prototyping.

By the end of this tutorial, you will have created a website with two pages using Sinatra and Haml. Along the way, you'll learn how Sinatra applications are structured, and will be introduced to Haml. You will also learn how to use a layout file to reduce the amount of duplicated code and give consistency between the pages.

Step 1: Install Ruby and the Gems

You can skip this section if you already have Ruby installed and working on your system.

We need to install the Ruby language and the Sinatra and Haml gems to get started.

The method for doing this will vary depending on your operating system. I like to use the Ruby Version Manager (RVM) to manage Ruby on OS X and Linux. (Windows users might want to look at Pik as an alternative to RVM.)

Install RVM to Manage our Ruby Environment

For those of you who do not have Ruby installed, download and install RVM.

This will download and install RVM. We need to add a line to the end of our .bashrc file. Those of you using an alternative to shell to Bash will need to amend the appropriate profile. See the RVM installation page for more details.

Install Dependencies and the Ruby Language

Type 'rvm notes' to check out any dependencies you may need to install for your operating system. There are serveral different versions of Ruby that RVM can manage. We will use the standard version called MRI. Hence, in the output of rvm notes look for the section that says, 'For MRI and REE...'. Then copy and paste the command stated for 'ruby'.

For example, on a fresh install of Ubuntu, I got the following output and needed to install the dependencies listed by using the aptitude command given in the output. See screenshot below.

With the tricky bit over, installing and using different Ruby versions and gems is now easy. Install version 1.9.2 of Ruby by entering the following:

Step 2: Create the Sinatra Application

To begin making the Sinatra application, create a folder containing a Ruby file for the application code. In your terminal, type:

mkdir sinatra-app
cd sinatra-app
touch website.rb

Open the newly created 'website.rb' file in your text editor and enter the following:

require 'rubygems'
require 'sinatra'
get '/' do
"This is Sinatra"
end

This is a basic Sinatra application. The first two lines bring in the 'rubygems' and 'sinatra' libraries to do the heavy work.

The next section tells Sinatra how to respond to a 'get' request. Specifically, it tells it what to do when the root url (the '/' path) is requested. In this example, Sinatra just returns the string "This is Sinatra". This is what will appear in the browser when the root url of the application is requested.

To see it in action, go back to your terminal and execute the Sinatra application using the following command:

ruby website.rb

You will need to restart this website.rb file every time you change it. Hence it is a good idea to keep a separate shell running in its own window or tab to start and stop it.

This is telling us that a webserver (called WEBrick) has started and is now serving your application on port 4567.

To view it, open your browser and go to "localhost:4567". You should see the application's output:

Congratulations! Your Sinatra application is up and running!

Let's start looking at building pages with Haml and some default Sinatra conventions for special files.

Step 3: Introducing Haml

We are going to build our pages with Haml. The first step is to tell our application that we will be using the Haml gem.

We do this by adding include 'Haml' towards the top of you code. Change your 'website.rb' file to look like the following:

require 'rubygems'
require 'sinatra'
require 'Haml
get '/' do
"This is Sinatra"
end

Your application will now know to use the Haml gem that we installed earlier.

The Haml Markup Language

Haml is a simple and clean way of describing HTML. It can also handle inline code, such as PHP, ASP and Ruby script.

One of Haml's goals is to reduce the amount of duplication and repetition found in creating webpages with HTML; one example of this is closing tags. It does this by relying on the structure of the indents in the code: When writing in Haml, it is important to be consistent with indents as they describe the structure of the page.

The result is markup that is logical and much easier to read than HTML for all but the most trivial of cases.

Let's look at some Haml markup and show the HTML it produces.

!!!
%html
%head
%title This is the Title in a title tag within the head tag
%body
%h1 This is a heading within an h1 tag
%p
This is text in a paragraph. Notice how we do not close the tag...the indents do that!

The '!!!' at the start of the code tells Haml to output the DOCTYPE tag. HTML tags are described with a '%' sign. So %html outputs the <html> tag, %head creates the <head> tag, %p creates the <p> tag and so on.

The indents tell Haml which tags lie within others. So the heading tag <h1> produced by the '%h1' markup is within the <body> tag created by the '%body' markup. The following paragraph tag marked up by the '%p' tag is also within the body tag. Following the indents, we can see that the text lies within the paragraph.

Hence, the markup above gives the following HTML output:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title >This is the Title within the head tag </title>
</head>
<body>
<h1>This is a heading within the body tag </h1>
<p>
This is text in a paragraph. Notice how we do not close the tag...the indents do that!
</p>
</body>
</html>

You can see where the closing tags correspond to the indentation in the original Haml markup.

Adding Haml Templates to the Sinatra Application

With that quick introduction to Haml out of the way, we can start to use it in our application. By default, Sinatra will look for webpage templates in a folder called 'views'. Let's add that folder now.

Open a terminal, navigate to the sinatra_app folder we made earlier and enter the following:

mkdir views
cd views

Now we are inside the views folder, let's create an 'index.haml' page.

Great! We now have our website working by using the Haml templates in the 'views' directory.

Let's now work the home page into something that follows a typical structure with a header, footer, content area and a sidebar. We'll also add some basic CSS to position and style the page. In doing this, we'll see how to express <div> tags in Haml and how to bring link to CSS files.

Create the Home Page

Go back to the 'index.haml' file in your text editor and change it look like the following:

!!!
%html
%head
%title My Sinatra Website
%body
#wrapper
#header
%h1 My Sinatra Website
%h2 A Simple Site made with Sinatra and HAML!
#content
%h1 The Home Page
%p
Welcome to my website made with Sinatra and HAML.
%p
This is the home page and this is some text to fill out the home page!
#side_bar
%h1 Side Bar
%p
This is the side bar of the webpage
#footer
%p
This is the footer.

This is a typical layout with header, content, side_bar and footer divs. As you can see, <div> tags are created with the # sign. The whole page is wrapped in a <div id="wrapper"> tag created by the '#wrapper' line.

To give an HTML tag an id we just chain the # on the end, so we could write %body#my_ID to get <body id="my_ID">. Classes are marked up with a dot. So %article.my_class would give <article class="my_class">.

Save the file and refresh it in your browser. You should see something like this:

Add Some CSS Styling

Sinatra uses another special directory names 'public' to store assets such as CSS files and images. Create a folder called 'public' in your application's root folder. Change into that directory and create one called 'css' to store the css files. Finish by creating a blank css file in that directory.

Do this in your terminal by typing:

mkdir public
cd public
mkdir css
cd css
touch styles.css

Open the styles.css file in your editor and copy and paste the following in:

I won't go into the details of the css, as it's just a quick and dirty way of making the page elements more obvious in the browser.

We need to link to the CSS file from within the index page. I'm also going to add a link to the Yahoo CSS reset to help consistency across browsers. Open the index.haml page the editor and add these two lines to the %head section.

This illustrates how we can use brackets in Haml for additional tag attributes: rel and href in this case.

Your final file should look like this:

!!!
%html
%head
%title My Sinatra Website
%link(rel="stylesheet" href="http://yui.yahooapis.com/2.8.0r4/build/reset/reset-min.css")
%link(rel="stylesheet" href="css/styles.css")
%body
#wrapper
#header
%h1 My Sinatra Website
%h2 A Simple Site made with Sinatra and HAML!
#content
%h1 The Home Page
%p
Welcome to my website made with Sinatra and HAML.
%p
This is the home page and this is some text to fill out the home page!
#side_bar
%h1 Side Bar
%p
This is the side bar of the webpage
#footer
%p
This is the footer.

Refresh your browser, and you should see the home page with styling and the divs positioned.

We now have the basic template for our web pages that we can reuse to create additional pages.

Step 4: Creating a Common Layout

Now that we have our basic page layout, we can see that much of the content in our index.html file might be the same for other pages on the site. In this example, we will keep the header, footer and sidebar common to both pages. We can use a layout file in Sinatra to achieve this.

Go back to the index page in your text editor; change the filename by choosing 'Save As' to layout.haml.

We will now edit the layout file and introduce some templating markup using the '=' tag in Haml.

Change the layout file to look like:

!!!
%html
%head
%title My Sinatra Website
%link(rel="stylesheet" href="http://yui.yahooapis.com/2.8.0r4/build/reset/reset-min.css")
%link(rel="stylesheet" href="css/styles.css")
%body
#wrapper
#header
%h1 My Sinatra Website
%h2 A Simple Site made with Sinatra and HAML!
#content
=yield
#side_bar
%h1 Side Bar
%p
This is the side bar of the webpage
#footer
%p
This is the footer.

The key here is the '=yield' command. The = sign tells Haml to process some Ruby code and put the output in the browser. Here we are simply calling Ruby's yield function that will return the contents of the page.

We can now edit our index.haml page to take out all of the code that is duplicated in the layout file. Change it to look like:

%h1 The Home Page
%p
Welcome to my website made with Sinatra and HAML.
%p
This is the home page and this is some text to fill out the home page!

Refreshing the browser should provide exactly the same result as earlier. But this time, the layout file is automatically being picked up by Sinatra and the index page is being rendered as a result of the yield function.

Create the About Page

Creating additional pages that use this template is now straightforward. Create a new file in the 'views' folder called about.haml

Your directory and file structure for the application should look like this:

Enter the following code in the new file:

%h1 About
%p
This is a simple application using Sinatra and HAML.

As you can see, this is a very simple page with a heading and a piece of text within a paragraph tag.

We have no way of seeing the page at the moment. To do that, we need to amend the website.rb file to tell Sinatra to handle a request for '/about' and to return the about.haml template as a result.

We do that by adding the following lines to the website.rb file:

require 'rubygems'
require 'sinatra'
require 'haml'
get '/' do
haml :index
end
get '/about' do
haml :about
end

The get '/about' block simple tells Sinatra to return the 'about' Haml template in response to an HTTP get for '/about'.

Restart the WEBrick webs server by pressing Ctrl-C in the terminal in which it's running, as we did before, and calling ruby website.rb.

You should see the following page when you navigate to 'localhost:4567/about' in your browser.

Adding more pages would be as quick and as simple as that. Just remember that you will need to restart the WEBrick server if you change the application file.

Step 5: Adding a Meny (and Tidying Up)

We need to add some way of navigating between the pages; so we'll add a simple menu in the layout. Open the layout.haml file and add the navigation div and the links like this:

!!!
%html
%head
%title My Sinatra Website
%link(rel="stylesheet" href="http://yui.yahooapis.com/2.8.0r4/build/reset/reset-min.css")
%link(rel="stylesheet" href="css/styles.css")
%body
#wrapper
#header
%h1 My Sinatra Website
%h2 A Simple Site made with Sinatra and HAML!
#nav
%ol
%a(href="/")
%li Home
%a(href="about")
%li About
#content
=yield
#side_bar
%h1 Side Bar
%p
This is the side bar of the webpage
#footer
%p
This is the footer.

Here, we create a div with the id of nav. This div contains a list with anchor tags to '/' and 'about'. Notice how the linked text is indented on the following line to surround it in the HTML anchor tag.

Refresh your browser, and you should see a menu which links the two pages:

Clicking on the links in the navigation menu should take you to each page. You can experiment with adding more pages. Remember, the steps are as follows:

Add a new .haml file to the views directory.

Describe the view using Haml in that file.

Add the navigation to the new page in the menu part of the layout file.

Edit the website.rb file for the new route in the same way as the '/about' route.

Don't forget to restart the website.rb file!

Conclusion

There's certainly much more to both Sinatra and Haml than we have seen here. Sinatra is a great choice for website and web-services, whereas a heavier framework such as Ruby on Rails might be overkill. Further, I find the simplicity and clarity of Haml complements Sinatra beautifully, and make for a very productive development approach.