Class: Jig::XML

Inherits:
Jig
  • Object
show all
Defined in:
lib/jig/xml.rb

Constant Summary collapse

Newlines =

These elements will have newlines inserted into the default constructions to increase the readability of the generated XML.

[:html, :head, :body, :title, :div, :p, :table, :script, :form]
Encode =

:nodoc:

Entities =

:nodoc:

Encode.keys.join
ATTRS =

:nodoc:

Gap::ATTRS
ATTRS_GAP =
Jig::ALGap.new(ATTRS)
Element_Cache =

ATTRS_GAP = Gap.new(ATTRS) { |h| h && h.map { |k,v| Jig::XML.attribute(k, v) } } # :nodoc:

{}
Empty_Element_Cache =

:nodoc:

{}
Cache =

:nodoc:

{}

Constants inherited from Jig

Before, DEFAULT_GAP, GAP, Replace, VERSION

Instance Attribute Summary

Attributes inherited from Jig

#contents, #rawgaps

Class Method Summary collapse

  • ._element!(tag) ⇒ Object

    Construct an XML empty element with one gap: * :__a filters a hash into an XML attribute list * :___ which is a default gap Jig::XML._element!('br') # => #<Jig: ["<br", :"__a{}", "/>"]>.

  • .anonymous(tag = 'div', *args) ⇒ Object

    Construct an anonymous XML element.

  • .attribute(aname, value) ⇒ Object

    Prepare aname and value for use as an attribute pair in an XML jig: * If value is nil or false, the empty string is returned.

  • .cdata(*args) ⇒ Object

    Construct a CDATA block.

  • .comment(*args) ⇒ Object

    Construct an XML comment element.

  • .comments(*args) ⇒ Object

    Construct a multiline XML comment element.

  • .element(tag = 'div', *args) ⇒ Object

    Construct a standard XML element with tag as the XML tag and a default gap for the contents of the element.

  • .element!(tag, *args) ⇒ Object

    Construct a standard XML empty element with tag as the XML tag.

  • .escape(target) ⇒ Object

    Returns a new string with <, >, and & converted to their HTML entity codes.

  • .method_missing(symbol, *args, &block) ⇒ Object

    Construct an HTML element using the method name as the element tag.

  • .parse ⇒ Object

    In addition to the parsing done by Jig.parse, Jig::XML.parse recognizes and constructs attribute gaps from text of the form: %=attribute,gapname= Jig.parse("<input%=type,itype />").plug(:itype, 'password') # .

  • .parse_other(delim, stripped) ⇒ Object

    Extend Jig.parse to recognize attribute gaps as %=attrname,gapname=.

  • .xml(*args) ⇒ Object

    Construct an XML declaration tag.

  • Methods inherited from Jig

    #+, #==, #===, #=~, #after, #after!, #before, #before!, #closed?, #concat, #eql?, #fill!, #filln!, #freeze, #gaps, #has_gap?, #index, #initialize, #initialize_copy, #inspect, interpolate, #join, #mult, null, #null?, #open?, #plug, #plug!, #plug_gap!, #plugn, #plugn!, #push, #push_jig, #slice, #split, #syntax, #to_jig, #to_s

    Constructor Details

    This class inherits a constructor from Jig

    Class Method Details

    ._anonymous(tag) ⇒ Object

    Construct a generic XML element with four gaps:

    • :__a filters a hash into an XML attribute list
    • :___ which is a default gap
    • tag which acts a placeholder for the element's opening and closing tag Jig::XML.element(:tag) # => #<Jig: ["<", :tag, :"a{}", ">\n", :, "</", :tag, ">\n"]>
    
    
    201
    202
    203
    204
    # File 'lib/jig/xml.rb', line 201
    
    def _anonymous(tag) # :nodoc:
      whitespace = Newlines.include?(tag.to_sym) && "\n" || ""
      new("<", tag.to_sym, ATTRS_GAP, ">#{whitespace}", GAP, "</", tag.to_sym, ">\n")
    end

    ._element(tag) ⇒ Object

    Construct a generic XML element with two gaps:

    • :__a filters a hash into an XML attribute list
    • :___ which is a default gap Jig::XML.element('div') # => #<Jig: ["<div", :"a{}", ">\n", :, "
    \n"]>
    
    
    189
    190
    191
    192
    193
    194
    # File 'lib/jig/xml.rb', line 189
    
    def _element(tag) 
      Element_Cache[tag] ||= begin
        whitespace = Newlines.include?(tag.to_sym) && "\n" || ""
        new("<#{tag}".freeze, ATTRS_GAP, ">#{whitespace}".freeze, GAP, "</#{tag}>\n".freeze).freeze
      end
    end

    ._element!(tag) ⇒ Object

    Construct an XML empty element with one gap:

    • :__a filters a hash into an XML attribute list
    • :___ which is a default gap Jig::XML._element!('br') # => #<Jig: ["<br", :"__a{}", "/>"]>
    
    
    211
    212
    213
    214
    215
    # File 'lib/jig/xml.rb', line 211
    
    def _element!(tag) # :nodoc:
      Empty_Element_Cache[tag] ||= begin
        new("<#{tag}".freeze, ATTRS_GAP, "/>\n".freeze).freeze
      end
    end

    .anonymous(tag = 'div', *args) ⇒ Object

    Construct an anonymous XML element. The single argument provides a name for a gap that replaces the XML start and end tags. Use plug to replace the gaps with an actual tag.

    a = anonymous(:heading)       # => #<Jig: ["<", :heading, ">", :___, "</", :heading, ">\n"]>
    b = a.plug(:heading, 'h1')    # => #<Jig: ["<", "h1", ">", :___, "</", "h1", ">\n"]>
    b.plug('contents')            # => #<Jig: ["<", "h1", ">", "contents", "</", "h1", ">\n"]>
    
    
    258
    259
    260
    261
    262
    263
    # File 'lib/jig/xml.rb', line 258
    
    def anonymous(tag='div', *args)
      attrs = args.last.respond_to?(:fetch) && args.pop || nil
      args.push(lambda{|*x| yield(*x) }) if block_given?
      args.push GAP if args.empty?
      _anonymous(tag).plug(ATTRS => attrs, GAP => args)
    end

    .attribute(aname, value) ⇒ Object

    Prepare aname and value for use as an attribute pair in an XML jig:

    • If value is nil or false, the empty string is returned.
    • If value is a symbol, an attribute gap is returned.
    • If value is a gap, the gap is returned.
    • If value is a proc, method or jig, the construction of the attribute is deferred by wrapping it in a proc inside a jig.
    • Otherwise, aname and value are converted to strings and rendered as an XML attribute pair. Examples: attribute('value', :firstname) # => Gap.new(:firstname) ... attribute('type', 'password') # => 'type="password"' attribute('type', nil) # => '' attribute('lastname', 'Einstein') # => 'lastname="Einstein"' a = attribute('lastname', Jig.new('Einstein')) # => #<Jig: [#Proc:0x00058624]> a.to_s # => 'lastname="Einstein"' b = attribute('lastname', Jig.new { }) # => #<Jig: [#Proc:0x000523dc] b.to_s # => '' c = attribute('lastname', Jig.new "") # => #<Jig: [#Proc:0x00055a3c] c.to_s # => 'lastname=""'
    
    
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    # File 'lib/jig/xml.rb', line 135
    
    def attribute(aname, value)
      case value
      when nil, false
        ""
      when Symbol
        AGap.new(value, aname)
        #Gap.new(value) { |fill| attribute(aname, fill) }
      when Gap
        value
      when Proc, Method
        Jig.new { attribute(aname, value.call) }
      when Jig
        Jig.new { attribute(aname, value.to_s) }
      else
        " #{aname}=\"#{value}\""
      end
    end

    .cdata(*args) ⇒ Object

    Construct a CDATA block

    Jig::XML.cdata('This data can have < & >')
    
    ]]>
    
    
    307
    308
    309
    310
    311
    312
    # File 'lib/jig/xml.rb', line 307
    
    def cdata(*args)
      args.push(lambda{|*x| yield(*x) }) if block_given?
      args.push GAP if args.empty?
      jig = (Cache[:cdata] ||= new("<![CDATA[\n".freeze, GAP, " ]]>\n".freeze).freeze)
      jig.plug(GAP, *args)
    end

    .comment(*args) ⇒ Object

    Construct an XML comment element.

    Jig::XML.comment("This is a comment")
    
    \<!-- This is a comment -->
    
    
    319
    320
    321
    322
    323
    324
    325
    326
    # File 'lib/jig/xml.rb', line 319
    
    def comment(*args)
      #:stopdoc:
      args.push(lambda{|*x| yield(*x) }) if block_given?
      args.push GAP if args.empty?
      jig = (Cache[:comment] ||= new("<!-- ".freeze, GAP, " -->\n".freeze).freeze)
      jig.plug(GAP, *args)
      #:startdoc:
    end

    .comments(*args) ⇒ Object

    Construct a multiline XML comment element.

    Jig::XML.comment("first line\nsecond line")
    
    \<!-- 
    first line
    second line
    -->
    
    
    336
    337
    338
    339
    340
    341
    # File 'lib/jig/xml.rb', line 336
    
    def comments(*args)
      args.push(lambda{|*x| yield(*x) }) if block_given?
      args.push GAP if args.empty?
      args.push "\n"
      comment("\n", *args)
    end

    .element(tag = 'div', *args) ⇒ Object

    Construct a standard XML element with tag as the XML tag and a default gap for the contents of the element. Jig::XML.element('h1') # => #<Jig: ["<h1", ">", :, "\n"]> Jig::XML.element('p', :class => 'body') # => #<Jig: ["<p", "class="body"", ">", :, "\n"]>

    
    
    269
    270
    271
    272
    273
    274
    # File 'lib/jig/xml.rb', line 269
    
    def element(tag='div', *args)
      attrs = args.last.respond_to?(:fetch) && args.pop || nil
      args.push(lambda(&Proc.new)) if block_given?
      args.push GAP if args.empty?
      _element(tag).plug(ATTRS => attrs, GAP => args)
    end

    .element!(tag, *args) ⇒ Object

    Construct a standard XML empty element with tag as the XML tag.

    Jig::XHTML.element!('br')              # => '<br />'
    
    h = { :name => 'year', :maxsize => 4, :type => :type }
    
    j = Jig::XHTML.element!('input', h)    # => '<input name="year" maxsize="4"/>'
    j.plug(:type => 'hidden')              # => '<input name="year" maxsize="4" type="hidden"/>'
    
    
    284
    285
    286
    287
    # File 'lib/jig/xml.rb', line 284
    
    def element!(tag, *args)
      attrs = args.last.respond_to?(:fetch) && args.pop || nil
      _element!(tag).plug(ATTRS => attrs, GAP => nil)
    end

    .escape(target) ⇒ Object

    Returns a new string with <, >, and & converted to their HTML entity codes.

    
    
    161
    162
    163
    # File 'lib/jig/xml.rb', line 161
    
    def escape(target)
      new(target.to_s.gsub(/[#{Entities}]/) {|m| "&#{Encode[m]};" })
    end

    .method_missing(symbol, *args, &block) ⇒ Object

    Construct an HTML element using the method name as the element tag. If a method ends with '!', the element is constructed as an empty element. If a method ends with '?', the element is constructed as an anonymous element. If a method ends with '', it is stripped and the result used as a the tag. If a method contains an '', it is converted to a ':' to provide XML namespace tags. If a method contains an '__', it is converted to a single '_'.

    Jig::XML.div.to_s # => "

    " Jig::XML.div_.to_s # => "
    " Jig::XML.br!to_s # =>
    " Jig::XML.heading? # => Jig["<", :heading, ">", :___, "</", :heading, ">"] Jig::XML.xhtml_h1 # => "xhtml:h1</xhtml:h1>" Jig::XML.xhtml__h1 # => "<xhtml_h1></xhtml_h1>"

    
    
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    # File 'lib/jig/xml.rb', line 230
    
    def method_missing(symbol, *args, &block)
      constructor = :element
      text = symbol.to_s
      if text =~ /!\z/
        text.chop!
        constructor = :element!
      elsif text =~ /\?\z/
        text.chop!
        constructor = :anonymous
      end
      if text =~ /_$/    # alternate for clashes with existing methods
        text.chop!
      end
      if text =~ /_/
        # Single _ gets converted to : for XML name spaces
        # Double _ gets converted to single _
        text = text.gsub(/([^_])_([^_])/){|x| "#{$1}:#{$2}"}.gsub(/__/, '_')
      end
      send(constructor, text, *args, &block)
    end

    .parseObject

    In addition to the parsing done by Jig.parse, Jig::XML.parse recognizes and constructs attribute gaps from text of the form: %=attribute,gapname= Jig.parse("<input%=type,itype />").plug(:itype, 'password') #

    
    
    156
    157
    158
    # File 'lib/jig/xml.rb', line 156
    
    def parse(*)
      super
    end

    .parse_other(delim, stripped) ⇒ Object

    Extend Jig.parse to recognize attribute gaps as %=attrname,gapname=. An attribute gap is returned.

    
    
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    # File 'lib/jig/xml.rb', line 167
    
    def parse_other(delim, stripped)
      if delim == '='
        if stripped =~ /\A(.*),(.*)\z/
          new({ $1 => $2.to_sym})
        else
          raise ArgumentError, "invalid gap syntax: #{quoted}"
        end
      else
        super
      end
    end

    .xml(*args) ⇒ Object

    Construct an XML declaration tag.

    Jig::XML.xml                   # => '<?xml version="1.0">'
    Jig::XML.xml(:lang => 'jp')    # => '<?xml version="1.0" lang="jp">'
    
    
    293
    294
    295
    296
    297
    298
    # File 'lib/jig/xml.rb', line 293
    
    def xml(*args)
      attrs = { :version => '1.0' }
      attrs.merge!(args.pop) if args.last.respond_to?(:fetch) 
      args.push(lambda{|*x| yield(*x) }) if block_given?
      new("<?xml", attrs, " ?>\n", *args)
    end