ABach
ABach

Reputation: 3738

Nested blocks and ERB

For the life of me, I can't figure out why this doesn't work as expected.

Code:

require 'erb'

def say_hello(name)
  "Nice to see you, #{ name }!"
end

def greetings
  template = <<-TEMPLATE
Hello!
<%= yield %>
Goodbye!
  TEMPLATE
  ERB.new(template).result(binding)
end

people = ['Aaron', 'Bob', 'Tim', 'Juan']
t = greetings do
  people.each do |p|
    say_hello(p)
  end
end

puts t

(a bit contrived, I know, but it'll serve the point.)

What I Expect:

Hello!
Nice to see you, Aaron!
Nice to see you, Bob!
Nice to see you, Tim!
Nice to see you, Juan!
Goodbye!

What I Get:

Hello!
['Aaron', 'Bob', 'Tim', 'Juan']
Goodbye!

Thoughts:

I'm guessing this is happening because the interior block (beginning with people.each) gets coerced into a string before the block executes. Perhaps ERB doesn't like how I'm trying to inject a new block of constructed text into its template.

What's going on here?

Upvotes: 0

Views: 373

Answers (1)

Uri Agassi
Uri Agassi

Reputation: 37409

The return value of each is the array itself, not the return value of the block:

people.each do |p|
  say_hello(p)
end
# => ['Aaron', 'Bob', 'Tim', 'Juan']

You should use map, which returns the array of return values from the block:

people.map do |p|
  say_hello(p)
end
# => ["Nice to see you, Aaron!", "Nice to see you, Bob!", "Nice to see you, Tim!", "Nice to see you, Juan!"]

You will also need to concatenate the array to render it properly:

t = greetings do
  people.map do |p|
    say_hello(p)
  end.join("\n")
end

Upvotes: 2

Related Questions