smacks-apricoteatsgorilla 0.4.5 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,10 +1,8 @@
1
1
  = Apricot eats Gorilla
2
2
 
3
- Apricot eats Gorilla is a SOAP communication helper.
4
-
5
- It translates between SOAP messages (XML) and Ruby Hashes while offering some
6
- helpful methods for working with SOAP webservices. Apricot eats Gorilla was
7
- initially based on CobraVsMongoose but uses Hpricot instead of REXML.
3
+ Apricot eats Gorilla is a SOAP communication helper. It translates between
4
+ SOAP messages (XML) and Ruby Hashes and comes with some additional helpers
5
+ for working with SOAP services.
8
6
 
9
7
  == Install
10
8
 
@@ -14,84 +12,41 @@ initially based on CobraVsMongoose but uses Hpricot instead of REXML.
14
12
 
15
13
  hpricot 0.6.164 (also available for JRuby)
16
14
 
17
- == How to use
18
-
19
- === xml_to_hash(xml, root_node = nil)
20
-
21
- Converts a given XML String into a Ruby Hash. Starts parsing at root node by
22
- default. The optional root_node parameter can be used to specify a custom root
23
- node to start parsing at using an XPath expression (Hpricot search). The root
24
- node itself won't be included in the Hash. Converts tag names from CamelCase/
25
- lowerCamelCase to snake_case and into Symbols by default.
15
+ == Translate an XML String into a Ruby Hash
26
16
 
27
17
  xml = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
28
18
  <soap:Body>
29
19
  <ns2:authenticateResponse xmlns:ns2="http://v1_0.ws.example.com/">
30
20
  <return>
31
- <authValue>
32
- <token>secret</token>
33
- <client>example</client>
34
- </authValue>
21
+ <apricot>
22
+ <eats>Gorilla</eats>
23
+ </apricot>
35
24
  </return>
36
25
  </ns2:authenticateResponse>
37
26
  </soap:Body>
38
27
  </soap:Envelope>'
39
28
 
40
29
  ApricotEatsGorilla[xml, "//return"]
41
- # => { :auth_value => { :token => "secret", :client => "example" } }
42
-
43
- === hash_to_xml(hash)
30
+ # => { :apricot => { :eats => "Gorilla" } }
44
31
 
45
- Converts a given Ruby Hash into an XML String. Converts Hash keys from snake_case
46
- to lowerCamelCase by default.
32
+ == Translate a Ruby Hash into an XML String
47
33
 
48
- hash = { :apricot => { :eats => { :lots_of => "Gorillas" } } }
34
+ hash = { :apricot => { :eats => "Gorilla" } }
49
35
 
50
36
  ApricotEatsGorilla[hash]
51
- # => "<apricot><eats><lotsOf>Gorillas</lotsOf></eats></apricot>"
37
+ # => "<apricot><eats>Gorilla</eats></apricot>"
52
38
 
53
- === soap_envelope(namespaces = {})
39
+ == Build a SOAP request envelope
54
40
 
55
- Builds a SOAP request envelope and includes the content from a given block
56
- into the envelope body. Accepts a Hash (namespace => namespace_uri) of additional
57
- namespaces to set.
58
-
59
- ApricotEatsGorilla.soap_envelope { "<authenticate>me</authenticate>" }
41
+ ApricotEatsGorilla.soap_envelope { "<apricot><eats>Gorilla</eats></apricot>" }
60
42
 
61
43
  # => '<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
62
44
  # => <env:Body>
63
- # => <authenticate>me</authenticate>
45
+ # => <apricot><eats>Gorilla</eats></apricot>
64
46
  # => </env:Body>
65
47
  # => </env:Envelope>'
66
48
 
67
- == Changing defaults
68
-
69
- There are several options for changing the default behavior. Options can be
70
- set using a setup block or by setting one option at a time.
71
-
72
- ApricotEatsGorilla.setup do |s|
73
- s.disable_tag_names_to_lower_camel_case = true
74
- s.disable_hash_keys_to_snake_case = true
75
- s.disable_hash_keys_to_symbol = true
76
- end
77
-
78
- === Disable conversion of tag names to lowerCamelCase
79
-
80
- By default XML tags created by hash_to_xml are converted from snake_case to
81
- lowerCamelCase. Disable by setting disable_tag_names_to_lower_camel_case to true.
82
-
83
- ApricotEatsGorilla.disable_tag_names_to_lower_camel_case = true
84
-
85
- === Disable conversion of Hash keys to snake_case
86
-
87
- By default Hash keys created by xml_to_hash are converted from lowerCamelCase/
88
- CamelCase to snake_case. Disable by setting disable_hash_keys_to_snake_case to true.
89
-
90
- ApricotEatsGorilla.disable_hash_keys_to_snake_case = true
91
-
92
- === Disable conversion of Hash keys to Symbols
93
-
94
- By default Hash keys created by xml_to_hash are converted to Symbols.
95
- Disable by setting disable_hash_keys_to_symbol to true.
49
+ == Read more
96
50
 
97
- ApricotEatsGorilla.disable_hash_keys_to_symbol = true
51
+ For more detailed information, please take a look at the
52
+ {GitHub Wiki}[http://wiki.github.com/smacks/apricoteatsgorilla].
@@ -1,245 +1,4 @@
1
- require "rubygems"
2
- require "iconv"
3
- require "hpricot"
1
+ $:.unshift(File.join(File.dirname(__FILE__), "apricoteatsgorilla"))
4
2
 
5
- # Apricot eats Gorilla is a SOAP communication helper.
6
- #
7
- # It translates between SOAP messages (XML) and Ruby Hashes while offering some
8
- # helpful methods for working with SOAP webservices. Apricot eats Gorilla was
9
- # initially based on CobraVsMongoose but uses Hpricot instead of REXML.
10
- class ApricotEatsGorilla
11
- class << self # Class methods
12
-
13
- # Flag to enable sorting of Hash keys.
14
- attr_accessor :sort_keys
15
-
16
- # Flag to disable conversion of tag names to lowerCamelCase.
17
- attr_accessor :disable_tag_names_to_lower_camel_case
18
-
19
- # Flag to disable conversion of Hash keys to snake_case.
20
- attr_accessor :disable_hash_keys_to_snake_case
21
-
22
- # Flag to disable conversion of Hash keys to Symbols.
23
- attr_accessor :disable_hash_keys_to_symbol
24
-
25
- # Array of XML nodes to add a namespace to.
26
- attr_accessor :nodes_to_namespace
27
-
28
- # The namespace for nodes set by nodes_to_namespace.
29
- attr_accessor :node_namespace
30
-
31
- # Shortcut method for translating between XML Strings and Ruby Hashes.
32
- # Delegates to xml_to_hash in case +source+ is of type String or delegates
33
- # to hash_to_xml in case +source+ is of type Hash. Returns nil otherwise.
34
- def [](source, root_node = nil)
35
- case source
36
- when String
37
- xml_to_hash(source, root_node)
38
- when Hash
39
- hash_to_xml(source)
40
- else
41
- nil
42
- end
43
- end
44
-
45
- # Yields this class object in case a +block+ was given. Nice way for setting
46
- # multiple options at once.
47
- def setup
48
- yield self if block_given?
49
- end
50
-
51
- # Converts a given +xml+ String into a Ruby Hash. Starts parsing at root
52
- # node by default. The optional +root_node+ parameter can be used to specify
53
- # a custom root node to start parsing at using an XPath (Hpricot search).
54
- # The root node itself won't be included in the Hash. Converts tag names
55
- # from CamelCase/lowerCamelCase to snake_case and into Symbols by default.
56
- #
57
- # ==== Examples
58
- #
59
- # xml = "<apricot><eats>Gorilla</eats></apricot>"
60
- # ApricotEatsGorilla[xml]
61
- # # => { :eats => "Gorilla" }
62
- #
63
- # xml = "<apricot><eats><lotsOf>Gorillas</lotsOf></eats></apricot>"
64
- # ApricotEatsGorilla[xml, "//eats"]
65
- # # => { :lots_of => "Gorillas" }
66
- def xml_to_hash(xml, root_node = nil)
67
- doc = Hpricot.XML remove_whitespace(xml)
68
- root = root_node ? doc.search(root_node) : doc.root
69
-
70
- return nil if root.nil?
71
- return xml_node_to_hash(root) unless root.respond_to? :each
72
-
73
- if root.size == 1
74
- return root.first.children.to_s if root.first.children.first.kind_of?(Hpricot::Text)
75
- xml_node_to_hash(root.first)
76
- else
77
- root.map do |node|
78
- if node.children.first.kind_of?(Hpricot::Text)
79
- node.children.to_s
80
- else
81
- xml_node_to_hash(node)
82
- end
83
- end
84
- end
85
- end
86
-
87
- # Converts a given Ruby Hash into an XML String. Converts Hash keys from
88
- # snake_case to lowerCamelCase by default.
89
- #
90
- # ==== Examples
91
- #
92
- # hash = { :apricot => { :eats => "Gorilla" } }
93
- # ApricotEatsGorilla[hash]
94
- # # => "<apricot><eats>Gorilla</eats></apricot>"
95
- #
96
- # hash = { :apricot => { :eats => [ "Gorillas", "Snakes" ] } }
97
- # ApricotEatsGorilla[hash]
98
- # # => "<apricot><eats>Gorillas</eats><eats>Snakes</eats></apricot>"
99
- def hash_to_xml(hash)
100
- nested_data_to_xml(hash.keys.first, hash.values.first)
101
- end
102
-
103
- # Builds a SOAP request envelope and includes the content from a given +block+
104
- # into the envelope body. Accepts a Hash (namespace => namespace_uri) of
105
- # additional +namespaces+ to set.
106
- #
107
- # ==== Examples
108
- #
109
- # ApricotEatsGorilla.soap_envelope { "<authenticate>me</authenticate>" }
110
- #
111
- # # => '<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
112
- # # => <env:Body>
113
- # # => <authenticate>me</authenticate>
114
- # # => </env:Body>
115
- # # => </env:Envelope>'
116
- #
117
- # ApricotEatsGorilla.soap_envelope :wsdl => "http://example.com" do
118
- # "<authenticate>me</authenticate>"
119
- # end
120
- #
121
- # # => '<env:Envelope
122
- # # => xmlns:wsdl="http://example.com"
123
- # # => xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
124
- # # => <env:Body>
125
- # # => <authenticate>me</authenticate>
126
- # # => </env:Body>
127
- # # => </env:Envelope>'
128
- def soap_envelope(namespaces = {})
129
- namespaces["env"] = "http://schemas.xmlsoap.org/soap/envelope/"
130
- tag("env:Envelope", namespaces) do
131
- tag("env:Body") do
132
- yield if block_given?
133
- end
134
- end
135
- end
136
-
137
- # Converts a given +string+ from CamelCase/lowerCamelCase to snake_case.
138
- def to_snake_case(string)
139
- string = string.gsub(/[A-Z]+/, '\1_\0').downcase
140
- string = string[1, string.length-1] if string[0, 1] == "_"
141
- string
142
- end
143
-
144
- # Converts a given +string+ from snake_case to lowerCamelCase.
145
- def to_lower_camel_case(string)
146
- string.to_s.gsub(/_(.)/) { $1.upcase }
147
- end
148
-
149
- private
150
-
151
- # Actual implementation for xml_to_hash. Takes and iterates through a given
152
- # Hpricot +element+ and returns a Ruby Hash equal to the given content.
153
- def xml_node_to_hash(element)
154
- this_node = {}
155
- element.each_child do |child|
156
- # hpricot 0.6.1 returns an empty array, while 0.8 returns nil
157
- if child.children.nil? || child.children.empty?
158
- key, value = child.name, nil
159
- elsif child.children.size == 1 && child.children.first.text?
160
- key, value = child.name, map_to_boolean(child.children.first.to_html)
161
- else
162
- key, value = child.name, xml_node_to_hash(child)
163
- end
164
-
165
- key = remove_namespace(key)
166
- key = to_snake_case(key) unless disable_hash_keys_to_snake_case
167
- key = key.intern unless disable_hash_keys_to_symbol
168
- current = this_node[key]
169
- case current
170
- when Array
171
- this_node[key] << value
172
- when nil
173
- this_node[key] = value
174
- else
175
- this_node[key] = [current.dup, value]
176
- end
177
- end
178
- this_node
179
- end
180
-
181
- # Actual implementation for hash_to_xml. Takes a Hash key +name+ and a
182
- # value +item+ and returns an XML String equal to the given content.
183
- def nested_data_to_xml(name, item)
184
- case item
185
- when Array
186
- item.map { |subitem| nested_data_to_xml(name, subitem) }.join
187
- when Hash
188
- tag(name) do
189
- opt_order(item).map { |tag, value|
190
- case value
191
- when Array
192
- value.map { |subitem| nested_data_to_xml(tag, subitem) }.join
193
- when Hash
194
- nested_data_to_xml(tag, value)
195
- else
196
- tag(tag) { value.to_s } if value.respond_to? :to_s
197
- end
198
- }.join
199
- end
200
- else
201
- tag(name) { item.to_s } if item.respond_to? :to_s
202
- end
203
- end
204
-
205
- # Creates an XML tag. Expects a block for tag content. Defaults to an empty
206
- # element tag in case no block was supplied.
207
- def tag(name, attributes = {})
208
- name = to_lower_camel_case(name) unless disable_tag_names_to_lower_camel_case
209
- if nodes_to_namespace.kind_of? Array
210
- name = "#{node_namespace}:#{name}" if node_namespace && nodes_to_namespace.include?(name)
211
- end
212
- return "<#{name} />" unless block_given?
213
-
214
- attr = opt_order(attributes).map { |k, v| %Q( xmlns:#{k}="#{v}") }.to_s
215
- body = yield || ""
216
- "<#{name}#{attr}>" << body << "</#{name}>"
217
- end
218
-
219
- # Removes whitespace between tags of a given +xml+ String.
220
- def remove_whitespace(xml)
221
- xml.gsub(/(>)\s*(<)/, '\1\2')
222
- end
223
-
224
- # Removes the namespace from a given XML +tag+.
225
- def remove_namespace(tag)
226
- tag.sub(/.+:(.+)/, '\1')
227
- end
228
-
229
- # Checks to see if a given +string+ matches "true" or "false" and converts
230
- # these values to actual Boolean objects. Returns the original String in
231
- # case it does not match "true" or "false".
232
- def map_to_boolean(string)
233
- return true if string == "true"
234
- return false if string == "false"
235
- Iconv.new("iso-8859-1", "utf-8").iconv(string)
236
- end
237
-
238
- # Returns a sorted version of a given +hash+ if sort_keys is enabled.
239
- def opt_order(hash)
240
- return hash unless sort_keys
241
- hash.keys.sort_by { |s| s.to_s }.map { |key| [key, hash[key]] }
242
- end
243
-
244
- end
245
- end
3
+ require "apricoteatsgorilla"
4
+ require "xml_node"
@@ -0,0 +1,222 @@
1
+ require "rubygems"
2
+ require "hpricot"
3
+ require "iconv"
4
+
5
+ # == Apricot eats Gorilla
6
+ #
7
+ # Apricot eats Gorilla is a SOAP communication helper. It translates between
8
+ # SOAP messages (XML) and Ruby Hashes and comes with some additional helpers
9
+ # for working with SOAP services.
10
+ class ApricotEatsGorilla
11
+ class << self
12
+
13
+ # Flag to enable sorting of Hash keys.
14
+ attr_accessor :sort_keys
15
+
16
+ # Flag to disable conversion of XML tags names to lowerCamelCase.
17
+ attr_accessor :disable_tag_names_to_lower_camel_case
18
+
19
+ # Flag to disable conversion of Hash keys to snake_case.
20
+ attr_accessor :disable_hash_keys_to_snake_case
21
+
22
+ # Flag to disable conversion of Hash keys to Symbols.
23
+ attr_accessor :disable_hash_keys_to_symbols
24
+
25
+ # Hash of namespaces and XML nodes to apply these namespaces to.
26
+ attr_accessor :nodes_to_namespace
27
+
28
+ # Shortcut method for translating between XML Strings and Ruby Hashes.
29
+ # Delegates to +xml_to_hash+ in case +source+ is a String or delegates
30
+ # to +hash_to_xml+ in case +source+ is a Hash. Returns nil otherwise.
31
+ def [](source, root_node = nil)
32
+ case source
33
+ when String
34
+ xml_to_hash(source, root_node)
35
+ when Hash
36
+ hash_to_xml(source)
37
+ else
38
+ nil
39
+ end
40
+ end
41
+
42
+ # Yields this class in case a +block+ was given.
43
+ def setup
44
+ yield self if block_given?
45
+ end
46
+
47
+ # Translates a given +xml+ String into a Ruby Hash.
48
+ #
49
+ # Starts parsing at the XML root node by default. Accepts an optional
50
+ # +root_node+ parameter for defining a custom root node to start parsing
51
+ # at using an XPath (Hpricot search).
52
+ #
53
+ # The root node itself won't be included in the Hash.
54
+ #
55
+ # ==== Examples
56
+ #
57
+ # xml = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
58
+ # <soap:Body>
59
+ # <ns2:authenticateResponse xmlns:ns2="http://v1_0.ws.example.com/">
60
+ # <return>
61
+ # <apricot>
62
+ # <eats>Gorilla</eats>
63
+ # </apricot>
64
+ # </return>
65
+ # </ns2:authenticateResponse>
66
+ # </soap:Body>
67
+ # </soap:Envelope>'
68
+ #
69
+ # ApricotEatsGorilla.xml_to_hash(xml, "//return")
70
+ # # => { :apricot => { :eats => "Gorilla" } }
71
+ def xml_to_hash(xml, root_node = nil)
72
+ doc = Hpricot.XML remove_whitespace(xml)
73
+ root = root_node ? doc.search(root_node) : doc.root
74
+
75
+ return nil if root.nil?
76
+ return xml_node_to_hash(root) unless root.respond_to? :each
77
+
78
+ if root.size == 1
79
+ if root.first.children.first.kind_of?(Hpricot::Text)
80
+ map_xml_value(root.first.children.to_s)
81
+ else
82
+ xml_node_to_hash(root.first)
83
+ end
84
+ else
85
+ root.map do |node|
86
+ if node.children.first.kind_of?(Hpricot::Text)
87
+ map_xml_value(node.children.to_s)
88
+ else
89
+ xml_node_to_hash(node)
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ # Translates a given Ruby +hash+ into an XML String.
96
+ #
97
+ # ==== Examples
98
+ #
99
+ # hash = { :apricot => { :eats => "Gorilla" } }
100
+ #
101
+ # ApricotEatsGorilla.hash_to_xml(hash)
102
+ # # => "<apricot><eats>Gorilla</eats></apricot>"
103
+ def hash_to_xml(hash)
104
+ nested_data_to_xml(hash.keys.first, hash.values.first)
105
+ end
106
+
107
+ # Builds a SOAP request envelope and includes the content from a given
108
+ # +block+ into the envelope body. Accepts a Hash of additional +namespaces+
109
+ # to set.
110
+ #
111
+ # ==== Examples
112
+ #
113
+ # ApricotEatsGorilla.soap_envelope do
114
+ # "<apricot><eats>Gorilla</eats></apricot>"
115
+ # end
116
+ #
117
+ # # => '<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
118
+ # # => <env:Body>
119
+ # # => <apricot><eats>Gorilla</eats></apricot>
120
+ # # => </env:Body>
121
+ # # => </env:Envelope>'
122
+ def soap_envelope(namespaces = {})
123
+ namespaces[:env] = "http://schemas.xmlsoap.org/soap/envelope/"
124
+
125
+ xml_node("env:Envelope", namespaces) do
126
+ xml_node("env:Body") { yield if block_given? }
127
+ end
128
+ end
129
+
130
+ private
131
+
132
+ # Iterates through an expected Hpricot +element+ and returns a Ruby Hash
133
+ # equal to the XML content of the given element.
134
+ def xml_node_to_hash(element)
135
+ hash = {}
136
+ element.each_child do |child|
137
+ key = XMLNode.new(child.name)
138
+ key.strip_namespace!
139
+ key.to_snake_case! unless disable_hash_keys_to_snake_case
140
+ key = disable_hash_keys_to_symbols ? key.to_s : key.to_sym
141
+
142
+ # hpricot 0.6.1 returns an empty array, while 0.8 returns nil
143
+ if child.children.nil? || child.children.empty?
144
+ value = nil
145
+ elsif child.children.size == 1 && child.children.first.text?
146
+ value = map_xml_value(child.children.first.to_html)
147
+ else
148
+ value = xml_node_to_hash(child)
149
+ end
150
+
151
+ case hash[key]
152
+ when Array
153
+ hash[key] << value
154
+ when nil
155
+ hash[key] = value
156
+ else
157
+ hash[key] = [hash[key].dup, value]
158
+ end
159
+ end
160
+ hash
161
+ end
162
+
163
+ # Expects a Hash +key+ and a Hash +value+. Iterates through the given Hash
164
+ # +value+ and returns an XML String of the given Hash structure.
165
+ def nested_data_to_xml(key, value)
166
+ case value
167
+ when Array
168
+ value.map { |subitem| nested_data_to_xml(key, subitem) }.join
169
+ when Hash
170
+ xml_node(key) do
171
+ sort_hash_keys(value).map do |subkey, subvalue|
172
+ case subvalue
173
+ when Array
174
+ subvalue.map { |subitem| nested_data_to_xml(subkey, subitem) }.join
175
+ when Hash
176
+ nested_data_to_xml(subkey, subvalue)
177
+ else
178
+ xml_node(subkey) { subvalue.to_s } if subvalue.respond_to?(:to_s)
179
+ end
180
+ end.join
181
+ end
182
+ else
183
+ xml_node(key) { value.to_s } if value.respond_to?(:to_s)
184
+ end
185
+ end
186
+
187
+ # Returns an XML tag with a given +name+. Accepts a +block+ for tag content.
188
+ # Defaults to returning an empty element tag in case no block was given.
189
+ # Also accepts a Hash of +attributes+ to be added to the XML tag.
190
+ def xml_node(name, attributes = {})
191
+ node = XMLNode.new(name.to_s)
192
+
193
+ node.to_lower_camel_case! unless disable_tag_names_to_lower_camel_case
194
+ node.namespace_from_hash!(nodes_to_namespace)
195
+ node.attributes = sort_hash_keys(attributes)
196
+ node.body = yield if block_given?
197
+
198
+ node.to_tag
199
+ end
200
+
201
+ # Removes whitespace between tags from a given +xml+ String.
202
+ def remove_whitespace(xml)
203
+ xml.gsub(/(>)\s*(<)/, '\1\2')
204
+ end
205
+
206
+ # Maps an XML value to a more natural Ruby object. Converts String values
207
+ # of "true" and "false" to TrueClass and FalseClass. Converts other String
208
+ # values from "iso-8859-1" to "utf-8".
209
+ def map_xml_value(value)
210
+ return true if value == "true"
211
+ return false if value == "false"
212
+ Iconv.new("iso-8859-1", "utf-8").iconv(value)
213
+ end
214
+
215
+ # Returns a sorted version of a given +hash+ if +sort_keys+ is enabled.
216
+ def sort_hash_keys(hash)
217
+ return hash unless sort_keys
218
+ hash.keys.sort_by { |key| key.to_s }.map { |key| [ key, hash[key] ] }
219
+ end
220
+
221
+ end
222
+ end
@@ -0,0 +1,75 @@
1
+ # == XMLNode
2
+ #
3
+ # Representation of an XML node.
4
+ class XMLNode < String
5
+
6
+ # Hash of attributes.
7
+ attr_writer :attributes
8
+
9
+ # Body content.
10
+ attr_writer :body
11
+
12
+ # Strips the namespace from this node.
13
+ def strip_namespace!
14
+ sub!(/.+:(.+)/, '\1')
15
+ end
16
+
17
+ # Converts the name of this node to snake_case.
18
+ def to_snake_case!
19
+ self.gsub!(/[A-Z]/, '_\0')
20
+ self.gsub!(/^_/, '')
21
+ self.downcase!
22
+ end
23
+
24
+ # Converts the name of this node to lowerCamelCase.
25
+ def to_lower_camel_case!
26
+ self.gsub!(/_(.)/) { $1.upcase }
27
+ end
28
+
29
+ # Checks if the name of this node is included in a given Hash of +namespaces+
30
+ # and sets the namespace for this node in case it was found in the Hash.
31
+ def namespace_from_hash!(namespaces)
32
+ return if namespaces.nil? || namespaces.empty?
33
+
34
+ namespaces.each do |namespace, nodes|
35
+ @namespace = namespace if self_included?(nodes)
36
+ end
37
+ end
38
+
39
+ # Returns this node as a complete XML tag including a +namespace+, +attributes+
40
+ # and a +body+ in case these values were supplied.
41
+ def to_tag
42
+ return "<#{namespace}#{self}#{attributes} />" unless @body
43
+ "<#{namespace}#{self}#{attributes}>#{body}</#{namespace}#{self}>"
44
+ end
45
+
46
+ private
47
+
48
+ # Returns +true+ if self as a String or a Symbol is included in a given
49
+ # +array+. Returns +false+ otherwise.
50
+ def self_included?(array)
51
+ array.include?(self.to_s) || array.include?(self.to_sym)
52
+ end
53
+
54
+ # Returns the namespace of this node. Defaults to an empty String in case
55
+ # no namespace was defined.
56
+ def namespace
57
+ return "" if @namespace.nil?
58
+ "#{@namespace}:"
59
+ end
60
+
61
+ # Returns the attributes of this node. Defaults to an empty String in case
62
+ # no attributes were defined.
63
+ def attributes
64
+ return "" if @attributes.nil?
65
+ @attributes.map { |key, value| %Q( xmlns:#{key}="#{value}") }
66
+ end
67
+
68
+ # Returns the body of this node. Defaults to an empty String in case no body
69
+ # was defined.
70
+ def body
71
+ return "" if @body.nil?
72
+ @body
73
+ end
74
+
75
+ end
@@ -8,14 +8,15 @@ class TestHashToXml < Test::Unit::TestCase
8
8
  s.sort_keys = true
9
9
  s.disable_tag_names_to_lower_camel_case = false
10
10
  s.disable_hash_keys_to_snake_case = false
11
- s.disable_hash_keys_to_symbol = false
11
+ s.disable_hash_keys_to_symbols = false
12
+ s.nodes_to_namespace = nil
12
13
  end
13
14
  end
14
15
 
15
- context "with a Hash consisting of a single key-value-pair" do
16
+ context "with a Hash containing only a single key-value-pair" do
16
17
  should "return an XML String containing one node and a value" do
17
- hash = { "apricot" => "eats gorilla" }
18
- expected = "<apricot>eats gorilla</apricot>"
18
+ hash = { "apricot" => "eats Gorilla" }
19
+ expected = "<apricot>eats Gorilla</apricot>"
19
20
 
20
21
  result = ApricotEatsGorilla.hash_to_xml(hash)
21
22
  assert_equal expected, result
@@ -103,6 +104,18 @@ class TestHashToXml < Test::Unit::TestCase
103
104
  assert_equal expected, result
104
105
  end
105
106
  end
107
+
108
+ context "with some Hash and nodes to namespace" do
109
+ setup { ApricotEatsGorilla.nodes_to_namespace = { :wsdl => [ :apricot ] } }
110
+
111
+ should "apply the defined namespaces" do
112
+ hash = { :apricot => { :eats => "Gorilla" } }
113
+ expected = "<wsdl:apricot><eats>Gorilla</eats></wsdl:apricot>"
114
+
115
+ result = ApricotEatsGorilla.hash_to_xml(hash)
116
+ assert_equal expected, result
117
+ end
118
+ end
106
119
  end
107
120
 
108
121
  end
@@ -8,7 +8,8 @@ class TestShortcutMethod < Test::Unit::TestCase
8
8
  s.sort_keys = true
9
9
  s.disable_tag_names_to_lower_camel_case = false
10
10
  s.disable_hash_keys_to_snake_case = false
11
- s.disable_hash_keys_to_symbol = false
11
+ s.disable_hash_keys_to_symbols = false
12
+ s.nodes_to_namespace = nil
12
13
  end
13
14
  end
14
15
 
@@ -6,9 +6,9 @@ class TestSoapEnvelope < Test::Unit::TestCase
6
6
  setup { ApricotEatsGorilla.sort_keys = true }
7
7
 
8
8
  context "without parameter and block" do
9
- should "returns a SOAP envelope without body content" do
9
+ should "returns a SOAP envelope with an empty element body tag" do
10
10
  expected = '<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">' <<
11
- '<env:Body></env:Body></env:Envelope>'
11
+ '<env:Body /></env:Envelope>'
12
12
 
13
13
  result = ApricotEatsGorilla.soap_envelope
14
14
  assert_equal expected, result
@@ -16,7 +16,7 @@ class TestSoapEnvelope < Test::Unit::TestCase
16
16
  end
17
17
 
18
18
  context "with a Hash containing a custom namespace and a block" do
19
- should "returns a SOAP envelope with custom namespace and body content" do
19
+ should "returns a SOAP envelope with a custom namespace and body content" do
20
20
  expected = '<env:Envelope ' <<
21
21
  'xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" ' <<
22
22
  'xmlns:wsdl="http://example.com">' <<
@@ -0,0 +1,87 @@
1
+ require File.join(File.dirname(__FILE__), "..", "helper")
2
+
3
+ class TestXMLNode < Test::Unit::TestCase
4
+
5
+ context "strip_namespace!" do
6
+ should "strip the namespace from the XMLNode" do
7
+ node = XMLNode.new("wsdl:apricot")
8
+ node.strip_namespace!
9
+
10
+ assert_equal "apricot", node.to_s
11
+ end
12
+ end
13
+
14
+ context "to_snake_case!" do
15
+ should "convert the XMLNode from CamelCase to snake_case" do
16
+ node = XMLNode.new("ApricotEatsGorilla")
17
+ node.to_snake_case!
18
+
19
+ assert_equal "apricot_eats_gorilla", node.to_s
20
+ end
21
+
22
+ should "convert the XMLNode from lowerCamelCase to snake_case" do
23
+ node = XMLNode.new("apricotEatsGorilla")
24
+ node.to_snake_case!
25
+
26
+ assert_equal "apricot_eats_gorilla", node.to_s
27
+ end
28
+ end
29
+
30
+ context "namespace_from_hash!" do
31
+ context "with a Hash containing the name of the XMLNode" do
32
+ should "set the namespace of the XMLNode" do
33
+ node = XMLNode.new("apricot")
34
+ node.namespace_from_hash!(:wsdl => [ :apricot ])
35
+
36
+ assert_equal "apricot", node.to_s
37
+ assert_equal "<wsdl:apricot />", node.to_tag
38
+ end
39
+ end
40
+
41
+ context "with a Hash that does not contain the name of the XMLNode" do
42
+ should "not set the namespace of the XMLNode" do
43
+ node = XMLNode.new("apricot")
44
+ node.namespace_from_hash!(:wsdl => [ :some_key ])
45
+
46
+ assert_equal "<apricot />", node.to_tag
47
+ end
48
+ end
49
+ end
50
+
51
+ context "to_tag" do
52
+ context "with a simple XMLNode" do
53
+ should "return an empty element tag" do
54
+ node = XMLNode.new("apricot")
55
+ assert_equal "<apricot />", node.to_tag
56
+ end
57
+ end
58
+
59
+ context "with an XMLNode containing a namespace" do
60
+ should "return a namespaced empty element tag" do
61
+ node = XMLNode.new("apricot")
62
+ node.namespace_from_hash!(:wsdl => [ :apricot ])
63
+
64
+ assert_equal "<wsdl:apricot />", node.to_tag
65
+ end
66
+ end
67
+
68
+ context "with an XMLNode containing an attribute" do
69
+ should "return an empty element tag with an xmlns attribute" do
70
+ node = XMLNode.new("apricot")
71
+ node.attributes = { :wsdl => "http://example.com" }
72
+
73
+ assert_equal '<apricot xmlns:wsdl="http://example.com" />', node.to_tag
74
+ end
75
+ end
76
+
77
+ context "with an XMLNode containing a body" do
78
+ should "return an element with a body" do
79
+ node = XMLNode.new("apricot")
80
+ node.body = "eats Gorilla"
81
+
82
+ assert_equal '<apricot>eats Gorilla</apricot>', node.to_tag
83
+ end
84
+ end
85
+ end
86
+
87
+ end
@@ -8,7 +8,8 @@ class TestXmlToHash < Test::Unit::TestCase
8
8
  s.sort_keys = true
9
9
  s.disable_tag_names_to_lower_camel_case = false
10
10
  s.disable_hash_keys_to_snake_case = false
11
- s.disable_hash_keys_to_symbol = false
11
+ s.disable_hash_keys_to_symbols = false
12
+ s.nodes_to_namespace = nil
12
13
  end
13
14
  end
14
15
 
@@ -33,6 +34,16 @@ class TestXmlToHash < Test::Unit::TestCase
33
34
  end
34
35
  end
35
36
 
37
+ context "with XML containing namespaced nodes" do
38
+ should "remove namespaces from nodes" do
39
+ xml = "<return><wsdl:apricot><eats>Gorilla</eats></wsdl:apricot></return>"
40
+ expected = { :apricot => { :eats => "Gorilla" } }
41
+
42
+ result = ApricotEatsGorilla.xml_to_hash(xml)
43
+ assert_equal expected, result
44
+ end
45
+ end
46
+
36
47
  context "with XML containing 'true' and 'false' Strings" do
37
48
  should "convert these Strings into actual Boolean objects" do
38
49
  xml = "<root><yes>true</yes><no>false</no><text>something</text></root>"
@@ -135,7 +146,7 @@ class TestXmlToHash < Test::Unit::TestCase
135
146
  end
136
147
 
137
148
  context "and converting Hash keys to Symbols turned off" do
138
- setup { ApricotEatsGorilla.disable_hash_keys_to_symbol = true }
149
+ setup { ApricotEatsGorilla.disable_hash_keys_to_symbols = true }
139
150
 
140
151
  should "not convert Hash keys to Symbols" do
141
152
  xml = "<contact><name>Jungle Julia</name><address/></contact>"
@@ -1,5 +1,7 @@
1
1
  $:.unshift(File.join(File.dirname(__FILE__), "apricoteatsgorilla"))
2
+
2
3
  require "test_shortcut_method"
3
4
  require "test_xml_to_hash"
4
5
  require "test_hash_to_xml"
5
- require "test_soap_envelope"
6
+ require "test_soap_envelope"
7
+ require "test_xml_node"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smacks-apricoteatsgorilla
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.4.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Harrington
@@ -22,7 +22,7 @@ dependencies:
22
22
  - !ruby/object:Gem::Version
23
23
  version: 0.6.164
24
24
  version:
25
- description: Apricot eats Gorilla is a SOAP communication helper.
25
+ description: SOAP communication helper.
26
26
  email:
27
27
  executables: []
28
28
 
@@ -33,6 +33,8 @@ extra_rdoc_files:
33
33
  files:
34
34
  - README.rdoc
35
35
  - lib/apricoteatsgorilla.rb
36
+ - lib/apricoteatsgorilla/apricoteatsgorilla.rb
37
+ - lib/apricoteatsgorilla/xml_node.rb
36
38
  has_rdoc: true
37
39
  homepage: http://github.com/smacks/apricoteatsgorilla
38
40
  post_install_message:
@@ -59,7 +61,7 @@ rubyforge_project:
59
61
  rubygems_version: 1.2.0
60
62
  signing_key:
61
63
  specification_version: 2
62
- summary: Apricot eats Gorilla is a SOAP communication helper.
64
+ summary: SOAP communication helper.
63
65
  test_files:
64
66
  - test/test_apricoteatsgorilla.rb
65
67
  - test/helper.rb
@@ -67,3 +69,4 @@ test_files:
67
69
  - test/apricoteatsgorilla/test_xml_to_hash.rb
68
70
  - test/apricoteatsgorilla/test_shortcut_method.rb
69
71
  - test/apricoteatsgorilla/test_soap_envelope.rb
72
+ - test/apricoteatsgorilla/test_xml_node.rb