class XML # blank slate instance_methods.each { |m| undef_method m unless (m =~ /^__|instance_eval$/)} # Each item in @doc is an array containing three values: type, value, attributes def initialize(&block) @doc = [] instance_eval(&block) end def method_missing(tag, *args, &block) value = block ? nil : args.pop attributes = args.pop @__to_s = nil # invalidate to_s cache if value @doc << [:open, tag, attributes] << [:value, value] << [:close, tag] else @doc << [:open, tag, attributes] instance_eval(&block) @doc << [:close, tag] end end def instruct!(atts = nil) @doc << [:instruct, atts || {:version => "1.0", :encoding => "UTF-8"}] end def to_s @__to_s ||= @doc.map{|i| _fmt_part i}.join end alias_method :inspect, :to_s def _fmt_part(part) case part[0] when :instruct "" when :open part[2] ? "<#{part[1]} #{_fmt_atts(part[2])}>" : "<#{part[1]}>" when :close "" when :value part[1].to_s end end def _fmt_atts(atts) atts.inject([]) {|m, i| m << "#{i[0]}=#{i[1].to_s.inspect}"}.join(' ') end end def t1(list) xml = XML.new do instruct! reality(:time => Time.now) do event do type 1 path "/sharon" value "abcdefg" end list.each {|i| item i} end end xml.to_s end require 'rubygems' require 'builder' def t2(list) xml = Builder::XmlMarkup.new(:indent => 2) xml.instruct! xml.reality(:time => Time.now) do xml.event do xml.type 1 xml.path "/sharon" xml.value "abcdefg" end list.each {|i| xml.item i} end xml.to_s end puts "**************" puts t1([]) puts "**************" puts t2([]) puts "**************" require 'benchmark' n = 1000 list = []#(1..10).map {rand(76564).to_s(36)} Benchmark.bm do |x| x.report('quick&dirty') {n.times {t1(list)}} x.report('builder') {n.times {t2(list)}} end __END__ class EventsController < ServerSide::Controller::Base.mount('/events/:format') invoke_by_parameter :format, :default => :html def before_response @events = Events.select end def xml render_xml('text/xml+svg') do events @events.to_xml end end end xml = XML.new do instruct! reality(:time => Time.now) do event do type 1 path "/sharon" value "abcdefg" end list.each {|i| item i} end end xml.to_s