我的最终目标是创建几个静态HTML文件,以便传递给其他人。
但是对于我的工作流程,我希望将HAML作为基本源文件。在这样做的时候,我希望至少在我这边干预这个过程。
现在我有很多页面最终将共享一个共同的布局,我想知道如何合并布局。
这是我目前的代码:
#!/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
!!!
%html
%head
%title Yay
%body
= yield
= render :layout => 'header' do
%p This is awesome
现在这显然不起作用,因为渲染方法在Rails的上下文中是未定义的,但我希望它能够解决我想要做的事情。
有什么建议吗?
答案 0 :(得分:75)
您混合了两个不同的Rails功能:partials (using render
)和layouts (using yield
)。
您可以将其中任何一个(或两个)的类似轨道的版本添加到仅限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模板的范围内可用。我们只是在调用render
之前将Haml::Engine.new(...).render
方法放在脚本中,并在我们的模板中将其调用为:
!!!
%html
%head
%title Hello
%body
=render :the_partial
现在文件_the_partial.html.haml
将在输出的适当位置呈现。
我们可以更进一步。 Rails允许您将local variables的哈希值传递给部分哈希值。 Haml还将接受作为局部变量传递的变量哈希值,作为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
。
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以满足您的需求。
答案 1 :(得分:5)
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
你也可以在haml中使用Object.new
的实例变量(替换为有意义的对象)。