I have the following Ruby script:
require 'nokogiri'
require 'erb'
listing = %Q{<% listing "app/controllers/purchases_controller.rb", :id => "ch01_724" do %>
foo
<% end %>}
erb = ERB.new(listing, nil, nil, "@output")
def listing(title, attributes={})
builder = Nokogiri::XML::Builder.new do |xml|
xml.example(attributes) do
xml.title "Listing 1.1 #{title}"
xml.programlisting do
yield
end
end
end
@output.concat(builder.doc.root.to_xml)
end
p erb.result(binding)
When it runs, it outputs the following content:
"\n foo\n <example id=\"ch01_724\">\n <title>Listing 1.1 app/controllers/purchases_controller.rb</title>\n <programlisting/>\n</example>"
The “foo” part of this string should be inside the programlisting element, but instead is, for some reason, prefixed to the beginning of the string.
Why is this, and how can I fix it?
That’s because by yielding you’re passing control to ERB, which gets the “foo” and then you’re concatenating the output from the method after that.
How Rails does this is by using capture, which basically switches the output buffer for a new string, and then concatenates that new string.
Something like this seems to work: