RoR:在Rails代码中erb有什么好处?

时间:2011-03-02 19:28:31

标签: ruby-on-rails ruby-on-rails-3 erb

我读了一篇名为Block Helpers in Rails 3的Magnus Holm的一篇令人回味的帖子,其中他指出Rails 3将ERB的语法弯曲得太过分了。 (在'原始'ERB中,ERB构造只能跨越单个语句.Rails 3允许 - 甚至需要 - 跨越多个语句。)

这让我想知道:使用ERB而不是Ruby的本地字符串处理有什么真正的优势?为了深入研究,我采用了ERB文档中列出的示例,并在ERB和本机Ruby字符串中进行了尝试。事实证明,Ruby丰富的字符串处理库使翻译变得非常简单 - 甚至是直观的。

这是它的外观。这两者相同(直接从ERB文件中提取):

require "erb"

# Build template data class.
class Product
  def initialize( code, name, desc, cost )
    @code = code
    @name = name
    @desc = desc
    @cost = cost
    @features = [ ]
  end

  def add_feature( feature )
    @features << feature
  end

  # Support templating of member data.
  def get_binding
    binding
  end
end

这是用ERB编写的模板和扩展:

# ================================================================
# using ERB
erb_template = %{
    <html>
      <head><title>Ruby Toys -- <%= @name %></title></head>
      <body>
        <h1><%= @name %> (<%= @code %>)</h1>
        <p><%= @desc %></p>
        <ul>
          <% @features.each do |f| %>
            <li><b><%= f %></b></li>
          <% end %>
        </ul>
        <p>
          <% if @cost < 10 %>
            <b>Only <%= @cost %>!!!</b>
          <% else %>
             Call for a price, today!
          <% end %>
        </p>
      </body>
    </html>
  }.gsub(/^  /, '')
rhtml = ERB.new(erb_template)
# Produce results
@r1 = rhtml.result(toy.get_binding)

这是用纯Ruby编写的模板:

# ================================================================
# using native Ruby strings
ruby_template = %q{"
    <html>
      <head><title>Ruby Toys -- #{ @name }</title></head>
      <body>
        <h1>#{ @name } (#{ @code })</h1>
        <p>#{ @desc }</p>
        <ul>
          #{ @features.map do |f|
               "<li><b>#{f}</b></li>\n"
             end.join }
        </ul>
        <p>
          #{ if @cost < 10
               "<b>Only #{ @cost }!!!</b>"
             else
               "Call for a price, today!"
             end
           }
        </p>
      </body>
    </html>
  "}
# Produce results
@r2 = eval(ruby_template, toy.get_binding)

这些产生相同的结果(模数空白)。 ERB是否更简单或更难是真正的品味和经验问题。从有关ERB和&lt;%= ...%&gt;的问题数量来看vs&lt;%...%&gt; vs&lt;%= ... - %&gt;,似乎很多人可能更容易坚持直接使用Ruby。

冒着开始某种圣战的风险,当原生Ruby做同样的工作时,为什么还要用ERB呢?您认为ERB有用吗? Rails是否应该接受“原生Ruby”模板?

2 个答案:

答案 0 :(得分:4)

Magnus Holm在这里;很高兴看到你喜欢这篇文章: - )

首先让我们看看模板(是的,插值是一个模板),作为使用常规代码构建字符串的演变:

# "Regular" way of constructing a string:
str = "Hello World: "
@users.each do |user|
  str << "How are you today, "
  str << user.name
  str << "? \n"
end

如果我们看一下这段代码,很明显有三种模式可以重复:

  • 我们附加了大量静态文字:str << "Static"
  • 我们附加了一些动态代码:str << expresstion
  • 我们有一些代码可以改变控制流程:@users.each

ERB的优点在于它是这些模式的完美同构,这意味着用户可以通过常规方式构造字符串来思考它。它只是一种构建字符串的方法,它更关注静态部分(因为它们很常见)而不是动态部分。

作为“纯粹主义者”,你注意到这不是最低级别。这是完全正确的:只要您可以评估图灵完整代码,您的模板引擎就会变得图灵完整,从技术上讲,您不需要任何其他内容。只需嵌套模板引擎就不需要块。

现在我们需要考虑低级别易于理解之间的区别。是的,当您移除建筑部件时,最终会使用较小的核心,但这并不一定会使其更容易理解。您可以对GOTO进行类比:您可以使用单个概念(GOTO)创建任何循环/条件,但事实证明使用if / while语句更容易推理代码。为什么?因为出现模式!我们不是在每次看到它们时从概念上解析这些模式,而是创建我们可以立即理解的抽象更容易。

在您的示例中,我认为将在任何模板中使用一种模式:@users.map { |f| code }.join。这是完全 ERB试图抽象出来的东西,所以你可以忘记关于你的逻辑的细节和原因。

我也相信如果你让模板引擎变得更简单,但仍然让图灵完成,那么无论如何你都会抽象出这些细节。你会发现一个模式出现了,作为DRY编码器,你将开始创建帮助器等。你实际上是在另一个上面实现你自己的小模板引擎。现在一切都取决于基本语言的语法灵活性,无论你是否设法抽象出真正的细节而没有太多的其他噪音。例如,有Lisp风格支持静态类型和模式匹配,但通常它无法击败专门针对该问题设计的语法。

那么,使用ERB而不是Ruby的本地字符串处理有什么真正的优势?在一句话中:它为常用模式提供了很好的语法。

  

您认为ERB有用吗?

是和否。我认为插值肯定是不是正确的方式。您将在模板中看到模式,并且在模板方面没有任何东西胜过自定义语法。我认为ERB非常有用,但它在某些方面缺乏:它没有块也是表达式的概念:

# This block is more like a statement (we don't care about the return value)
@users.each do |foo|
  str << "Hello"
end

# This block is an expression
str << form_for(thing) do
  another_string
end

我不知道你是否可以用语法解决这个问题,但是现在它在每个框架中都“固定”了,并且没有办法编写适用于多个框架的块帮助程序。我希望看到一种更“官方”的方式来解决这个问题。

  

Rails是否也应该接受“原生Ruby”模板?

Tilt已经做到了,最好的解决方案是如果Rails切换到Tilt,但我不认为“本机Ruby”毕竟是有用的。如果它是一个简短的模板,您当然可以在代码中使用插值字符串。如果它是一个大模板并且你要将它从Ruby文件中移出,为什么不使用为模板设计的语法?

答案 1 :(得分:1)

Rails是自以为是的软件。它带有一堆“默认”的做事方式,我猜核心团队同意他们首选的做事方式 - erb,Test :: Unit,prototype等等,但没有什么可以阻止你改变这些(更多)使用Rails 3)。

在我看来,在Rails中的erb,尽管不像普通的erb那么远远比ruby字符串插值更好 - 特别是当涉及到块时。不得不为块内的HTML打破字符串对我来说太可怕了。

然而又一次,haml看起来很可怕,而其他人则发誓并讨厌erb。这完全取决于您的偏好。这就是为什么Rails使开发人员很容易创建自己的模板系统。我不知道是否存在,但没有什么能阻止开发人员创建一个仅使用红宝石字符串的模板系统。

那么,在回答“应该Rails接受”原生Ruby“模板吗?”时,它已经做到了。只要其他人实现它;)

相关问题