Examples

This page will explore some of the options made available by Haml User Tags.

Porting the Rails helpers

Rails defines many helper functions and it makes sense to create user tags wrapping them. When wrapping Ruby helper methods, it is simpler to implement them in Ruby.

# Use this like:
# %LinkTo{href: {controller: "main", action: "index"}} Link text
def LinkTo(attributes = {})
  url_options = attributes.delete("href")
  link_to url_options, attributes { yield }
end

Migrating from partials

It's easy to define a helper that will aid transition from partials to user tags.

module MyPartialHelper
  def self.include_as_tag(name, path)
    include_tags path
    define_method name do |attributes = {}, &content|
      attributes["content"] = capture_haml { content.call } if content
      render partial: path, locals: attributes
    end
  end

  include_as_tag :SomePartial, "partials/some_partial"
end
-# Before:
= render partial: "partials/some_partial", locals: {class: "classes", foo: "bar"}
-# After:
%SomePartial.classes{foo: "bar"}

Pool inline JavaScript at the end of body

This technique will allows user tags with JavaScript bindings to be created where the JavaScript is automatically consolidated in one script tag at the end of the document. If the JS element has an ID, then it will only be included once (for example, if it simply initializes a jQuery plugin).

@included_scripts = {}
@inline_js = []

def JS(attributes = {})
  if id = attributes["id"]
    return if @included_scripts[id]
    @included_scripts[id] = true
  end
  @inline_js << capture_haml { yield }
  nil
end
- define_tag :FancyTag do |attributes, content|
  .fancy-tag= content
  %JS#FancyTag
    :plain
      document.write("Initialized FancyTag plugin");
%FancyTag Fancy Tag 1
%FancyTag Fancy Tag 2

%div End of the body, maybe in a layout:
%script
  = @inline_js.join("\n")
Fancy Tag 1
Fancy Tag 2
End of the body, maybe in a layout:

Automatically build a table of contents

By taking advantage of lazy evaluation of child content, it's possible to build up a table of contents of the contents of a page. This technique is used on this page to build the navigation at the right.

- define_tag :PageWithChapters do |attributes, content|
  - @chapters = []
  -# Note that the content needs to be accessed to be evaluated, i.e.
  -# simply copying the reference to a new variable will not work.
  - page_content = content.to_s
  %h4 Contents
  %ol
    - @chapters.each do |section, title|
      %li
        %a{ :href => "##{section}" }= title
  = page_content

- define_tag :ChapterHeading do |attributes, content|
  - @chapters << [attributes["id"], content]
  %h4{attributes}= content

%PageWithChapters
  %ChapterHeading#cras-vitae Cras vitae
  %p Lorem ipsum dolor sit amet, consectetur adipiscing elit.
  %ChapterHeading#sed-tincidunt Sed tincidunt
  %p Suspendisse non pharetra nibh, sed fringilla est.
  %ChapterHeading#nullam-sed-augue Nullam sed augue
  %p Proin placerat orci ut ipsum vehicula laoreet.

Contents

  1. Cras vitae
  2. Sed tincidunt
  3. Nullam sed augue

Cras vitae

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

Sed tincidunt

Suspendisse non pharetra nibh, sed fringilla est.

Nullam sed augue

Proin placerat orci ut ipsum vehicula laoreet.