lcjury
lcjury

Reputation: 1258

Why erb blocks concatenate the block content

I have the following code:

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)

When I execute it outputs 2 2 2. Why in each call to block.call inside the body method it is concatenating the content of the block?

Why if I use the following template it doesn't happens:

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

I can't get my mind around what's happening here. I had this problem with rails but isolated the code to plain Ruby to try to understand what the problem was.

Upvotes: 1

Views: 361

Answers (1)

Vasfed
Vasfed

Reputation: 18474

This is because how ERB works. See erb-generated ruby source for your templates (template.src, below is prettified), for the former template:

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

and for the latter:

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

note how blocks output to the same buffer when being run.

Actually this is normal and is widely used, for example for the below block that's passed to each method you expect output from each run to be concatenated:

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

Upvotes: 3

Related Questions