require 'artisan'module Markabu class Element attr_reader :attributes, :children def initialize(name) @name = name @children = [] @attributes = {} end def to_html(indent = 0) indentation = " " * (indent * 2) result = "" << indentation << "<#@name" @attributes.keys.map{|x| x.to_s}.sort.each do |key| result << " #{key} = \"#{@attributes[key.to_sym]}\"" end result << " class = \"" << @class.sort.join(" ") << '"' if @class result << " id = \"#@id\"" if @id result << ">\n" @children.each do |child| result << child.to_html(indent + 1) end result << indentation << "</#@name>" result << "\n" end end class TextElement < Element def initialize(text) super '' @children << text end def to_html(indent = 0) "#{' ' * (indent * 2)}#{@children[0]}\n" end end class DocumentElement < Element def initialize super 'html' end end class BodyElement < Element def initialize super 'body' end end class DivElement < Element def initialize super 'div' end end ## class DivBuilder < Artisan::Builder target DivElement hash_arg :attributes chain :div, :children, self modifier(/^([A-Za-z0-9_]+)$/) do |target, class_name| target.instance_eval do (@class ||= []) << class_name end end modifier(/^([A-Za-z0-9_]+)!$/) do |target, id| target.instance_variable_set :@id, id end default do |target, value| target.children << TextElement.new(value) if value.is_a? String end end class BodyBuilder < Artisan::Builder target BodyElement hash_arg :attributes chain :div, :children, DivBuilder end class DocumentBuilder < Artisan::Builder target DocumentElement hash_arg :attributes do {:version => 4} end chain :body, :children, BodyBuilder endenddef html(hash_args = {}, &block) if block_given? Artisan::Overseer.build(Markabu::DocumentBuilder, hash_args, &block) else Artisan::Overseer.new(Markabu::DocumentBuilder) endendmy_doc = html :lol => 5 do body :font => 'verdana' do div.the_best! {"Hello, world!"} div.blue.short {"Like a smurf."} endendputs my_doc.to_html=begin<html lol = "5" version = "4"> <body> <div id = "the_best"> Hello, world! </div> <div class = "blue short"> Like a smurf. </div> </body></html>=end