require 'enumerator' module HTML class Generator attr_accessor :indentation, :stack, :buffer def initialize(indentation=" ") self.indentation=indentation self.stack=[] self.buffer="" end def write(text) whitespace=(1..self.stack.size).collect{self.indentation}.join self.buffer << whitespace+text.gsub("\n", "\n#{whitespace}")+"\n" end def start_tag(tag) text="<#{tag}>" self.write(text) self.stack << tag end def text(text); self.write("#{text}"); end def end_tag tag=self.stack.pop() text="" self.write(text) end def process(obj) proc=Proc.new do |head, tail| if tail.class==Array text=(0!=tail.size%2) ? tail.pop() : nil if tail.empty? self.start_tag(head) self.text(text) unless text==nil self.end_tag else self.start_tag(head) tail.each_slice(2){|h, t|proc.call(h, t)} self.text(text) unless text==nil self.end_tag end else self.start_tag(head) self.text(tail) self.end_tag end end proc.call(obj[0], obj[1]) end end def HTML.generate(obj) generator=HTML::Generator.new generator.process(obj) generator.buffer end end puts HTML.generate(['html', ['head', ['title', "Here's the title"], 'body', ['h1', "Here's the body"]]])