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

发布于 2024-11-09 08:40:09 字数 772 浏览 0 评论 0原文

我的最终目标是创建几个静态 HTML 文件以交给其他人。

但对于我的工作流程,我希望将 HAML 作为基本源文件。在这样做时,我希望至少在我这边能够干燥这个过程。

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

这是我当前的代码:

./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 上下文之外未定义,但我希望它能明白我想做的事情。

有什么建议吗?

My end goal is to create several static HTML files for hand-off to other folks.

But for my workflow, I'd like to have HAML as the basic source files. In doing so, I'd hope to DRY up the process at least on my side.

Now I have a lot of pages that will ultimately be sharing a common layout, and I'm wondering how to incorporate the layouts.

Here's my current code:

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

Now this clearly doesn't work because the render method is undefined out of the context of Rails, but I hope it gets the point across what I'm trying to do.

Any suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

初见 2024-11-16 08:40:09

您混合了两个不同的 Rails 功能: partials(使用 render )布局(使用 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 模板的范围内可用。我们只需将 render 方法放在脚本中调用 Haml::Engine.new(...).render 之前,并在模板中像这样调用它:

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

现在,文件 _the_partial.html.haml 将出现在输出的适当位置处。

局部变量

我们可以更进一步。 Rails 允许您将 局部变量 的哈希值传递给局部变量。 Haml 还将接受作为局部变量传递的变量哈希,作为 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"

这将在 Rails 中渲染

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

布局

,您可以为视图指定布局,以便所有页面可以分享相同的
标题、菜单区域等。这是通过指定布局文件来完成的,您可以在其中调用 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< /code> 在布局中被调用。我们可以使用一个小帮助器类来复制它,以提供 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

现在变量 output 包含最终渲染的输出。

请注意,此处的代码并未提供 Rails 所包含的所有灵活性,但希望它足以向您展示从哪里开始自定义 Haml 以满足您的需求。

You're mixing up two distinct Rails feature: partials (using render) and layouts (using yield).

You can add a rails-like version of either (or both) of them to a Haml only program.

Partials

In a rails view, you can use render :partial_name to cause the file _partial_name.html.haml to be rendered at that point in the containing view (actually Rails allows you to use any templating language supported and it will find to correct filename extension to use, but I'll stick to just Haml here). Outside of Rails render isn't available, but it can be added fairly easily.

A simple render method would just find the appropriate haml file, render it, and return the html string for inclusion in the parent:

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

The first argument to Haml::Engine.render is a scope object, which we can use to add methods available inside the haml template. It defaults to Object.new. In a simple case like this, however, we can define the render method in the top level, and it will be available in the scope of the Haml template. We simply put our render method in the script before the call to Haml::Engine.new(...).render, and call it like this in our template:

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

Now the file _the_partial.html.haml will appear rendered at the appropriate point of the output.

Local variables

We can take this a step further. Rails allows you to pass in a hash of local variables to a partial. Haml will also accept a hash of variables to be passed as local variables, as the second argument to the Haml render method. So if we expand our render method to look like:

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

we can use a partial that looks something like:

%p You passed in #{foo}

and call it from our template with:

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

which will render

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

Layouts

In Rails, you can specify a layout for your views, so that all your pages can share the same
header, menu area etc. This is done by specifying a layout file, within which you call yield to render the actual view in question. Layouts are slightly more tricky to add to haml, but can still be done.

Hamls render method also accepts a block, so a simple solution would be to render the layout file, and pass a block that renders the view file:

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

This would give the contents of layout.html.haml rendered with the contents of view.html.haml rendered where the layout file contained =yield.

content_for

Rails is a bit more flexible than that though. It allows you to call yield multiple times in your layout file, naming a specific region in each case, and to specify the contents to be added at each region using the content_for method within your views. So in your layout file:

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

and in your view:

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

The way Rails actually works is to render the view part first, storing all the different sections, and then rendering the layout, passing a block that provides the appropriate chunk whenever yield is called in the layout. We can replicate this using a little helper class to provide the content_for method and keep track of the rendered chunks for each region:

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

Here we're using the capture_haml method to get the rendered haml without it going direct to the output. Note that this doesn't capture the unnamed part of the view.

We can now use our helper class to render the final output.

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

Now the variable output contains the final rendered output.

Note that the code here doesn't provide all the flexibility that's included with rails, but hopefully it's enough to show you where to start customising Haml to meet your needs.

许仙没带伞 2024-11-16 08:40:09
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 的实例变量(替换为有意义的对象)。

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

You can also use instance variables of Object.new (replace with meaningful object) in haml I believe.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文