在独立于Rails的HAML文件中使用布局

我的最终目标是创build几个静态的HTML文件,以供其他人使用。

但是对于我的工作stream程,我希望将HAML作为基本的源文件。 在这样做的时候,我希望至less在我身边干掉这个过程。

现在我有很多页面将最终共享一个共同的布局,我想知道如何合并布局。

这是我现在的代码:

./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的上下文,但我希望它能够得到我想要做的事情。

有什么build议么?

你正在混合两个不同的Rails特性: partials(使用render )和布局(使用yield ) 。

你可以添加一个类似rails的版本(或两者)到一个Haml only程序。

谐音

在rails视图中,你可以使用render :partial_name来使文件_partial_name.html.haml在包含视图的那一点被渲染(实际上,Rails允许你使用任何支持的模板语言,并且它会find正确的文件扩展名使用,但我会坚持Haml在这里)。 Rails之外的render不可用,但它可以很容易地添加。

一个简单的render方法只会find适当的haml文件,渲染它,并返回包含在父级的htmlstring:

 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将显示在输出的适当位置。

局部variables

我们可以更进一步。 Rails允许你将局部variables的散列传递给一个局部variables 。 Haml也会接受一个哈希variables作为局部variables传递,作为Haml 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方法也接受一个块,所以一个简单的解决scheme是渲染布局文件,并传递一个渲染视图文件的块:

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

这将给layout.html.haml的内容渲染,其中layout.html.haml的内容呈现在layout文件包含的位置=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方法获取渲染的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 

现在variablesoutput包含最终的渲染输出。

请注意,这里的代码并没有提供rails所包含的所有灵活性,但希望能够告诉你在哪里开始定制Haml以满足您的需求。

 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使用Object.new实例variables(用有意义的对象replace),我相信。