lib/apricoteatsgorilla.rb in smacks-apricoteatsgorilla-0.4.5 vs lib/apricoteatsgorilla.rb in smacks-apricoteatsgorilla-0.4.6
- old
+ new
@@ -1,245 +1,4 @@
-require "rubygems"
-require "iconv"
-require "hpricot"
+$:.unshift(File.join(File.dirname(__FILE__), "apricoteatsgorilla"))
-# Apricot eats Gorilla is a SOAP communication helper.
-#
-# It translates between SOAP messages (XML) and Ruby Hashes while offering some
-# helpful methods for working with SOAP webservices. Apricot eats Gorilla was
-# initially based on CobraVsMongoose but uses Hpricot instead of REXML.
-class ApricotEatsGorilla
- class << self # Class methods
-
- # Flag to enable sorting of Hash keys.
- attr_accessor :sort_keys
-
- # Flag to disable conversion of tag names to lowerCamelCase.
- attr_accessor :disable_tag_names_to_lower_camel_case
-
- # Flag to disable conversion of Hash keys to snake_case.
- attr_accessor :disable_hash_keys_to_snake_case
-
- # Flag to disable conversion of Hash keys to Symbols.
- attr_accessor :disable_hash_keys_to_symbol
-
- # Array of XML nodes to add a namespace to.
- attr_accessor :nodes_to_namespace
-
- # The namespace for nodes set by nodes_to_namespace.
- attr_accessor :node_namespace
-
- # Shortcut method for translating between XML Strings and Ruby Hashes.
- # Delegates to xml_to_hash in case +source+ is of type String or delegates
- # to hash_to_xml in case +source+ is of type Hash. Returns nil otherwise.
- def [](source, root_node = nil)
- case source
- when String
- xml_to_hash(source, root_node)
- when Hash
- hash_to_xml(source)
- else
- nil
- end
- end
-
- # Yields this class object in case a +block+ was given. Nice way for setting
- # multiple options at once.
- def setup
- yield self if block_given?
- end
-
- # Converts a given +xml+ String into a Ruby Hash. Starts parsing at root
- # node by default. The optional +root_node+ parameter can be used to specify
- # a custom root node to start parsing at using an XPath (Hpricot search).
- # The root node itself won't be included in the Hash. Converts tag names
- # from CamelCase/lowerCamelCase to snake_case and into Symbols by default.
- #
- # ==== Examples
- #
- # xml = "<apricot><eats>Gorilla</eats></apricot>"
- # ApricotEatsGorilla[xml]
- # # => { :eats => "Gorilla" }
- #
- # xml = "<apricot><eats><lotsOf>Gorillas</lotsOf></eats></apricot>"
- # ApricotEatsGorilla[xml, "//eats"]
- # # => { :lots_of => "Gorillas" }
- def xml_to_hash(xml, root_node = nil)
- doc = Hpricot.XML remove_whitespace(xml)
- root = root_node ? doc.search(root_node) : doc.root
-
- return nil if root.nil?
- return xml_node_to_hash(root) unless root.respond_to? :each
-
- if root.size == 1
- return root.first.children.to_s if root.first.children.first.kind_of?(Hpricot::Text)
- xml_node_to_hash(root.first)
- else
- root.map do |node|
- if node.children.first.kind_of?(Hpricot::Text)
- node.children.to_s
- else
- xml_node_to_hash(node)
- end
- end
- end
- end
-
- # Converts a given Ruby Hash into an XML String. Converts Hash keys from
- # snake_case to lowerCamelCase by default.
- #
- # ==== Examples
- #
- # hash = { :apricot => { :eats => "Gorilla" } }
- # ApricotEatsGorilla[hash]
- # # => "<apricot><eats>Gorilla</eats></apricot>"
- #
- # hash = { :apricot => { :eats => [ "Gorillas", "Snakes" ] } }
- # ApricotEatsGorilla[hash]
- # # => "<apricot><eats>Gorillas</eats><eats>Snakes</eats></apricot>"
- def hash_to_xml(hash)
- nested_data_to_xml(hash.keys.first, hash.values.first)
- end
-
- # Builds a SOAP request envelope and includes the content from a given +block+
- # into the envelope body. Accepts a Hash (namespace => namespace_uri) of
- # additional +namespaces+ to set.
- #
- # ==== Examples
- #
- # ApricotEatsGorilla.soap_envelope { "<authenticate>me</authenticate>" }
- #
- # # => '<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
- # # => <env:Body>
- # # => <authenticate>me</authenticate>
- # # => </env:Body>
- # # => </env:Envelope>'
- #
- # ApricotEatsGorilla.soap_envelope :wsdl => "http://example.com" do
- # "<authenticate>me</authenticate>"
- # end
- #
- # # => '<env:Envelope
- # # => xmlns:wsdl="http://example.com"
- # # => xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
- # # => <env:Body>
- # # => <authenticate>me</authenticate>
- # # => </env:Body>
- # # => </env:Envelope>'
- def soap_envelope(namespaces = {})
- namespaces["env"] = "http://schemas.xmlsoap.org/soap/envelope/"
- tag("env:Envelope", namespaces) do
- tag("env:Body") do
- yield if block_given?
- end
- end
- end
-
- # Converts a given +string+ from CamelCase/lowerCamelCase to snake_case.
- def to_snake_case(string)
- string = string.gsub(/[A-Z]+/, '\1_\0').downcase
- string = string[1, string.length-1] if string[0, 1] == "_"
- string
- end
-
- # Converts a given +string+ from snake_case to lowerCamelCase.
- def to_lower_camel_case(string)
- string.to_s.gsub(/_(.)/) { $1.upcase }
- end
-
- private
-
- # Actual implementation for xml_to_hash. Takes and iterates through a given
- # Hpricot +element+ and returns a Ruby Hash equal to the given content.
- def xml_node_to_hash(element)
- this_node = {}
- element.each_child do |child|
- # hpricot 0.6.1 returns an empty array, while 0.8 returns nil
- if child.children.nil? || child.children.empty?
- key, value = child.name, nil
- elsif child.children.size == 1 && child.children.first.text?
- key, value = child.name, map_to_boolean(child.children.first.to_html)
- else
- key, value = child.name, xml_node_to_hash(child)
- end
-
- key = remove_namespace(key)
- key = to_snake_case(key) unless disable_hash_keys_to_snake_case
- key = key.intern unless disable_hash_keys_to_symbol
- current = this_node[key]
- case current
- when Array
- this_node[key] << value
- when nil
- this_node[key] = value
- else
- this_node[key] = [current.dup, value]
- end
- end
- this_node
- end
-
- # Actual implementation for hash_to_xml. Takes a Hash key +name+ and a
- # value +item+ and returns an XML String equal to the given content.
- def nested_data_to_xml(name, item)
- case item
- when Array
- item.map { |subitem| nested_data_to_xml(name, subitem) }.join
- when Hash
- tag(name) do
- opt_order(item).map { |tag, value|
- case value
- when Array
- value.map { |subitem| nested_data_to_xml(tag, subitem) }.join
- when Hash
- nested_data_to_xml(tag, value)
- else
- tag(tag) { value.to_s } if value.respond_to? :to_s
- end
- }.join
- end
- else
- tag(name) { item.to_s } if item.respond_to? :to_s
- end
- end
-
- # Creates an XML tag. Expects a block for tag content. Defaults to an empty
- # element tag in case no block was supplied.
- def tag(name, attributes = {})
- name = to_lower_camel_case(name) unless disable_tag_names_to_lower_camel_case
- if nodes_to_namespace.kind_of? Array
- name = "#{node_namespace}:#{name}" if node_namespace && nodes_to_namespace.include?(name)
- end
- return "<#{name} />" unless block_given?
-
- attr = opt_order(attributes).map { |k, v| %Q( xmlns:#{k}="#{v}") }.to_s
- body = yield || ""
- "<#{name}#{attr}>" << body << "</#{name}>"
- end
-
- # Removes whitespace between tags of a given +xml+ String.
- def remove_whitespace(xml)
- xml.gsub(/(>)\s*(<)/, '\1\2')
- end
-
- # Removes the namespace from a given XML +tag+.
- def remove_namespace(tag)
- tag.sub(/.+:(.+)/, '\1')
- end
-
- # Checks to see if a given +string+ matches "true" or "false" and converts
- # these values to actual Boolean objects. Returns the original String in
- # case it does not match "true" or "false".
- def map_to_boolean(string)
- return true if string == "true"
- return false if string == "false"
- Iconv.new("iso-8859-1", "utf-8").iconv(string)
- end
-
- # Returns a sorted version of a given +hash+ if sort_keys is enabled.
- def opt_order(hash)
- return hash unless sort_keys
- hash.keys.sort_by { |s| s.to_s }.map { |key| [key, hash[key]] }
- end
-
- end
-end
+require "apricoteatsgorilla"
+require "xml_node"
\ No newline at end of file