smacks-apricoteatsgorilla 0.4.5 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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