【问题标题】:RoR: what are the benefits of erb in Rails code?RoR:在 Rails 代码中使用 erb 有什么好处?
【发布时间】:2011-03-02 19:28:30
【问题描述】:

我阅读了 Magnus Holm 的一篇题为 Block Helpers in Rails 3 的帖子,其中他指出 Rails 3 过度弯曲 ERB 的语法。 (在“原始”ERB 中,ERB 构造只能跨越单个语句。Rails 3 允许 - 甚至需要 - 跨越多个语句。)

这让我想知道:与 Ruby 的原生字符串处理相比,使用 ERB 的真正优势是什么?为了深入研究这一点,我采用了 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 和 vs vs 的问题数量来看,似乎很多人可能更容易坚持纯 Ruby .

冒着引发某种圣战的风险,当原生 Ruby 做同样的工作时,为什么还要使用 ERB?你觉得ERB有用吗? Rails 是否也应该接受“原生 Ruby”模板?

【问题讨论】:

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


    【解决方案1】:

    这里是马格努斯霍尔姆;很高兴看到你喜欢这篇文章:-)

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

    # "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 &lt;&lt; "Static"
    • 我们添加了一些 动态 代码:str &lt;&lt; expresstion
    • 我们有一些 代码可以改变控制流:@users.each

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

    作为“纯粹主义者”,您已经注意到这不是最低级别。这是完全正确的:只要您可以评估图灵完备的代码,您的模板引擎就成为图灵完备的,从技术上讲,您不需要任何其他东西。当您可以简单地嵌套模板引擎时,您不需要块。

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

    在您的示例中,我相信任何模板都会使用一种模式:@users.map { |f| code }.join。这正是ERB试图抽象出来的,这样你就可以忘记你的逻辑的细节和原因。

    我还相信,如果您要让模板引擎更简单,但仍要使其图灵完备,那么无论如何您都会抽象出这些细节。您将意识到出现了一种模式,并且作为 DRY 编码器,您将开始创建助手等。您实际上是在另一个之上实现自己的小模板引擎。现在一切都取决于基础语言的语法灵活性,无论您是否设法在没有太多其他噪音的情况下抽象出真实的细节。例如,有支持静态类型和模式匹配的 Lisp 风格,但通常无法击败专门针对该问题设计的语法。

    那么,与 Ruby 的原生字符串处理相比,使用 ERB 的真正优势是什么?一句话:它为您提供了常见模式的良好语法。

    你认为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 文件中移出,为什么不使用为模板设计的语法呢?

    【讨论】:

      【解决方案2】:

      Rails 是固执己见的软件。它附带了一堆“默认”的做事方式,我猜核心团队同意这是他们首选的做事方式——erb、Test::Unit、原型等,但没有什么可以阻止你改变这些(更是如此使用 Rails 3)。

      在我看来,Rails 中的 erb 尽管与普通的 erb 不太一样,但比 ruby​​ 字符串插值要好得多——尤其是在块方面。不得不为块中的 HTML 重新分解成字符串对我来说看起来很可怕。

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

      所以,在回答“Rails 是否也应该接受“原生 Ruby”模板?”时,它已经接受了。只要其他人实现它;)

      【讨论】:

      • 你应该再给haml一次机会,你需要一段时间才能成长,但一旦成功就很难回头。我讨厌它,直到我找到了一个 textmate 包。
      • @jonnii,我用过很多次。我仍在从事的许多项目都在使用它,我可以很肯定地说,在我看来,这太可怕了。如果我正在编写 html,我想使用 html。我编写干净的 html 并有效地使用部分和助手没有问题。阅读写得很好的html没有任何问题。除了一些粗俗的 ERB 之外,我无法想象在我的模板系统中还需要其他任何东西。
      • 我喜欢它的标记较少,因为嵌套负责发出结束标签,但我知道你的意思。你见过 Razor 的 asp.net mvc 视图引擎吗?如果我们有类似的东西用于rails,那就太好了。
      • 我没看过……看起来还不错!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-04
      • 1970-01-01
      • 1970-01-01
      • 2011-01-11
      相关资源
      最近更新 更多