lib/apricoteatsgorilla.rb in smacks-apricoteatsgorilla-0.4.1 vs lib/apricoteatsgorilla.rb in smacks-apricoteatsgorilla-0.4.2

- old
+ new

@@ -1,52 +1,17 @@ require "rubygems" require "hpricot" # Apricot eats Gorilla is a SOAP communication helper. # -# It translates between SOAP response messages (XML) and Ruby Hashes and may -# be used to build a SOAP request envelope. It is based on CobraVsMongoose but -# uses Hpricot instead of REXML and doesn't follow the BadgerFish convention. -# -# === xml_to_hash(xml, root_node = nil) -# -# xml = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> -# <soap:Body> -# <ns2:authenticateResponse xmlns:ns2="http://v1_0.ws.example.com/"> -# <return> -# <authValue> -# <token>secret</token> -# <client>example</client> -# </authValue> -# </return> -# </ns2:authenticateResponse> -# </soap:Body> -# </soap:Envelope>' -# -# ApricotEatsGorilla[xml, "//return"] -# # => { :auth_value => { :token => "secret", :client => "example" } } -# -# === hash_to_xml(hash) -# -# hash = { :apricot => { :eats => "Gorilla" } } -# -# ApricotEatsGorilla[hash] -# # => "<apricot><eats>Gorilla</eats></apricot>" -# -# === soap_envelope(namespaces = {}) -# -# 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>' +# 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 optional sorting of Hash keys. + # 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 @@ -57,11 +22,11 @@ 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 in :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. @@ -84,19 +49,20 @@ # 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 via XPath (Hpricot search). - # The root node itself won't be included in the Hash. + # 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. # # ==== Parameters # - # * +xml+ - The XML String to translate into a Ruby Hash. + # * +xml+ - The XML String to translate. # * +root_node+ - Optional. Custom root node to start parsing the given XML. # # ==== Examples # # xml = "<apricot><eats>Gorilla</eats></apricot>" @@ -105,23 +71,33 @@ # # xml = "<apricot><eats><lotsOf>Gorillas</lotsOf></eats></apricot>" # ApricotEatsGorilla[xml, "//eats"] # # => { :lots_of => "Gorillas" } def xml_to_hash(xml, root_node = nil) - xml = clean_xml(xml) - doc = Hpricot.XML(xml) - root = root_node ? doc.at(root_node) : doc.root + doc = Hpricot.XML clean_xml(xml) + root = root_node ? doc.search(root_node) : doc.root return nil if root.nil? + # root is an Hpricot::Elements object + if root.respond_to?(:count) + # root is an Hpricot::Elements object with only one element + return root.entries.map { |e| xml_node_to_hash(e) } if root.count > 1 + root = root.entries.first + if root.children.size == 1 && root.children.first.text? + # root contains text only + return root.children.first.to_s + end + end xml_node_to_hash(root) end - # Converts a given +hash+ into an XML String. + # Converts a given Ruby Hash into an XML String. Converts Hash keys from + # snake_case to lowerCamelCase by default. # # ==== Parameters # - # * +hash+ - The Ruby Hash to translate into an XML String. + # * +hash+ - The Ruby Hash to translate. # # ==== Examples # # hash = { :apricot => { :eats => "Gorilla" } } # ApricotEatsGorilla[hash] @@ -132,17 +108,17 @@ # # => "<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 of +namespaces+ and their - # corresponding URI for specifying custom namespaces. + # 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. # # ==== Parameters # - # * +namespaces+ - A Hash of namespaces and their corresponding URI. + # * +namespaces+ - A Hash of namespaces and their URI. # # ==== Examples # # ApricotEatsGorilla.soap_envelope { "<authenticate>me</authenticate>" } # @@ -189,19 +165,19 @@ # Actual implementation for xml_to_hash. Takes and iterates through a given # Hpricot +element+ and returns a Ruby Hash equal to the given content. # # ==== Parameters # - # * +element+ - The Hpricot element to translate into a Ruby Hash. + # * +element+ - The Hpricot element to translate. 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, booleanize(child.children.first.to_html) + key, value = child.name, to_boolean(child.children.first.to_html) else key, value = child.name, xml_node_to_hash(child) end key = remove_namespace(key) @@ -223,12 +199,12 @@ # 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. # # ==== Parameters # - # * +name+ - A Hash key to translate into an XML String. - # * +item+ - A Hash value to translate into an XML String. + # * +name+ - Root key from Hash to translate. + # * +item+ - Root value from Hash to translate. def nested_data_to_xml(name, item) case item when Array item.map { |subitem| nested_data_to_xml(name, subitem) }.join when Hash @@ -280,18 +256,18 @@ tag.sub!(/.+:(.+)/, '\1') tag 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 + # these values to actual Boolean objects. Returns the original String in # case it does not match "true" or "false". - def booleanize(string) + def to_boolean(string) return true if string == "true" return false if string == "false" string end - # Returns a sorted version of a given +hash+ if :sort_keys was enabled. + # 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 \ No newline at end of file