items = ['abc', 'def', 'ghi'] 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 puts xml.to_s
The XML class:
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 "<?xml #{_fmt_atts(part[1])}?>" when :open part[2] ? "<#{part[1]} #{_fmt_atts(part[2])}>" : "<#{part[1]}>" when :close "</#{part[1]}>" 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