为什么erb块连接块内容

Why erb blocks concatenate the block content

我有以下代码:

require 'erb'

def body &block
  content = block.call
  content = block.call
  content = block.call
  content
end

x = 2
template = ERB.new <<-EOF
  <% body do %>
     2
  <% end %>
EOF

template.run(binding)

当我执行它时输出 2 2 2。为什么在 body 方法中对 block.call 的每次调用都会连接块的内容?

为什么如果我使用以下模板就不会发生:

template = ERB.new <<-EOF
  <%= body do
     2
  end %>
EOF

我无法理解这里发生的事情。我在使用 rails 时遇到了这个问题,但将代码隔离为纯 Ruby 以试图了解问题所在。

这是因为 ERB 的运作方式。请参阅模板的 erb-generated ruby 源代码(template.src,下面是经过美化的),对于以前的模板:

_erbout = +''
_erbout.<< "  ".freeze
body do
  _erbout.<< "\n     2\n  ".freeze      # <<-- this is the line that produces extra output
end
_erbout.<< "\n".freeze
_erbout

对于后者:

_erbout = +''
_erbout.<< "  ".freeze
_erbout.<<(( body do
     2                                  # <<- and this time it is just plain ruby code
  end
).to_s)
_erbout.<< "\n".freeze
_erbout

注意当 运行.

时如何阻止输出到同一个缓冲区

实际上这是正常的并且被广泛使用,例如,对于传递给 each 方法的以下块,您希望每个 运行 的输出被串联:

<% @items.each do |item| %>
  Item <%= item %>
<% end %>