Haml (HTML抽象化マークアップ言語)

Hamlは、インラインコードを使用せずに、WebドキュメントのHTMLをクリーンかつシンプルに記述するために使用されるマークアップ言語です。Hamlは、PHP、ERB、ASPなどのインラインページテンプレートシステムの代替として機能します。ただし、HamlはテンプレートにHTMLを明示的にコーディングする必要性を回避します。それは実際にはHTMLの抽象的な記述であり、動的なコンテンツを生成するためのいくつかのコードが含まれているからです。

特徴

  • 空白がアクティブ
  • 整形式のマークアップ
  • DRY(Don't Repeat Yourself:同じことを繰り返さない)
  • CSSの規約に従う
  • Rubyコードを統合
  • .haml拡張子でRailsテンプレートを実装

Hamlの使用

Hamlは3つの方法で使用できます。

  • コマンドラインツールとして、
  • Ruby on Railsのプラグインとして、
  • スタンドアロンのRubyモジュールとして。

これらすべての最初のステップは、Haml gemをインストールすることです。

gem install haml

コマンドラインからHamlを実行するには、次のように使用します。

haml render input.haml > output.html

完全なドキュメントについては、haml --helpを使用してください。

RailsでHamlを使用するには、Gemfileに次の行を追加します。

gem "haml"

インストールされると、".html.haml"拡張子を持つすべてのビューファイルはHamlを使用してコンパイルされます。

Hamlテンプレート内のインスタンス変数には、ERBテンプレートと同じ方法でアクセスできます。ヘルパーメソッドもHamlテンプレートで利用できます。たとえば

# file: app/controllers/movies_controller.rb

class MoviesController < ApplicationController
  def index
    @title = "Teen Wolf"
  end
end

-# file: app/views/movies/index.html.haml

#content
 .title
   %h1= @title
   = link_to 'Home', home_url

は、次のようにコンパイルされる可能性があります。

<div id='content'>
  <div class='title'>
    <h1>Teen Wolf</h1>
    <a href='/'>Home</a>
  </div>
</div>

Rubyモジュール

Hamlは、RailsやActionViewとは完全に分離して使用することもできます。これを行うには、RubyGemsでgemをインストールします。

gem install haml

次に、Rubyコードにhaml gemを含め、次のようにHaml::Templateを使用することで使用できます。

engine = Haml::Template.new { "%p Haml code!" }
engine.render #=> "<p>Haml code!</p>\n"

オプション

Hamlは、そのパフォーマンスと出力に影響を与えるさまざまな構成オプションを理解します。

Railsでは、初期化子でHaml::RailsTemplate.set_optionsを使用することでオプションを設定できます。

ruby # config/initializers/haml.rb Haml::RailsTemplate.set_options(escape_html: false)

Rails以外では、Haml::Template.optionsでグローバルに構成することで設定できます。

ruby Haml::Template.options[:escape_html] = false

特にsinatraでは、グローバル構成で次のように設定できます:ruby set :haml, { escape_html: false }

最後に、オプションのハッシュをHaml::Engine.newまたはHaml::Template.newに渡すことによっても設定できます。利用可能なオプションの完全なリストについては、Haml::Engineを参照してください。

プレーンテキスト

HTMLドキュメントの大部分はそのコンテンツであり、それはプレーンテキストです。他のものとして解釈されないHaml行は、プレーンテキストとして扱われ、変更されずに渡されます。たとえば

%gee
  %whiz
    Wow this is cool!

は、次のようにコンパイルされます。

<gee>
  <whiz>
    Wow this is cool!
  </whiz>
</gee>

HTMLタグも変更されずに渡されることに注意してください。Hamlに変換したくないHTMLがある場合、またはファイルを1行ずつ変換している場合は、そのまま含めることができます。たとえば

%p
  <div id="blah">Blah!</div>

は、次のようにコンパイルされます。

<p>
  <div id="blah">Blah!</div>
</p>

エスケープ: \

バックスラッシュ文字は、行の最初の文字をエスケープし、それ以外の場合はプレーンテキストとして解釈される文字を使用できるようにします。たとえば

%title
  = @title
  \= @title

は、次のようにコンパイルされます。

<title>
  MyPage
  = @title
</title>

HTML要素

要素名: %

パーセント文字は行の先頭に配置されます。その直後に要素の名前、続いてオプションで修飾子(下記参照)、スペース、および要素内にレンダリングされるテキストが続きます。<element></element>の形式で要素を作成します。たとえば

%one
  %two
    %three Hey there

は、次のようにコンパイルされます。

<one>
  <two>
    <three>Hey there</three>
  </two>
</one>

任意の文字列が有効な要素名です。Hamlは、任意の要素の開始タグと終了タグを自動的に生成します。

属性: {} または ()

中かっこは、要素の属性を指定するために使用されるRubyハッシュを表します。これは文字通りRubyハッシュとして評価されるため、ロジックが機能し、ローカル変数を使用できます。属性内の引用符は、適切なエスケープシーケンスに置き換えられます。ハッシュは、タグが定義された後に配置されます。たとえば

%html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"}

は、次のようにコンパイルされます。

<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'></html>

属性ハッシュは、多数の属性に対応するために複数行にわたって拡張することもできます。

%script{
  "type": text/javascript",
  "src": javascripts/script_#{2 + 7}",
  "data": {
    "controller": "reporter",
  },
}

は、次のようにコンパイルされます。

<script src='javascripts/script_9' type='text/javascript' data-controller='reporter'></script>

:class および :id 属性

:classおよび:id属性は、要素が結合されるRuby配列としても指定できます。:class配列は" "で結合され、:id配列は"_"で結合されます。たとえば

%div{:id => [@item.type, @item.number], :class => [@item.type, @item.urgency]}

は、次と同等です。

%div{:id => "#{@item.type}_#{@item.number}", :class => "#{@item.type} #{@item.urgency}"}

配列は最初に平坦化され、trueとしてテストされない要素は削除されます。残りの要素は文字列に変換されます。たとえば

%div{:class => [@item.type, @item == @sortcol && [:sort, @sortdir]] } Contents

は、次のいずれかとしてレンダリングされる可能性があります。

<div class="numeric sort ascending">Contents</div>
<div class="numeric">Contents</div>
<div class="sort descending">Contents</div>
<div>Contents</div>

@item.type"numeric"またはnilであるか、@item == @sortcolであるか、@sortdir"ascending"または"descending"であるかによって異なります。

単一の値が指定されていて、falseと評価された場合は無視されます。それ以外の場合は文字列に変換されます。たとえば

.item{:class => @item.is_empty? && "empty"}

は、次のいずれかとしてレンダリングされる可能性があります。

class="item"
class="item empty"

HTMLスタイルの属性: ()

Hamlは、HTMLの属性に基づく、より簡潔でRuby固有でない属性構文もサポートしています。これらは、次のように、中かっこではなくかっこで使用されます。

%html(xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en")

引用符を省略することで、Ruby変数を使用できます。ローカル変数またはインスタンス変数を使用できます。たとえば

%a(title=@title href=href) Stuff

これは、次と同じです。

%a{:title => @title, :href => href} Stuff

ただし、属性を区切るコンマがないため、より複雑な式は許可されません。それらについては、{}構文を使用する必要があります。ただし、両方の構文を一緒に使用できます。

%a(title=@title){:href => @link.href} Stuff

また、#{}補間を使用して、HTMLスタイルの属性に複雑な式を挿入できます。

%span(class="widget_#{@widget.number}")

HTMLスタイルの属性は、ハッシュスタイルの属性と同様に複数行にわたって拡張できます。

%script(type="text/javascript"
        src="javascripts/script_#{2 + 7}")

Ruby 1.9スタイルのハッシュ

Hamlは、Rubyの新しいハッシュ構文もサポートしています。

%a{title: @title, href: href} Stuff

ブール属性

inputタグの「checked」やoptionタグの「selected」など、いくつかの属性は、値が重要ではなく、存在するかどうかが重要であるという意味で「ブール」です。HTML(ただしXHTMLではない)では、これらの属性は次のように記述できます。

<input selected>

ハッシュスタイルの属性を使用してHamlでこれを行うには、属性にRubyのtrue値を割り当てるだけです。

%input{:selected => true}

XHTMLでは、これらの属性の唯一の有効な値は属性の名前です。したがって、これはXHTMLで次のようにレンダリングされます。

<input selected='selected'>

これらの属性をfalseに設定するには、単にRubyのfalse値を割り当てます。XHTMLとHTMLの両方で、

%input{:selected => false}

は、次のようにレンダリングされます。

<input>

HTMLスタイルのブール属性は、HTMLのように記述できます。

%input(selected)

または、truefalseを使用して記述できます。

%input(selected=true)

この機能は、Haml::AttributeBuilder::BOOLEAN_ATTRIBUTESに含まれる属性、およびdata-属性とaria-属性でのみ機能します。

%input{'data-hidden' => false}
%input{'aria-hidden' => false}
%input{'xyz-hidden' => false}

は、次のようにレンダリングされます。

<input>
<input>
<input xyz-hidden='false'>

データ属性

HTML5では、data-で始まる属性名を使用して、要素にカスタムの非表示データ属性を追加できます。アクセシブルリッチインターネットアプリケーション仕様では、aria-で始まる属性を利用します。

Hamlは、これらのように接頭辞を共有する属性のコレクションの生成を支援できます。値としてハッシュを持つdataまたはaria属性ハッシュ内のエントリは、ハッシュ内の各キー/値ペアについて一連の属性に展開され、属性名は「親」キー名をキー名とハイフンで結合することによって形成されます。これはdataまたはariaでのみ機能します。

たとえば

%a{:href=>"/posts", :data => {:author_id => 123, :category => 7}} Posts By Author

は、次のようにレンダリングされます。

<a data-author-id='123' data-category='7' href='/posts'>Posts By Author</a>

author_idのアンダースコアがハイフンに置き換えられたことに注意してください。この動作を抑制する場合は、Hamlの:hyphenate_data_attrsオプションをfalseに設定すると、出力は次のようにレンダリングされます。

<a data-author_id='123' data-category='7' href='/posts'>Posts By Author</a>

このハッシュの展開は再帰的です。子ハッシュの値自体がハッシュである場合、各エントリの属性が作成され、属性名にはすべて先祖キーが接頭辞として付けられます。たとえば

.book-info{:data => {:book => {:id => 123, :genre => 'programming'}, :category => 7}}

は、次のようにレンダリングされます。

<div class='book-info' data-book-genre='programming' data-book-id='123' data-category='7'></div>

クラスとID: .#

ピリオドとポンド記号はCSSから借用されています。これらは、それぞれ要素のclassおよびid属性を指定するためのショートカットとして使用されます。複数のクラス名は、CSSと同様の方法で、ピリオドでクラス名を結合することで指定できます。これらは、タグの直後、および属性ハッシュの前に配置されます。たとえば

%div#things
  %span#rice Chicken Fried
  %p.beans{ :food => 'true' } The magical fruit
  %h1.class.otherclass#id La La La

は、次のようにコンパイルされます。

<div id='things'>
  <span id='rice'>Chicken Fried</span>
  <p class='beans' food='true'>The magical fruit</p>
  <h1 class='class otherclass' id='id'>La La La</h1>
</div>

そして、

%div#content
  %div.articles
    %div.article.title Doogie Howser Comes Out
    %div.article.date 2006-11-05
    %div.article.entry
      Neil Patrick Harris would like to dispel any rumors that he is straight

は、次のようにコンパイルされます。

<div id='content'>
  <div class='articles'>
    <div class='article title'>Doogie Howser Comes Out</div>
    <div class='article date'>2006-11-05</div>
    <div class='article entry'>
      Neil Patrick Harris would like to dispel any rumors that he is straight
    </div>
  </div>
</div>

これらのショートカットは、長文の属性と組み合わせることができます。2つの値は、すべてが配列に配置されているかのように結合されます(:classおよび:id属性に関するドキュメントを参照)。たとえば

%div#Article.article.entry{:id => @article.number, :class => @article.visibility}

は、次と同等です。

%div{:id => ['Article', @article.number], :class => ['article', 'entry', @article.visibility]} Gabba Hey

は、次のようにコンパイルされる可能性があります。

<div class="article entry visible" id="Article_27">Gabba Hey</div>

暗黙のDiv要素

divは非常に頻繁に使用されるため、デフォルトの要素です。.または#を使用してクラスやIDのみを定義する場合、divが自動的に使用されます。たとえば

#collection
  .item
    .description What a cool item!

は、次と同じです。

%div#collection
  %div.item
    %div.description What a cool item!

そして、次のようにコンパイルされます。

<div id='collection'>
  <div class='item'>
    <div class='description'>What a cool item!</div>
  </div>
</div>

クラス名のマージと順序付け

クラス名は次の順序で並べられます。

1)タグ識別子(例:「.alert.me」=>「alert me」)2)HTMLスタイルの属性に表示されるクラス3)ハッシュスタイルの属性に表示されるクラス

たとえば、これは順序付けを示す複雑で直感的でないテストケースです。

.foo.moo{:class => ['bar', 'alpha']}(class='baz')

結果のHTMLは次のようになります。

<div class='foo moo baz bar alpha'></div>

Haml 5.0より前のバージョンでは、クラス名をアルファベット順にソートしていました。

空(void)タグ: /

タグ定義の最後に配置されたスラッシュ文字は、Hamlがそれを空(またはvoid)要素として扱うようにします。形式に応じて、タグは終了タグなし(:html4または:html5)または自己終了タグ(:xhtml)としてレンダリングされます。

たとえば、次のようにします。

%br/
%meta{'http-equiv' => 'Content-Type', :content => 'text/html'}/

形式が:html4または:html5の場合、これは次のようにコンパイルされます。

<br>
<meta content='text/html' http-equiv='Content-Type'>

形式が:xhtmlの場合、次のようにコンパイルされます。

<br />
<meta content='text/html' http-equiv='Content-Type' />

一部のタグは、Hamlソースにコンテンツがない限り、自動的に空として扱われます。metaimglinkbrhrinputareaparamcol、およびbaseタグは、デフォルトで空として扱われます。このリストは、:autocloseオプションを設定することでカスタマイズできます。

空白の削除: ><

><を使用すると、タグ付近の空白をより詳細に制御できます。>はタグを囲むすべての空白を削除し、<はタグ内のすべての空白を削除します。それらを、空白を食べるワニと考えることができます。>はタグの外側を向き、外側の空白を食べ、<はタグの内側を向き、内側の空白を食べます。これらは、クラス、ID、および属性宣言の後、/または=の前のタグ定義の最後に配置されます。たとえば

%blockquote<
  %div
    Foo!

は、次のようにコンパイルされます。

<blockquote><div>
  Foo!
</div></blockquote>

そして

%img
%img>
%img

は、次のようにコンパイルされます。

<img /><img /><img />

そして

%p<= "Foo\nBar"

は、次のようにコンパイルされます。

<p>Foo
Bar</p>

そして最後に

%img
%pre><
  foo
  bar
%img

は、次のようにコンパイルされます。

<img /><pre>foo
bar</pre><img />

オブジェクト参照: []

角括弧はタグ定義の後に続き、そのタグのクラスと ID を設定するために使用される Ruby オブジェクトを含みます。クラスはオブジェクトのクラス(キャメルケースではなくアンダースコアを使用するように変換)に設定され、ID はオブジェクトのクラスに、その #to_key または #id メソッドの値(この順序で)が続いたものに設定されます。これは、Active Model モデルのインスタンスを表す要素に最も役立ちます。さらに、2 番目の引数(存在する場合)は、id 属性と class 属性の両方のプレフィックスとして使用されます。例:

# file: app/controllers/users_controller.rb

def show
  @user = CrazyUser.find(15)
end

-# file: app/views/users/show.haml

%div[@user, :greeting]
  %bar[290]/
  Hello!

は、次のようにコンパイルされます。

<div class='greeting_crazy_user' id='greeting_crazy_user_15'>
  <bar class='fixnum' id='fixnum_581' />
  Hello!
</div>

クラスがアンダースコア化されたオブジェクトのクラス以外のものが必要な場合は、オブジェクトに haml_object_ref メソッドを実装できます。

# file: app/models/crazy_user.rb

class CrazyUser < ActiveRecord::Base
  def haml_object_ref
    "a_crazy_user"
  end
end

-# file: app/views/users/show.haml

%div[@user]
  Hello!

は、次のようにコンパイルされます。

<div class='a_crazy_user' id='a_crazy_user_15'>
  Hello!
</div>

:class 属性はオブジェクト参照と組み合わせて使用できます。コンパイルされた要素は、すべてのクラスの和集合を持ちます。

- user = User.find(1)
%p[user]{:class => 'alpha bravo'}
<p id="user_1" class="alpha bravo user"></p>

ドキュメントタイプ: !!!

Haml を使用して HTML ドキュメントを記述する場合、!!! という文字を含めることで、ドキュメントタイプまたは XML プロローグを自動的に生成できます。例:

!!! XML
!!!
%html
  %head
    %title Myspace
  %body
    %h1 I am the international space station
    %p Sign my guestbook

は、次のようにコンパイルされます。

<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <head>
    <title>Myspace</title>
  </head>
  <body>
    <h1>I am the international space station</h1>
    <p>Sign my guestbook</p>
  </body>
</html>

:format:xhtml に設定されている場合は、!!! の後に特定のドキュメントタイプを指定することもできます。次のドキュメントタイプがサポートされています。

!!!
XHTML 1.0 Transitional
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
!!! Strict
XHTML 1.0 Strict
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
!!! Frameset
XHTML 1.0 Frameset
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
!!! 5
XHTML 5
<!DOCTYPE html>
!!! 1.1
XHTML 1.1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
!!! Basic
XHTML Basic 1.1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
!!! Mobile
XHTML Mobile 1.2
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">
!!! RDFa
XHTML+RDFa 1.0
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">

:format オプションが :html4 に設定されている場合は、次のドキュメントタイプがサポートされています

!!!
HTML 4.01 Transitional
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
!!! Strict
HTML 4.01 Strict
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
!!! Frameset
HTML 4.01 Frameset
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">

:format オプションが :html5 に設定されている場合、!!! は常に <!DOCTYPE html> です。

ドキュメントに UTF-8 文字セットを使用していない場合は、同様の方法で XML プロローグに表示するエンコーディングを指定できます。例:

!!! XML iso-8859-1

は、次のようにコンパイルされます。

<?xml version='1.0' encoding='iso-8859-1' ?>

レンダリングされるテンプレートの mime_type が text/xml の場合、グローバル出力形式が :html4 または :html5 に設定されている場合でも、:xhtml の形式が使用されます。

コメント

Haml は 2 種類のコメントをサポートしています。HTML 出力に表示されるものと、表示されないものです。

HTML コメント: /

行の先頭にスラッシュ文字を置くと、その後のすべてのテキストが HTML コメントで囲まれます。例:

%peanutbutterjelly
  / This is the peanutbutterjelly element
  I like sandwiches!

は、次のようにコンパイルされます。

<peanutbutterjelly>
  <!-- This is the peanutbutterjelly element -->
  I like sandwiches!
</peanutbutterjelly>

スラッシュは、インデントされたコードセクションを囲むこともできます。例:

/
  %p This doesn't render...
  %div
    %h1 Because it's commented out!

は、次のようにコンパイルされます。

<!--
  <p>This doesn't render...</p>
  <div>
    <h1>Because it's commented out!</h1>
  </div>
-->

条件付きコメント: /[]

/ の後の角括弧内に条件を囲むことで、Internet Explorer の条件付きコメントを使用することもできます。例:

/[if IE]
  %a{ :href => 'http://www.mozilla.com/en-US/firefox/' }
    %h1 Get Firefox

は、次のようにコンパイルされます。

<!--[if IE]>
  <a href='http://www.mozilla.com/en-US/firefox/'>
    <h1>Get Firefox</h1>
  </a>
<![endif]-->

IE には表示されないが、他のブラウザーには表示される「ダウンレベル表示」の条件付きコメントを生成するには、角括弧の前に ! を追加します: /![]。Haml は、この種の条件付きコメントを生成するときに有効な HTML を生成します。

たとえば

/![if !IE]
  You are not using Internet Explorer, or are using version 10+.

は、次のようにコンパイルされます。

<!--[if !IE]><!-->
  You are not using Internet Explorer, or are using version 10+.
<!--<![endif]-->

Haml コメント: -#

ハイフンとそれに続くポンド記号は、サイレント コメントを示します。この後に続くテキストは、結果のドキュメントにはまったくレンダリングされません。

たとえば

%p foo
-# This is a comment
%p bar

は、次のようにコンパイルされます。

<p>foo</p>
<p>bar</p>

サイレント コメントの下にテキストをネストすることもできます。このテキストはレンダリングされません。例:

%p foo
-#
  This won't be displayed
    Nor will this
                   Nor will this.
%p bar

は、次のようにコンパイルされます。

<p>foo</p>
<p>bar</p>

Ruby の評価

Ruby の挿入: =

等号の後に Ruby コードが続きます。このコードが評価され、出力がドキュメントに挿入されます。例:

%p
  = ['hi', 'there', 'reader!'].join " "
  = "yo"

は、次のようにコンパイルされます。

<p>
  hi there reader!
  yo
</p>

:escape_html オプションが設定されている場合、= はスクリプトによって生成された HTML に敏感な文字をサニタイズします。例:

= '<script>alert("I\'m evil!");</script>'

コンパイルすると、次のようになります。

&lt;script&gt;alert(&quot;I'm evil!&quot;);&lt;/script&gt;

= は、タグの最後に使用して、そのタグ内に Ruby コードを挿入することもできます。例:

%p= "hello"

コンパイルすると、次のようになります。

<p>hello</p>

Ruby コードの行は、最後の行を除く各行がコンマで終わる限り、複数行にまたがることができます。例:

= link_to_remote "Add to cart",
    :url => { :action => "add", :id => product.id },
    :update => { :success => "cart", :failure => "error" }

= で終わるタグ内にコードをネストすることは違法であることに注意してください。

Ruby の実行: -

ハイフン文字の後にも Ruby コードが続きます。このコードは評価されますが、ドキュメントには挿入されません

これを広く使用することは推奨されません。ほとんどすべての処理コードとロジックは、コントローラー、ヘルパー、またはパーシャルに制限する必要があります。

たとえば

- foo = "hello"
- foo << " there"
- foo << " you!"
%p= foo

は、次のようにコンパイルされます。

<p>
  hello there you!
</p>

Ruby コードの行は、最後の行を除く各行がコンマで終わる限り、複数行にまたがることができます。例:

- links = {:home => "/",
    :docs => "/docs",
    :about => "/about"}

Ruby ブロック

XHTML タグと同様に、Ruby ブロックを Haml で明示的に閉じる必要はありません。むしろ、インデントに基づいて自動的に閉じられます。Ruby 評価コマンドの後にインデントが増加すると、ブロックが開始されます。インデントが減少すると終了します(else 句や同様のものがない限り)。例:

- (42...47).each do |i|
  %p= i
%p See, I can count!

は、次のようにコンパイルされます。

<p>42</p>
<p>43</p>
<p>44</p>
<p>45</p>
<p>46</p>
<p>See, I can count!</p>

別の例

%p
  - case 2
  - when 1
    = "1!"
  - when 2
    = "2?"
  - when 3
    = "3."

は、次のようにコンパイルされます。

<p>
  2?
</p>

空白の保持: ~

~= と同じように機能しますが、入力に対して Haml::Helpers.preserve を実行する点が異なります。例:

~ "Foo\n<pre>Bar\nBaz</pre>"

は、次と同じです。

= find_and_preserve("Foo\n<pre>Bar\nBaz</pre>")

そして、次のようにコンパイルされます。

Foo
<pre>Bar&#x000A;Baz</pre>

空白の保持も参照してください。

Ruby のインターポレーション: #{}

Ruby コードは、Ruby 文字列のインターポレーションと同様に、#{} を使用してプレーンテキスト内に補間することもできます。例:

%p This is #{h quality} cake!

は、次と同じです。

%p= "This is #{h quality} cake!"

コンパイルすると次のようになります。

<p>This is scrumptious cake!</p>

バックスラッシュを使用して #{} 文字列をエスケープできますが、文字列内の他の場所ではエスケープとして機能しません。例:

%p
  Look at \\#{h word} lack of backslash: \#{foo}
  And yon presence thereof: \{foo}

コンパイルすると次のようになります。

<p>
  Look at \yon lack of backslash: #{foo}
  And yon presence thereof: \{foo}
</p>

インターポレーションは フィルター内でも使用できます。例:

:javascript
  $(document).ready(function() {
    alert(#{@message.to_json});
  });

コンパイルすると次のようになります。

<script type='text/javascript'>
  //<![CDATA[
    $(document).ready(function() {
      alert("Hi there!");
    });
  //]]>
</script>

落とし穴

Haml は、完全な Ruby パーサーではなく、過度に単純化された正規表現を使用して文字列のインターポレーションを識別します。これは高速で、ほとんどのコードで機能しますが、次のようなコードではエラーが発生する可能性があります。

%span #{'{'}

このコードは、アンバランスな中括弧について不満を言う構文エラーを生成します。このような場合、推奨される回避策は、Haml に Ruby でコードを強制的に解析させるために、コードを Ruby 文字列として出力することです。

%span= "#{'{'}"

HTML のエスケープ: &=

アンパサンドに 1 つまたは 2 つの等号が続く場合、アンパサンドなしの等号と同じように Ruby コードを評価しますが、コードの結果に含まれる HTML に敏感な文字をサニタイズします。例:

&= "I like cheese & crackers"

コンパイルすると次のようになります。

I like cheese &amp; crackers

:escape_html オプションが設定されている場合、&== と同じように動作します。

& は単独で使用して、#{} インターポレーションをエスケープすることもできます。例:

& I like #{"cheese & crackers"}

コンパイルすると次のようになります。

I like cheese &amp; crackers

HTML のエスケープ解除: !=

感嘆符に 1 つまたは 2 つの等号が続く場合、等号と同じように Ruby コードを評価しますが、HTML をサニタイズすることはありません。

デフォルトでは、1 つの等号も HTML をサニタイズしません。ただし、:escape_html オプションが設定されている場合、= は HTML をサニタイズしますが、!= はサニタイズしません。たとえば、:escape_html が設定されている場合

= "I feel <strong>!"
!= "I feel <strong>!"

コンパイルすると次のようになります。

I feel &lt;strong&gt;!
I feel <strong>!

! は単独で使用して、#{} インターポレーションをエスケープ解除することもできます。例:

! I feel #{"<strong>"}!

コンパイルすると次のようになります。

I feel <strong>!

フィルター

コロン文字はフィルターを示します。これにより、インデントされたテキストのブロックを別のフィルタープログラムへの入力として渡し、Haml の出力に結果を追加できます。構文は、単純にコロンの後にフィルターの名前が続きます。例:

%p
  :markdown
    # Greetings

    Hello, *World*

は、次のようにコンパイルされます。

<p>
  <h1>Greetings</h1>

  <p>Hello, <em>World</em></p>
</p>

フィルターには、#{} を使用して Ruby コードを補間できます。例:

- flavor = "raspberry"
#content
  :textile
    I *really* prefer _#{flavor}_ jam.

は、次のようにコンパイルされます。

<div id='content'>
  <p>I <strong>really</strong> prefer <em>raspberry</em> jam.</p>
</div>

Markdown など一部のフィルターの機能は、さまざまなライブラリによって提供できます。通常、これを心配する必要はありません。任意の gem をロードするだけで、Haml が自動的に使用します。

ただし、場合によっては、Haml にフィルターで使用される特定の gem を明示的に使用させたい場合があります。このような場合は、Haml が多数のフィルターを実装するために使用するライブラリである Tilt を介してこれを行うことができます。

Tilt.prefer Tilt::RedCarpetTemplate

詳細については、Tilt ドキュメントを参照してください。

Haml には、次のフィルターが定義されています。

:cdata

フィルター処理されたテキストを CDATA タグで囲みます。

:coffee

フィルター処理されたテキストを CoffeeScript を使用して <script> タグ内の JavaScript にコンパイルします。このフィルターを :coffeescript として参照することもできます。このフィルターは Tilt を使用して実装されています。

:css

フィルター処理されたテキストを <style> タグと(オプションで)CDATA タグで囲みます。インライン CSS を含めるのに役立ちます。CDATA タグが追加されるタイミングを制御するには、:cdata オプションを使用します。

:erb

フィルター処理されたテキストを RHTML テンプレートのように ERB で解析します。:suppress_eval オプションが true に設定されている場合は使用できません。埋め込まれた Ruby コードは、Haml テンプレートと同じコンテキストで評価されます。このフィルターは Tilt を使用して実装されています。

:escaped

プレーンと同じように機能しますが、ドキュメントに配置する前に HTML をエスケープします。

:javascript

フィルター処理されたテキストを <script> タグと(オプションで)CDATA タグで囲みます。インライン Javascript を含めるのに役立ちます。CDATA タグが追加されるタイミングを制御するには、:cdata オプションを使用します。

:less

Less でフィルター処理されたテキストを解析して、<style> タグに CSS 出力を生成します。このフィルターは Tilt を使用して実装されています。

:markdown

Markdown でフィルター処理されたテキストを解析します。このフィルターは Tilt を使用して実装されています。

:maruku

Maruku でフィルター処理されたテキストを解析します。これは、Markdown の非標準の拡張機能をいくつか備えています。

Haml 4.0 の時点で、このフィルターは Haml contrib で定義されていますが、歴史的な理由から自動的にロードされます。今後のバージョンの Haml では、デフォルトでロードされない可能性があります。このフィルターは Tilt を使用して実装されています。

:plain

フィルター処理されたテキストを解析しません。これは、. または - で始まる行を解析したくない場合に、HTML タグのない大きなテキストブロックに役立ちます。

:preserve

空白を保持した状態で、フィルター処理されたテキストをテンプレートに挿入します。preserveされたテキストブロックはインデントされず、改行は見栄えの良い出力を保持するために改行の HTML エスケープコードに置き換えられます。空白の保持も参照してください。

:ruby

フィルター処理されたテキストを通常の Ruby インタープリターで解析します。Ruby コードは、Haml テンプレートと同じコンテキストで評価されます。

:sass

Sass でフィルター処理されたテキストを解析して、<style> タグに CSS 出力を生成します。このフィルターは Tilt を使用して実装されています。

:scss

:sassフィルターと同様に、フィルター処理されたテキストをSassで解析しますが、新しいSCSS構文を使用して、<style>タグ内にCSS出力を生成します。このフィルターはTiltを使用して実装されています。

:textile

フィルター処理されたテキストをTextileで解析します。RedClothがインストールされている場合にのみ機能します。

Haml 4.0 の時点で、このフィルターは Haml contrib で定義されていますが、歴史的な理由から自動的にロードされます。今後のバージョンの Haml では、デフォルトでロードされない可能性があります。このフィルターは Tilt を使用して実装されています。

カスタムフィルター

独自のフィルターを定義することもできます。Haml::Filters::YourCustomFilter#compileは、Temple式を返す必要があります。

フィルターの最も簡単な例は次のようになります。

class HelloFilter < Haml::Filters::Base
  def compile(_node)
    [:static, "hello world"]
  end
end

Haml::Filters.registered[:hello] ||= HelloFilter

より複雑な例

class BetterFilter < Haml::Filters::Base
  def compile(node)
    temple = [:multi]
    temple << [:static, "hello "]
    temple << compile_text(node.value[:text])
    temple << [:static, " world"]
    temple
  end

  private
  def compile_text(text)
    if ::Haml::Util.contains_interpolation?(text)
      [:dynamic, ::Haml::Util.unescape_interpolation(text)]
    else
      [:static, text]
    end
  end
end

Haml::Filters.registered[:better] ||= BetterFilter

例については、Haml::Filtersを参照してください。

複数行: |

パイプ文字は複数行文字列を指定します。行末(空白の後)に配置され、|で終わる後続のすべての行が、同じ行にあるかのように評価されることを意味します。複数行ブロックの最後の行も|で終わる必要があることに注意してください。例:

%whoo
  %hoo= h(                       |
    "I think this might get " +  |
    "pretty long so I should " + |
    "probably make it " +        |
    "multiline so it doesn't " + |
    "look awful.")               |
  %p This is short.

は、次のようにコンパイルされます。

<whoo>
  <hoo>I think this might get pretty long so I should probably make it multiline so it doesn't look awful.</hoo>
  <p>This is short</p>
</whoo>

Hamlでの複数行宣言の使用は、意図的に扱いにくく設計されています。これは、Hamlテンプレートに大量のRubyコードを記述することを思いとどまらせるためのものです。複数行宣言を使用している場合は、立ち止まって考えてみてください。ヘルパーを使った方が良いのではないでしょうか?

ただし、複数行にまたがって記述することが、扱いやすく便利なケースがいくつかあります。その1つがHTML属性です。一部の要素には多数の属性があるため、|を使用せずに属性を折り返すことができます(属性を参照)。

また、テンプレート情報を多く必要とするRubyメソッドの呼び出しやデータ構造の宣言が必要になる場合があります。したがって、多数の引数を必要とするデータ構造や関数は、最後の行を除く各行がカンマで終わる限り、複数行に折り返すことができます(Rubyの挿入を参照)。

空白保持

Hamlにすべてのテキストをインデントしてほしくない場合があります。たとえば、pretextareaなどのタグは空白に敏感です。テキストをインデントすると、正しくレンダリングされません。

Hamlは、ドキュメントに挿入する前に改行を「保持」することによってこれに対処します。つまり、改行をHTML空白エスケープコードである&#x000A;に変換します。これにより、Hamlはインデントの再フォーマットを試行しません。

リテラルのtextareaおよびpreタグは、=を介して提供されたコンテンツを自動的に保持します。動的に生成されるtextareaおよびpreは自動的に保持できないため、Haml::Helpers.preserveまたは~コマンドを介して渡す必要があります。これは同じ効果があります。

リテラルテキストのブロックは、:preserveフィルターを使用して保持できます。

Turbo

Turbo-railsを使用している場合は、次のいずれかを行う必要があります。* html形式で命名規則に従う(つまり、すべての.hamlファイルが.html.hamlで終わるようにする)。または* 次のようにモンキーパッチを追加します。

```rb # config/initializers/haml.rb require “haml/rails_template”

module Haml class RailsTemplate def default_format :html end end end ```