web-dev-qa-db-ja.com

Rails)とは関係なくHAMLファイルのレイアウトを使用する

私の最終目標は、他の人に渡すためのいくつかの静的HTMLファイルを作成することです。

しかし、私のワークフローでは、基本的なソースファイルとしてHAMLを使用したいと思います。そうすることで、少なくとも私の側では、プロセスをDRYアップすることを望んでいます。

現在、最終的に共通のレイアウトを共有するページがたくさんあり、レイアウトをどのように組み込むのか疑問に思っています。

これが私の現在のコードです:

./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

レンダリングメソッドがRailsのコンテキスト外で定義されていないため、これは明らかに機能しませんが、私がやろうとしていることを理解できることを願っています。

助言がありますか?

36
Steven

2つの異なるRails機能: partials(renderを使用)layouts(yieldを使用)を混同しています)

それらのいずれか(または両方)のRailsのようなバージョンをHamlのみのプログラムに追加できます。

パーシャル

Railsビューでは、_render :partial_name_を使用して、ファイル__partial_name.html.haml_を包含ビューのその時点でレンダリングできます(実際にはRailsは、サポートされている任意のテンプレート言語を使用でき、使用するファイル名拡張子を修正することができますが、ここではHamlだけに固執します。Rails renderは利用できませんが、かなり簡単に追加できます。

単純なrenderメソッドは、適切なhamlファイルを見つけてレンダリングし、親に含めるためのhtml文字列を返すだけです。

_def render(partial)
  # assuming we want to keep the Rails practice of prefixing file names
  # of partials with "_"
  Haml::Engine.new(File.read("_#{partial}.html.haml")).render
end
_

_Haml::Engine.render_の最初の引数はスコープオブジェクトであり、hamlテンプレート内で使用可能なメソッドを追加するために使用できます。デフォルトは_Object.new_です。ただし、このような単純なケースでは、トップレベルでrenderメソッドを定義でき、Hamlテンプレートのスコープで使用できるようになります。 Haml::Engine.new(...).renderを呼び出す前に、スクリプトにrenderメソッドを配置し、テンプレートで次のように呼び出します。

_!!!
%html
  %head
    %title Hello
  %body
    =render :the_partial
_

これで、ファイル__the_partial.html.haml_が出力の適切なポイントにレンダリングされて表示されます。

ローカル変数

これをさらに一歩進めることができます。 Railsは、 ローカル変数 のハッシュをパーシャルに渡すことができます。Hamlは、2番目の引数として、ローカル変数として渡される変数のハッシュも受け入れます。 Haml renderメソッドに変換します。したがって、renderメソッドを展開して次のようにすると:

_def render(partial, locals = {})
  Haml::Engine.new(File.read("_#{partial}.html.haml")).render(Object.new, locals)
end
_

次のようなパーシャルを使用できます。

_%p You passed in #{foo}
_

テンプレートから次のように呼び出します。

_%body
  =render :partial, :foo => "bar"
_

レンダリングされます

_<body>
  <p>You passed in bar</p>
</body>
_

レイアウト

Railsでは、ビューのレイアウトを指定して、すべてのページが同じヘッダー、メニュー領域などを共有できるようにすることができます。これは、レイアウトファイルを指定することによって行われます。レイアウトファイル内でyieldを呼び出して実際のレンダリングを行います。問題のビュー。レイアウトはhamlに追加するのが少し難しいですが、それでも実行できます。

Hamls renderメソッドもブロックを受け入れるため、簡単な解決策は、レイアウトファイルをレンダリングし、ビューファイルをレンダリングするブロックを渡すことです。

_Haml::Engine.new(File.read("layout.html.haml")).render do
  Haml::Engine.new(File.read("view.html.haml")).render
end
_

これにより、レイアウトファイルに_layout.html.haml_が含まれている場所でレンダリングされた_view.html.haml_のコンテンツでレンダリングされた_=yield_のコンテンツが得られます。

content_for

ただし、Railsはそれよりも少し柔軟性があります。レイアウトファイルでyieldを複数回呼び出し、それぞれに特定の領域に名前を付け、ビュー内の_content_for_メソッドを使用して各領域に追加するコンテンツを指定できます。したがって、レイアウトファイルでは次のようになります。

_!!!
%html
  %head
    = yield :title
  %body
    =yield
_

そしてあなたの見解では:

_-content_for :title do
  %title Hello
%p
  Here's a paragraph.
_

Railsが実際に機能する方法は、最初にビューパーツをレンダリングし、すべての異なるセクションを保存してから、レイアウトをレンダリングし、yieldが常に適切なチャンクを提供するブロックを渡すことです。レイアウトで呼び出されます。小さなヘルパークラスを使用してこれを複製し、_content_for_メソッドを提供し、各領域のレンダリングされたチャンクを追跡できます。

_class Regions  
  def initialize
    @regions_hash={}
  end

  def content_for(region, &blk)  
    @regions_hash[region] = capture_haml(&blk)
  end

  def [](region)
    @regions_hash[region]
  end
end
_

ここでは、 _capture_haml_ method を使用して、出力に直接移動せずにレンダリングされたhamlを取得しています。これは、ビューの名前のない部分をキャプチャしないことに注意してください。

これで、ヘルパークラスを使用して最終出力をレンダリングできます。

_regions = Regions.new
unnamed = Haml::Engine.new(File.read("view_named.html.haml")).render(regions)

output = Haml::Engine.new(File.read("layout_named.html.haml")).render do |region|
  region ? regions[region] : unnamed
end
_

これで、変数outputに最終的にレンダリングされた出力が含まれます。

ここのコードは、Railsに含まれているすべての柔軟性を提供するわけではありませんが、ニーズに合わせてHamlのカスタマイズを開始する場所を示すだけで十分であることに注意してください。

75
matt
content = Haml::Engine.new(content_haml).render(
  Object.new, 
  :local_var_1 => ..., 
  :local_var_2 => ...
)


Haml::Engine.new(layout_haml).render(Object.new, :content => content)

layout.haml

!!!
%html
  %head
    %title
  %body
    = content

Object.newのインスタンス変数(意味のあるオブジェクトに置き換える)をhamlで使用することもできます。

5
Victor Moroz