File: active_support/vendor/builder-2.1.2/builder/xmlbase.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: Builder#5
  class: IllegalBlockError#8
inherits from
  RuntimeError ( Builtin-Module )
  class: XmlBase#12
inherits from
  BlankSlate   
has properties
method: initialize / 2 #22
method: tag! / 3 #30
method: method_missing / 3 #37
method: text! / 1 #80
method: << / 1 #97
method: nil? #107
method: _escape / 1 #114
method: _escape_quote / 1 #118
method: _newline #122
method: _indent #127
method: _nested_structures / 1 #132

Code

   1  #!/usr/bin/env ruby
   2 
   3  require 'builder/blankslate'
   4 
   5  module Builder
   6 
   7    # Generic error for builder
   8    class IllegalBlockError < RuntimeError; end
   9 
  10    # XmlBase is a base class for building XML builders.  See
  11    # Builder::XmlMarkup and Builder::XmlEvents for examples.
  12    class XmlBase < BlankSlate
  13 
  14      # Create an XML markup builder.
  15      #
  16      # out::     Object receiving the markup.  +out+ must respond to
  17      #           <tt><<</tt>.
  18      # indent::  Number of spaces used for indentation (0 implies no
  19      #           indentation and no line breaks).
  20      # initial:: Level of initial indentation.
  21      #
  22      def initialize(indent=0, initial=0)
  23        @indent = indent
  24        @level  = initial
  25      end
  26 
  27      # Create a tag named +sym+.  Other than the first argument which
  28      # is the tag name, the arguments are the same as the tags
  29      # implemented via <tt>method_missing</tt>.
  30      def tag!(sym, *args, &block)
  31        method_missing(sym.to_sym, *args, &block)
  32      end
  33 
  34      # Create XML markup based on the name of the method.  This method
  35      # is never invoked directly, but is called for each markup method
  36      # in the markup block.
  37      def method_missing(sym, *args, &block)
  38        text = nil
  39        attrs = nil
  40        sym = "#{sym}:#{args.shift}" if args.first.kind_of?(Symbol)
  41        args.each do |arg|
  42          case arg
  43          when Hash
  44            attrs ||= {}
  45            attrs.merge!(arg)
  46          else
  47            text ||= ''
  48            text << arg.to_s
  49          end
  50        end
  51        if block
  52          unless text.nil?
  53            raise ArgumentError, "XmlMarkup cannot mix a text argument with a block"
  54          end
  55          _indent
  56          _start_tag(sym, attrs)
  57          _newline
  58          _nested_structures(block)
  59          _indent
  60          _end_tag(sym)
  61          _newline
  62        elsif text.nil?
  63          _indent
  64          _start_tag(sym, attrs, true)
  65          _newline
  66        else
  67          _indent
  68          _start_tag(sym, attrs)
  69          text! text
  70          _end_tag(sym)
  71          _newline
  72        end
  73        @target
  74      end
  75 
  76      # Append text to the output target.  Escape any markup.  May be
  77      # used within the markup brackets as:
  78      #
  79      #   builder.p { |b| b.br; b.text! "HI" }   #=>  <p><br/>HI</p>
  80      def text!(text)
  81        _text(_escape(text))
  82      end
  83 
  84      # Append text to the output target without escaping any markup.
  85      # May be used within the markup brackets as:
  86      #
  87      #   builder.p { |x| x << "<br/>HI" }   #=>  <p><br/>HI</p>
  88      #
  89      # This is useful when using non-builder enabled software that
  90      # generates strings.  Just insert the string directly into the
  91      # builder without changing the inserted markup.
  92      #
  93      # It is also useful for stacking builder objects.  Builders only
  94      # use <tt><<</tt> to append to the target, so by supporting this
  95      # method/operation builders can use other builders as their
  96      # targets.
  97      def <<(text)
  98        _text(text)
  99      end
 100 
 101      # For some reason, nil? is sent to the XmlMarkup object.  If nil?
 102      # is not defined and method_missing is invoked, some strange kind
 103      # of recursion happens.  Since nil? won't ever be an XML tag, it
 104      # is pretty safe to define it here. (Note: this is an example of
 105      # cargo cult programming,
 106      # cf. http://fishbowl.pastiche.org/2004/10/13/cargo_cult_programming).
 107      def nil?
 108        false
 109      end
 110 
 111      private
 112 
 113      require 'builder/xchar'
 114      def _escape(text)
 115        text.to_xs
 116      end
 117 
 118      def _escape_quote(text)
 119        _escape(text).gsub(%r{"}, '&quot;')  # " WART
 120      end
 121 
 122      def _newline
 123        return if @indent == 0
 124        text! "\n"
 125      end
 126 
 127      def _indent
 128        return if @indent == 0 || @level == 0
 129        text!(" " * (@level * @indent))
 130      end
 131 
 132      def _nested_structures(block)
 133        @level += 1
 134        block.call(self)
 135      ensure
 136        @level -= 1
 137      end
 138    end
 139  end