#!/usr/bin/env ruby require 'builder/blankslate' module Builder # Generic error for builder class IllegalBlockError < RuntimeError; end # XmlBase is a base class for building XML builders. See # Builder::XmlMarkup and Builder::XmlEvents for examples. class XmlBase < BlankSlate # Create an XML markup builder. # # out:: Object receiving the markup. +out+ must respond to # <<. # indent:: Number of spaces used for indentation (0 implies no # indentation and no line breaks). # initial:: Level of initial indentation. # encoding:: When encoding and $KCODE are set to 'utf-8' # characters aren't converted to character entities in # the output stream. def initialize(indent=0, initial=0, encoding='utf-8') @indent = indent @level = initial @encoding = encoding.downcase end # Create a tag named +sym+. Other than the first argument which # is the tag name, the arguments are the same as the tags # implemented via method_missing. def tag!(sym, *args, &block) method_missing(sym.to_sym, *args, &block) end # Create XML markup based on the name of the method. This method # is never invoked directly, but is called for each markup method # in the markup block. def method_missing(sym, *args, &block) text = nil attrs = nil sym = "#{sym}:#{args.shift}" if args.first.kind_of?(::Symbol) args.each do |arg| case arg when ::Hash attrs ||= {} attrs.merge!(arg) else text ||= '' text << arg.to_s end end if block unless text.nil? ::Kernel::raise ::ArgumentError, "XmlMarkup cannot mix a text argument with a block" end _indent _start_tag(sym, attrs) _newline begin _nested_structures(block) ensure _indent _end_tag(sym) _newline end elsif text.nil? _indent _start_tag(sym, attrs, true) _newline else _indent _start_tag(sym, attrs) text! text _end_tag(sym) _newline end @target end # Append text to the output target. Escape any markup. May be # used within the markup brackets as: # # builder.p { |b| b.br; b.text! "HI" } #=>
HI
HI