Chapter 12. Haml

HAML gave us a great take on how views can also be done. It looks a little cryptic at first, but don’t let that shake you off. Once you internalize the meaning of %, #, and . it should be all good (and you already know most just from CSS)....Additionally, I can’t help but have respect for a Canadian who manages to swear more than I did during my vendoritis rant and drink beer at the same time. A perfect example of the diversity in the Rails community. Very much part of what makes us special.

—David talking about Haml and Hampton Catlin1

1. http://david.heinemeierhansson.com/arc/2006_09.html

Haml2 is a “whitespace-sensitive” HTML templating engine that uses indentation to determine the hierarchy of an HTML document. Haml was created because its creator, Hampton Catlin, was tired of having to type markup and wanted all his output code to be beautifully formatted. What he invented was a new templating engine that removed a lot of noisy boilerplate, such as angle brackets (from ERb), and did away with the need to close blocks and HTML tags.

2. http://haml.info

We love Haml because it’s truly minimal, allowing a developer to focus simply on the structure of the page and not on the content. Today it’s common to keep view logic out of your templates, but that directive has been a guiding principle of Haml since its beginning. According to the 2012 Ruby Survey,3 36.96 percent of Rubyists prefer Haml over ERb, and 15.84 percent demand it in their projects. Haml is also the standard templating engine at various professional Ruby agencies, such as Hashrocket, Envy Labs, Remarkable Labs, and Astrails.

3. http://survey.hamptoncatlin.com/survey/stats

In this chapter, we’ll cover the fundamentals of Haml, from creating HTML elements to using filters to create other kinds of textual content embedded in your document.

12.1 Getting Started

To start using the Haml template language over ERb in your project, first add the haml-rails gem to your Gemfile and run bundle install.

# Gemfile
gem 'haml-rails'

The benefit of using haml-rails over simply the haml gem is it adds support for Rails-specific features. For instance, when you use a controller or scaffold generator, haml-rails will generate Haml views instead of using the Rails default of ERb. The haml-rails gem also configures Haml templates to work with Rails 4 cache digests out of the box.

12.2 The Basics

In this section, we’ll cover how to create HTML elements and attributes using Haml.

12.2.1 Creating an Element

To create an HTML element in Haml, one simply needs to prefix the percent character (%) to an element name. The element name can be any string, allowing you to use newly added HTML5 elements, such as header.

Haml

%header content

HTML

<header>content</header>

Haml will automatically handle generating opening and closing tags for the element on compilation. Not only does this make templates more concise and clean, it also eliminates common errors such forgetting to not close an HTML tags.

12.2.2 Attributes

Attributes in Haml are defined using two styles. The first style involves defining attributes between curly braces ({}). These attribute “brackets” are really just Ruby hashes and are evaluated as such. Because of this, local variables and Ruby logic can be used when defining attributes.

%a{ title: @article.title, href: article_path(@article) } Title

The second style follows the more traditional way of defining HTML attributes using brackets. Note that attributes are separated by white space, not commas.

%a(title=@article.title href=article_path(@article)) Title


Multiline Attributes

Attribute hashes can be separated on multiple lines for readability. All new lines must be placed right after the comma:

1 %a{ title: @article.title,
2     href: article_path(@article) } Title


12.2.2.1 Data Attributes

Introduced with HTML5, data attributes allow custom data to be embedded in any HTML element by prefixing an attribute with data-. Instead of littering the attribute hash with multiple attribute keys prefixed with data-, one can define all their data attributes in a nested hash associated with the key :data, like this:

Haml

%article{ data: { author_id: 1 } } Lorem Ipsum...

HTML

<article data-author-id='123'>Lorem Ipsum...</article>

Note that underscores are automatically replaced with a hyphen. Not that you’d want to, but you can change this behavior by setting the Haml configuration option hyphenate_data_attrs to false. (Haml configuration options are covered in detail later in this chapter.)

It’s also possible to nest data hashes more than one level to reduce verbosity when attributes share common roots.

Haml

%article{ data: { author: {id: 1, name: "Kevin Wu" } } Lorem Ipsum...

HTML

<article data-author-id='123' data-author-name='Kevin Wu'>Lorem Ipsum...</article>

12.2.2.2 Boolean Attributes

In HTML, there exists certain attributes that do not have a value associated with them, such as required.

<input type="text" required>

These are referred to as boolean attributes in Haml, since their value does not matter—only that they’re present. To represent these attributes in using the hash-style attribute syntax, set the value of the attribute to true.

%input{ type: 'text', required: true }

Otherwise, if you’re using the HTML attribute style syntax, a boolean value doesn’t have to be set at all.

%input(type="text" required)


XHTML

If the format of Haml is set to :xhtml, boolean attributes will be set to their name. To illustrate, given the previous example, Haml would render the following HTML:

  <input type="text" required="required" />


12.2.3 Classes and IDs

Haml was designed to promote the DRY principle (not repeating code unnecessarily). As such, it provides a shorthand syntax for adding id and class attributes to an element. The syntax is borrowed from CSS, where ids are represented by a pound (#) and classes by a period (.). Both of these signs must be placed immediately after the element and before an attributes hash.

Haml

1 #content
2   .entry.featured
3     %h3.title Haml
4     %p.body Lorem Ipsum...

HTML

1 <div id='content'>
2   <div class='entry featured'>
3     <h3 class='title'>Haml</h3>
4     <p class='body'>Lorem Ipsum...</p>
5   </div>
6 </div>

As the previous example shows, multiple class names can be specified similarly to CSS by chaining the class names together with periods. In a slightly more complicated scenario, the shortcut CSS style class and id syntax can be combined with longhand attributes. Both values are merged together when compiled down to HTML.

Haml

%article.featured{ class: @article.visibility }

HTML

<article class='feature visible'>...</article>

Haml has some serious tricks up its sleeves for dealing with complex id and class attributes. For instance, an array of class names will automatically be joined with a space.

Haml

%article{ class: [@article.visibility, @article.category] }

HTML

<article class='visible breakingnews'>...</article>

Arrays of id values will be joined with an underscore.

Haml

%article{ id: [@article.category, :article, @article.id] }

HTML

<article id='sports_article_1234'>...</article>

Note that the array is flattened and any elements that evaluate to false or nil will be dropped automatically. This lets you do some pretty clever tricks at the possible expense of readability and maintainability.

1 %article{ class: [@article.visibility,
2   @article.published_at < 4.hours.ago && 'breakingnews'] }

In the example, if the article was published less than four hours ago, then breakingnews will be added a one of the CSS classes of the element. While we’re on the subject, remember that it is advisable to migrate this kind of logic into your Ruby classes. In this particular example, we might give the Article class (or one of its presenters or decorator classes) a breakingnews? method and use it instead of inlining the business logic.

1 def breaking?
2   published_at < 4.hours.ago
3 end

%article{ class: [@article.visibility, @article.breaking? && 'breakingnews'] }

If breaking? returns false, then the Ruby expression short-circuits to false, and Haml ignores that particular class name.

12.2.4 Implicit Divs

The default elements of Haml are divs. Since they are used so often in markup, one can simply define a div with a class or id using . or # respectively.

Haml

1 #container
2   .content Lorem Ipsum...

HTML

1 <div id="container">
2   <div class="content">
3     Lorem Ipsum...
4   </div>
5 </div>


Implicit Div Creation

Not having to specify div tags explicitly helps your markup be more semantic from the start, placing focus on the intention of the div instead of treating it as just another markup container. It’s also one of the main reasons that we recommend Haml over ERb. We believe that Haml templates lessen mental burden by communicating the structure of your DOM in way that maps cleanly to the CSS that will be applied to the document.


12.2.5 Empty Tags

In HTML, there are certain elements that don’t require a closing tag, such as br.4 By default, Haml will not add a closing tag for the following tags:

4. For a definitive explanation of why some HTML elements like <br/> close themselves, while others like <script> need a closing tag, read http://www.colorglare.com/2014/02/03/to-close-or-not-to-close.html

area

base

br

col

hr

img

input

link

meta

param

To illustrate, consider the following example:

%hr

would render HTML

<hr>

or XHTML

<hr />

Adding a forward slash character (/) at the end of a tag definition causes Haml to treat it as being an empty element. The list of empty tags Haml uses can be overridden using the autoclose configuration setting. Haml configuration options are covered in detail later in this chapter.

12.3 Doctype

A doctype must be the first item in any HTML document. By including the characters !!! at the beginning of a template, Haml will automatically generate a doctype based on the configuration option :format, set to :html5 by default. Adding !!! to a template would result in the following HTML:

<!DOCTYPE html>

Haml also allows the specifying of a specific doctype after !!!. A complete listing of supported doctypes can be found on Haml’s reference website.5

5. http://haml.info/docs/yardoc/file.REFERENCE.html#doctype_

12.4 Comments

There are two types of comments in Haml: those that appear in rendered HTML and those that don’t.

12.4.1 HTML Comments

To leave a comment that will be rendered by Haml, place a forward slash (/) at the beginning of the line you want commented. Anything nested under that line will also be commented out.

/ Some comment

<!-- Some comment -->

You can use this feature to produce Internet Explorer conditional comments by suffixing the condition in square brackets like this:

/[if lt IE 9]

12.4.2 Haml Comments

Besides conditional comments for targeting Internet Explorer, comments left in your markup are meant to communicate a message to other developers working with the template. These messages should not be rendered to the browser, as they are specific to your team. In Haml, starting a line with -# ensures any text following the pound sign isn’t rendered at all.

Haml

-# Some important comment...
%h1 The Rails 4 Way

HTML

<h1>The Rails 4 Way</h1>

If any text is nested beneath this kind of silent comment, it will also be omitted from the resulting output.

12.5 Evaluating Ruby Code

Somewhat similar to ERb, using the equals character (=) results in Haml evaluating Ruby code following the character and outputting the result into the document.

Haml

%p= %w(foo bar).join(' ')

HTML

<p>foo bar</p>

Alternatively, using the hyphen character (-) evaluates Ruby code but doesn’t insert its output into the resulting document. This is commonly used in combination with if/else statements and loops.

- if flash.notice
  .notice= flash.notice

Note that Ruby blocks don’t need to be explicitly closed in Haml. As seen in the previous example, any indentation beneath a Ruby evaluation command indicates a block.


Kevin Says ...

Do not use - to set variables. If you find yourself doing so, this is an indication that you need to create some form of view object, such as a presenter or decorator.


Lines of Ruby code can be broken up over multiple lines as long as each line except the last ends with a comma.

= image_tag post.mage_url,
    class: 'featured-image'

12.5.1 Interpolation

Ruby code can be interpolated in two ways in Haml: inline with plain text using #{} or using string interpolation in combination with =. To illustrate, the following two lines of Haml code samples are equivalent:

%p By: #{post.author_name}
%p= "By: #{post.author_name}"

12.5.2 Escaping/Unescaping HTML

To match the default Rails XSS protection scheme, Haml will sanitize any HTML-sensitive characters from the output of =. This results in any = call to behave like &=.

Haml

&= "Cookies & Cream"

HTML

Cookies &amp; Cream

Alternatively, to unescape HTML with Haml, simply use != instead of =. If the Haml configuration option escape_html is set to false, then any call to = will behave like !=. (You probably will never want to do that.)

Haml

!= "Remember the awful <blink> tag?"

HTML

Remember the awful <blink> tag?

12.5.3 Escaping the First Character of a Line

On rare occasion, you might want to start a line of your template with a character such as = that would normally be interpreted. You may escape the first character of a line using a backslash.

Haml

%p
  = equality for all =

HTML

<p>
  = equality for all =
</p>

12.5.4 Multiline Declarations

Haml is meant to be used for layout and design. Although one can technically write multiline declarations within a template, the creators of Haml made this intentionally awkward to discourage people from doing so.

If you for some reason do need declarations that span multiple lines in a template, you can do so by adding multiline operator (|) to the end of each line.

1 #content
2   %p= h( |
3     "While possible to write" +               |
4     "multiline Ruby code, " +                 |
5     "it is not the Haml way," +               |
6     "as you should eliminate as much Ruby" +  |
7     "in your views as possible.")             |

We highly recommend extracting multiline Ruby code into helpers, decorators, or presenters.

12.6 Helpers

Haml provides a variety of helpers that are useful for day-to-day development, such as creating list items for each item in a collection and setting CSS ids and classes based on a model or controller.

12.6.1 Object Reference []

Given an object, such as an Active Record instance, Haml can output an HTML element with the id and class attributes set by that object via the [] operator. For instance, assuming @post is an instance of a Post class with an id value of 1, then the template code

1 %li[@post]
2   %h4= @post.title
3   = @post.excerpt

renders

<li class='post' id='post_1'>...</li>

This is similar to using Rails helpers div_for and content_tag_for, covered in Chapter 11, “All about Helpers.”

12.6.2 page_class

Returns the name of the current controller and action to be used with the class attribute of an HTML element. This is commonly used with the body element to allow for easy style targeting based on a particular controller or action. To illustrate, assuming the current controller is PostsController and action index,

%body{ class: page_class }

renders

<body class='posts index'>

12.6.3 list_of(enum, opts = {}) { |item| ... }

Given an Enumerable object and a block, the list_of method will iterate and yield the results of the block into sequential <li> elements.

Haml

1 %ul
2   = list_of [1, 2, 3] do |item|
3     Number #{item}

HTML

1 <ul>
2     <li>Number 1</li>
3     <li>Number 2</li>
4     <li>Number 3</li>
5 </ul>

12.7 Filters

Haml ships with a collection of filters that allows you to pass arbitrary blocks of text content as input to another processor, with the resulting output inserted into the document. The syntax for using a filter is a colon followed by the name of the filter. For example, to use the markdown filter,

1 :markdown
2   # The Rails 4 Way
3
4   Some awesome **Rails**-related content.

renders

1 <h1>The Rails 4 Way</h1>
2
3 <p>Some awesome <strong>Rails</strong>-related content.</p>

Here is a table of all the filters that Haml supports by default:

Image

Table 12.1 Default Haml filters

Some filters require external gems to be added to your Gemfile in order to work. For instance, the :markdown filter requires a markdown gem, such as redcarpet.

12.8 Haml and Content

In Chris Eppstein’s blog post “Haml Sucks for Content,”6 he stated his opinions on why one shouldn’t use Haml to build content:

6. http://chriseppstein.github.io/blog/2010/02/08/haml-sucks-for-content

Haml’s use of CSS syntax for IDs and class names should make it very clear: The markup you write in Haml is intended to be styled by your stylesheets. Conversely, content does not usually have specific styling—it is styled by tags.

Essentially, what Chris was trying to convey is to not use native Haml syntax for creating anything other than skeletal (or structural) HTML markup. Use of filters to inline reader content, such as in this example using the :markdown filter,

1 %p
2   Do
3   %strong not
4   use
5   %a{ href: "http://haml.info" } Haml
6   for content.

is equivalent to the following markdown within a filter:

1 :markdown
2   Do **not* use [Haml](http://haml.info) for content.

We like this idea but admit that your mileage may vary. It really depends on the type of project you’re working on and the capabilities of the person that will be maintaining the Haml template source files.

12.9 Configuration Options

Haml provides various configuration options to control exactly how markup is rendered. Options can be set by setting the Haml::Template.options hash in a Rails initializer.

# config/initializers/haml.rb
Haml::Template.options[:format] = :html5

12.9.1 autoclose

The autoclose option accepts an array of all tags that Haml should self-close if no content is present. Defaults to ['meta', 'img', 'link', 'br', 'hr', 'input', 'area', 'param', 'col', 'base'].

12.9.2 cdata

Determines if Haml will include CDATA sections around JavaScript and CSS blocks when using the :javascript and :css filters, respectively.

When format is set to html, it defaults to false. If the format is xhtml, cdata will always be set to true and cannot be overridden.

This option also affects the filters * :sass, * :scss, * :less, and * :coffeescript.

12.9.3 compiler_class

The compiler class to use when compiling Haml to HTML. Defaults to Haml::Compiler.

12.9.4 Encoding

The default encoding for HTML output is Encoding.default_internal. If that is not set, the default is the encoding of the Haml template.

The encoding option can be set to either a string or an Encoding object.

12.9.5 escape_attrs

If set to true (default), will escape all HTML-sensitive characters in attributes.

12.9.6 escape_html

When Haml is used with a Rails project, the escape_html option is automatically set to true to match Rails’ XSS protection scheme. This causes = to behave like &= in Haml templates.

12.9.7 format

Specifies the output format of a Haml template. By default, it’s set to :html5.

Other options include the following:

:html4

:xhtml. Will cause Haml to automatically generate self-closing tags and wrap the output of JavaScript and CSS filters inside CDATA.

12.9.8 hyphenate_data_attrs

Haml converts all underscores in all data attributes to hyphens by default. To disable this functionality, set hyphenate_data_attrs to false.

12.9.9 mime_type

The MIME type that rendered Haml templates are servered with. If this is set to text/xml, then the format will be overridden to :xhtml, even if it has been set to :html4 or :html5.

12.9.10 parser_class

The parser class to use. Defaults to Haml::Parser.

12.9.11 preserve

The preserve option accepts that an array of all tags should have their newlines preserved using the preserve helper. Defaults to ['textarea', 'pre'].

12.9.12 remove_whitespace

Setting to true causes all tags to be treated as if whitespace removal Haml operators are present. Defaults to false.

12.9.13 ugly

Haml does not attempt to format or indent the output HTML of a rendered template. By default, ugly is set to false in every Rails environment except production. This enables you to view the rendered HTML in a pleasing format when you’re in development but yields higher performance in production.

12.10 Conclusion

In this chapter, we learned how Haml helps developers create clear, well-indented markup in your Rails applications. In the following chapter, we will cover how to manage sessions with Active Record, Memcached, and cookies.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.186.202