Your problem is not that @result
is reset, only that you add into the @result
the return value of instance_eval(&block)
, which is the last line in the block, and not the aggregated block. This should work better (although not perfectly):
class HtmlDsl
attr_reader :result
def initialize(&block)
instance_eval(&block)
end
private
def method_missing(name, *args, &block)
tag = name.to_s
content = args.first
(@result ||= '') << "<#{tag}>"
if block_given?
instance_eval(&block)
else
@result << content
end
@result << "</#{tag}>"
end
end
So now:
html = HtmlDsl.new do
html do
head do
title 'yoyo'
end
body do
h1 'hey'
end
end
end
p html.result
#=> "<html><head><title>yoyo</title></head><body><h1>hey</h1></body></html>"
What I've done is that each call actually renders a fragment to the @result
, so inner calls render inner fragments, each wrapping its own inner fragments with tags.