Follow me
RSS feed
My sources
My Viadeo

XML::DSL

Greg | 10 Jul 2009

rubyJ'ouvre aujourd'hui la nouvelle catégorie snippets en vous proposant une DSL pour générer du XML.

class XML
  class TagError < ArgumentError
  end
  
  class DSL
    def initialize( helper, &block )
      @__x_d_level = 0
      @__x_d_helper = helper
      @__x_d_helper.instance_variables.each do |ivar|
        self.instance_variable_set(
          ivar, @__x_d_helper.instance_variable_get(ivar)
        )
      end
      @__x_d_builder = ""
      instance_eval(&block) if block
    end

    def __
      " "*@__x_d_level
    end

    def _(x)
      @__x_d_builder << __ << x << "\n"
    end
    
    def tag!(sym, *args, &block)
      tag = {
        :bra => "<",
        :ket => " />",
        :name => sym.id2name,
        :close => block_given?(),
        :attrs => "",
        :value => ""
      }
              
      args.each do |a|
        if a.class == Hash
          a.each do |k, v|
            tag[:attrs] << " #{k.to_s}='#{v}'"
          end
        elsif a.class == String
          tag[:close] = true
          tag[:value] << a << "\n"
        end
      end
      
      if tag[:name].match( /\?$/ )
        tag[:name].gsub!( /\?$/, "" )
        tag[:bra] = "<?"
        tag[:ket] = "?>"
        
        if tag[:close] == true
          raise XML::TagError, "Malformated traitment tag!"
        end
      end

      @__x_d_builder << __ << tag[:bra] << "#{tag[:name]}#{tag[:attrs]}"
      if tag[:close]
        @__x_d_builder << ">\n"
      else
        @__x_d_builder << tag[:ket] << "\n"
      end
      
      @__x_d_level += 2
      
      @__x_d_builder << __ << tag[:value] if tag[:value].size > 0
      instance_eval(&block) if block
      
      @__x_d_level -= 2
      
      if tag[:close]
        @__x_d_builder << __ << "</#{tag[:name]}>\n"
      end
    end
    
    def cdata( x = "", &block )
      @__x_d_builder << __ << "<![CDATA["
      if x.match( /\n/ ) or block
        @__x_d_level += 2
        @__x_d_builder << "\n" << __ << x << "\n" if x.size > 0
        instance_eval(&block) if block
        @__x_d_level -= 2
        @__x_d_builder << __ 
      else
        @__x_d_builder << x if x.size > 0
      end
      @__x_d_builder << "]]>\n"
    end
    
    def to_s
      @__x_d_builder
    end
    
    def method_missing(sym, *args, &block)
      if @__x_d_helper.respond_to?(sym, true)
        @__x_d_helper.send(sym, *args, &block)
      else
        tag!(sym, *args, &block)
      end
    end
  end
end
Copyright © 2009 - 2011 Grégoire Lejeune.
All documents licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License, except ones with specified licence.
Powered by Jekyll.