smacks-apricoteatsgorilla 0.5.0 → 0.5.1
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/.gitignore +3 -0
- data/README.rdoc +2 -1
- data/Rakefile +24 -0
- data/VERSION +1 -0
- data/apricoteatsgorilla.gemspec +62 -0
- data/lib/apricoteatsgorilla.rb +3 -0
- data/lib/apricoteatsgorilla/apricoteatsgorilla.rb +239 -0
- data/lib/apricoteatsgorilla/xml_node.rb +72 -0
- data/spec/apricoteatsgorilla/apricoteatsgorilla_hash_to_xml_spec.rb +67 -0
- data/spec/apricoteatsgorilla/apricoteatsgorilla_spec.rb +56 -0
- data/spec/apricoteatsgorilla/apricoteatsgorilla_xml_to_hash_spec.rb +78 -0
- data/spec/apricoteatsgorilla/xml_node_spec.rb +80 -0
- data/spec/spec_helper.rb +20 -0
- metadata +23 -6
data/.gitignore
ADDED
data/README.rdoc
CHANGED
@@ -11,7 +11,8 @@ for working with SOAP services.
|
|
11
11
|
== Dependencies
|
12
12
|
|
13
13
|
hpricot 0.8.241 (the latest JRuby-compatible version)
|
14
|
-
|
14
|
+
|
15
|
+
Also available at: {GitHub Downloads}[http://github.com/smacks/apricoteatsgorilla/downloads]
|
15
16
|
|
16
17
|
== Translate an XML String into a Ruby Hash
|
17
18
|
|
data/Rakefile
CHANGED
@@ -17,3 +17,27 @@ Rake::RDocTask.new do |rdoc|
|
|
17
17
|
rdoc.rdoc_files.include("README.rdoc", "lib/**/*.rb")
|
18
18
|
rdoc.options = ["--line-numbers", "--inline-source"]
|
19
19
|
end
|
20
|
+
|
21
|
+
begin
|
22
|
+
require "jeweler"
|
23
|
+
Jeweler::Tasks.new do |spec|
|
24
|
+
spec.name = "apricoteatsgorilla"
|
25
|
+
spec.author = "Daniel Harrington"
|
26
|
+
spec.email = "me@d-harrington.com"
|
27
|
+
spec.homepage = "http://github.com/smacks/apricoteatsgorilla"
|
28
|
+
spec.summary = "SOAP communication helper."
|
29
|
+
spec.description = spec.summary
|
30
|
+
|
31
|
+
spec.rdoc_options += [
|
32
|
+
"--title", "Apricot eats Gorilla",
|
33
|
+
"--main", "README.rdoc",
|
34
|
+
"--line-numbers",
|
35
|
+
"--inline-source"
|
36
|
+
]
|
37
|
+
|
38
|
+
spec.add_runtime_dependency("hpricot", "0.8.241")
|
39
|
+
spec.add_development_dependency("rspec", ">= 1.2.8")
|
40
|
+
end
|
41
|
+
rescue LoadError
|
42
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
43
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.5.1
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{apricoteatsgorilla}
|
8
|
+
s.version = "0.5.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Daniel Harrington"]
|
12
|
+
s.date = %q{2009-08-29}
|
13
|
+
s.description = %q{SOAP communication helper.}
|
14
|
+
s.email = %q{me@d-harrington.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
".gitignore",
|
20
|
+
"README.rdoc",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION",
|
23
|
+
"apricoteatsgorilla.gemspec",
|
24
|
+
"lib/apricoteatsgorilla.rb",
|
25
|
+
"lib/apricoteatsgorilla/apricoteatsgorilla.rb",
|
26
|
+
"lib/apricoteatsgorilla/xml_node.rb",
|
27
|
+
"spec/apricoteatsgorilla/apricoteatsgorilla_hash_to_xml_spec.rb",
|
28
|
+
"spec/apricoteatsgorilla/apricoteatsgorilla_spec.rb",
|
29
|
+
"spec/apricoteatsgorilla/apricoteatsgorilla_xml_to_hash_spec.rb",
|
30
|
+
"spec/apricoteatsgorilla/xml_node_spec.rb",
|
31
|
+
"spec/spec_helper.rb"
|
32
|
+
]
|
33
|
+
s.has_rdoc = true
|
34
|
+
s.homepage = %q{http://github.com/smacks/apricoteatsgorilla}
|
35
|
+
s.rdoc_options = ["--charset=UTF-8", "--title", "Apricot eats Gorilla", "--main", "README.rdoc", "--line-numbers", "--inline-source"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = %q{1.3.1}
|
38
|
+
s.summary = %q{SOAP communication helper.}
|
39
|
+
s.test_files = [
|
40
|
+
"spec/apricoteatsgorilla/apricoteatsgorilla_hash_to_xml_spec.rb",
|
41
|
+
"spec/apricoteatsgorilla/apricoteatsgorilla_spec.rb",
|
42
|
+
"spec/apricoteatsgorilla/apricoteatsgorilla_xml_to_hash_spec.rb",
|
43
|
+
"spec/apricoteatsgorilla/xml_node_spec.rb",
|
44
|
+
"spec/spec_helper.rb"
|
45
|
+
]
|
46
|
+
|
47
|
+
if s.respond_to? :specification_version then
|
48
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
49
|
+
s.specification_version = 2
|
50
|
+
|
51
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
52
|
+
s.add_runtime_dependency(%q<hpricot>, ["= 0.8.241"])
|
53
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.8"])
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<hpricot>, ["= 0.8.241"])
|
56
|
+
s.add_dependency(%q<rspec>, [">= 1.2.8"])
|
57
|
+
end
|
58
|
+
else
|
59
|
+
s.add_dependency(%q<hpricot>, ["= 0.8.241"])
|
60
|
+
s.add_dependency(%q<rspec>, [">= 1.2.8"])
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
%w(rubygems hpricot).each do |gem|
|
2
|
+
require gem
|
3
|
+
end
|
4
|
+
|
5
|
+
# == ApricotEatsGorilla
|
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 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-Expression (Hpricot search).
|
52
|
+
#
|
53
|
+
# Notice that the root node itself won't be included in the Hash.
|
54
|
+
#
|
55
|
+
# ==== Example
|
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
|
+
if !root.respond_to? :each
|
77
|
+
xml_node_to_hash(root)
|
78
|
+
elsif root.size == 1
|
79
|
+
single_xml_root_node_to_hash(root)
|
80
|
+
else
|
81
|
+
multiple_xml_root_nodes_to_hash(root)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Translates a given Ruby +hash+ into an XML String.
|
86
|
+
#
|
87
|
+
# ==== Example
|
88
|
+
#
|
89
|
+
# hash = { :apricot => { :eats => "Gorilla" } }
|
90
|
+
#
|
91
|
+
# ApricotEatsGorilla.hash_to_xml(hash)
|
92
|
+
# # => "<apricot><eats>Gorilla</eats></apricot>"
|
93
|
+
def hash_to_xml(hash)
|
94
|
+
nested_data_to_xml(hash.keys.first, hash.values.first)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Builds a SOAP request envelope and includes the content from a given
|
98
|
+
# +block+ into the envelope body. Accepts a Hash of +namespaces+ to set.
|
99
|
+
#
|
100
|
+
# ==== Example
|
101
|
+
#
|
102
|
+
# ApricotEatsGorilla.soap_envelope do
|
103
|
+
# "<apricot><eats>Gorilla</eats></apricot>"
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# # => '<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
|
107
|
+
# # => <env:Body>
|
108
|
+
# # => <apricot><eats>Gorilla</eats></apricot>
|
109
|
+
# # => </env:Body>
|
110
|
+
# # => </env:Envelope>'
|
111
|
+
def soap_envelope(namespaces = {})
|
112
|
+
namespaces[:env] = "http://schemas.xmlsoap.org/soap/envelope/"
|
113
|
+
|
114
|
+
xml_node("env:Envelope", namespaces) do
|
115
|
+
xml_node("env:Body") { yield if block_given? }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
# Translates a single XML root node to a Ruby Hash.
|
122
|
+
def single_xml_root_node_to_hash(root)
|
123
|
+
if root.first.children.first.kind_of? Hpricot::Text
|
124
|
+
map_xml_value(root.first.children.to_s)
|
125
|
+
else
|
126
|
+
xml_node_to_hash(root.first)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Translates multiple XML root nodes to a Ruby Hash.
|
131
|
+
def multiple_xml_root_nodes_to_hash(root)
|
132
|
+
root.map do |node|
|
133
|
+
if node.children.first.kind_of? Hpricot::Text
|
134
|
+
map_xml_value(node.children.to_s)
|
135
|
+
else
|
136
|
+
xml_node_to_hash(node)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Iterates through a given Hpricot +element+ and returns a Ruby Hash
|
142
|
+
# equal to the XML content of the given element.
|
143
|
+
def xml_node_to_hash(element)
|
144
|
+
hash = {}
|
145
|
+
|
146
|
+
element.each_child do |child|
|
147
|
+
key = create_hash_key(child.name)
|
148
|
+
value = create_hash_value(child)
|
149
|
+
|
150
|
+
case hash[key]
|
151
|
+
when Array
|
152
|
+
hash[key] << value
|
153
|
+
when nil
|
154
|
+
hash[key] = value
|
155
|
+
else
|
156
|
+
hash[key] = [ hash[key].dup, value ]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
hash
|
161
|
+
end
|
162
|
+
|
163
|
+
# Returns a Hash key for +xml_node_to_hash+ by a given +name+.
|
164
|
+
def create_hash_key(name)
|
165
|
+
key = XMLNode.new(name)
|
166
|
+
key.strip_namespace!
|
167
|
+
key.to_snake_case! unless disable_hash_keys_to_snake_case
|
168
|
+
key = disable_hash_keys_to_symbols ? key.to_s : key.to_sym
|
169
|
+
end
|
170
|
+
|
171
|
+
# Returns a Hash value for +xml_node_to_hash+ by a given +value+.
|
172
|
+
def create_hash_value(value)
|
173
|
+
if value.children.nil? || value.children.empty?
|
174
|
+
nil
|
175
|
+
elsif value.children.size == 1 && value.children.first.text?
|
176
|
+
map_xml_value(value.children.first.to_html)
|
177
|
+
else
|
178
|
+
xml_node_to_hash(value)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Expects a Hash +key+ and a Hash +value+. Iterates through the given Hash
|
183
|
+
# +value+ and returns an XML String of the given Hash structure.
|
184
|
+
def nested_data_to_xml(key, value)
|
185
|
+
case value
|
186
|
+
when Array
|
187
|
+
value.map { |subitem| nested_data_to_xml(key, subitem) }.join
|
188
|
+
when Hash
|
189
|
+
xml_node(key) do
|
190
|
+
sort_hash_keys(value).map do |subkey, subvalue|
|
191
|
+
case subvalue
|
192
|
+
when Array
|
193
|
+
subvalue.map { |subitem| nested_data_to_xml(subkey, subitem) }.join
|
194
|
+
when Hash
|
195
|
+
nested_data_to_xml(subkey, subvalue)
|
196
|
+
else
|
197
|
+
xml_node(subkey) { subvalue.to_s } if subvalue.respond_to? :to_s
|
198
|
+
end
|
199
|
+
end.join
|
200
|
+
end
|
201
|
+
else
|
202
|
+
xml_node(key) { value.to_s } if value.respond_to? :to_s
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Returns an XML tag with a given +name+. Accepts a +block+ for tag content.
|
207
|
+
# Defaults to returning an empty-element tag in case no block was given.
|
208
|
+
# Also accepts a Hash of +attributes+ to be added to the XML tag.
|
209
|
+
def xml_node(name, attributes = {})
|
210
|
+
node = XMLNode.new(name.to_s)
|
211
|
+
node.to_lower_camel_case! unless disable_tag_names_to_lower_camel_case
|
212
|
+
node.namespace_from_hash!(nodes_to_namespace)
|
213
|
+
node.attributes = sort_hash_keys(attributes)
|
214
|
+
node.body = yield if block_given?
|
215
|
+
node.to_tag
|
216
|
+
end
|
217
|
+
|
218
|
+
# Removes whitespace between tags of a given +xml+ String.
|
219
|
+
def remove_whitespace(xml)
|
220
|
+
xml.gsub(/(>)\s*(<)/, '\1\2')
|
221
|
+
end
|
222
|
+
|
223
|
+
# Converts XML values to more natural Ruby objects.
|
224
|
+
def map_xml_value(value)
|
225
|
+
case value
|
226
|
+
when "true" then true
|
227
|
+
when "false" then false
|
228
|
+
else value
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Returns a sorted version of a given +hash+ if +sort_keys+ is enabled.
|
233
|
+
def sort_hash_keys(hash)
|
234
|
+
return hash unless sort_keys
|
235
|
+
hash.keys.sort_by { |key| key.to_s }.map { |key| [ key, hash[key] ] }
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# == XMLNode
|
2
|
+
#
|
3
|
+
# Representation of an XML node. Inherits from String and includes some
|
4
|
+
# useful methods for namespaces, attributes, body content etc.
|
5
|
+
class XMLNode < String
|
6
|
+
|
7
|
+
# Hash of attributes.
|
8
|
+
attr_writer :attributes
|
9
|
+
|
10
|
+
# Body content.
|
11
|
+
attr_writer :body
|
12
|
+
|
13
|
+
# Strips the namespace from this node.
|
14
|
+
def strip_namespace!
|
15
|
+
sub!(/.+:(.+)/, '\1')
|
16
|
+
end
|
17
|
+
|
18
|
+
# Converts this node to snake_case.
|
19
|
+
def to_snake_case!
|
20
|
+
gsub!(/[A-Z]/, '_\0')
|
21
|
+
gsub!(/^_/, '')
|
22
|
+
downcase!
|
23
|
+
end
|
24
|
+
|
25
|
+
# Converts this node to lowerCamelCase.
|
26
|
+
def to_lower_camel_case!
|
27
|
+
gsub!(/_(.)/) { $1.upcase }
|
28
|
+
end
|
29
|
+
|
30
|
+
# Checks if this node is included in a given Hash of +namespaces+ and
|
31
|
+
# sets the namespace for this node in case it was found in the Hash.
|
32
|
+
def namespace_from_hash!(namespaces)
|
33
|
+
namespaces.each do |namespace, nodes|
|
34
|
+
@namespace = namespace if self_included? nodes
|
35
|
+
end unless namespaces.nil? || namespaces.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns this node as an XML tag including a namespace, attributes
|
39
|
+
# and a body in case these values were supplied.
|
40
|
+
def to_tag
|
41
|
+
return "<#{namespace}#{self}#{attributes} />" unless @body
|
42
|
+
"<#{namespace}#{self}#{attributes}>#{body}</#{namespace}#{self}>"
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# Returns +true+ if self as a String or a Symbol is included in a
|
48
|
+
# given +array+. Returns +false+ otherwise.
|
49
|
+
def self_included?(array)
|
50
|
+
array.include?(self.to_s) || array.include?(self.to_sym)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns the namespace of this node. Defaults to an empty String
|
54
|
+
# in case no namespace was defined.
|
55
|
+
def namespace
|
56
|
+
@namespace ? "#{@namespace}:" : ""
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns the attributes of this node. Defaults to an empty String
|
60
|
+
# in case no attributes were defined.
|
61
|
+
def attributes
|
62
|
+
return "" if @attributes.nil?
|
63
|
+
@attributes.map { |key, value| %Q( xmlns:#{key}="#{value}") }
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns the body of this node. Defaults to an empty String in case
|
67
|
+
# no body was defined.
|
68
|
+
def body
|
69
|
+
@body ? @body : ""
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "spec_helper")
|
2
|
+
|
3
|
+
describe ApricotEatsGorilla do
|
4
|
+
include SpecHelper
|
5
|
+
|
6
|
+
# hash_to_xml
|
7
|
+
describe "hash_to_xml" do
|
8
|
+
before { reset_library_options }
|
9
|
+
|
10
|
+
it "converts Hash key Symbols into Strings" do
|
11
|
+
hash = { :apricot => { :eats => [ :gorilla, "snake" ] } }
|
12
|
+
ApricotEatsGorilla.hash_to_xml(hash).should ==
|
13
|
+
"<apricot><eats>gorilla</eats><eats>snake</eats></apricot>"
|
14
|
+
end
|
15
|
+
|
16
|
+
it "converts lowerCamelCase Hash keys to snake_case" do
|
17
|
+
hash = { :apricot => { :eats => { :lots_of => "gorillas" } } }
|
18
|
+
ApricotEatsGorilla.hash_to_xml(hash).should ==
|
19
|
+
"<apricot><eats><lotsOf>gorillas</lotsOf></eats></apricot>"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "does not convert lowerCamelCase Hash keys to snake_case if this was disabled" do
|
23
|
+
ApricotEatsGorilla.disable_tag_names_to_lower_camel_case = true
|
24
|
+
hash = { :apricot => { :eats => { :lots_of => "gorillas" } } }
|
25
|
+
ApricotEatsGorilla.hash_to_xml(hash).should ==
|
26
|
+
"<apricot><eats><lots_of>gorillas</lots_of></eats></apricot>"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "converts values responding to to_s into Strings" do
|
30
|
+
date_time = DateTime.now
|
31
|
+
hash = { :apricot => {
|
32
|
+
:at => date_time,
|
33
|
+
:with => 100.01,
|
34
|
+
:when => nil,
|
35
|
+
:what => :gorillas
|
36
|
+
}}
|
37
|
+
ApricotEatsGorilla.hash_to_xml(hash).should ==
|
38
|
+
"<apricot><at>#{date_time}</at><what>gorillas</what>" <<
|
39
|
+
"<when></when><with>100.01</with></apricot>"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "applies namespaces nodes defined via nodes_to_namespace" do
|
43
|
+
ApricotEatsGorilla.nodes_to_namespace = { :wsdl => [ :apricot ] }
|
44
|
+
hash = { :apricot => { :eats => "Gorilla" } }
|
45
|
+
ApricotEatsGorilla.hash_to_xml(hash).should ==
|
46
|
+
"<wsdl:apricot><eats>Gorilla</eats></wsdl:apricot>"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "converts a Hash containing only one key and a value into one node with content" do
|
50
|
+
hash = { "apricot" => "eats Gorilla" }
|
51
|
+
ApricotEatsGorilla.hash_to_xml(hash).should == "<apricot>eats Gorilla</apricot>"
|
52
|
+
end
|
53
|
+
|
54
|
+
it "converts a nested Hash into nested nodes" do
|
55
|
+
hash = { "apricot" => { "eats" => "gorilla", "drinks" => "beer" } }
|
56
|
+
ApricotEatsGorilla.hash_to_xml(hash).should ==
|
57
|
+
"<apricot><drinks>beer</drinks><eats>gorilla</eats></apricot>"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "converts a Hash containing an Array into multiple nodes" do
|
61
|
+
hash = { "apricot" => { "eats" => [ "gorilla", "snake" ] } }
|
62
|
+
ApricotEatsGorilla.hash_to_xml(hash).should ==
|
63
|
+
"<apricot><eats>gorilla</eats><eats>snake</eats></apricot>"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "spec_helper")
|
2
|
+
|
3
|
+
describe ApricotEatsGorilla do
|
4
|
+
include SpecHelper
|
5
|
+
|
6
|
+
# setup
|
7
|
+
describe "setup" do
|
8
|
+
it "yields self to a given block" do
|
9
|
+
ApricotEatsGorilla.setup do |yielded|
|
10
|
+
yielded.should == ApricotEatsGorilla
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# soap_envelope
|
16
|
+
describe "soap_envelope" do
|
17
|
+
before { ApricotEatsGorilla.sort_keys = true }
|
18
|
+
|
19
|
+
it "returns a SOAP envelope with an empty-element body tag" do
|
20
|
+
ApricotEatsGorilla.soap_envelope.should ==
|
21
|
+
'<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">' <<
|
22
|
+
'<env:Body /></env:Envelope>'
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns a SOAP envelope with a custom namespace and body content" do
|
26
|
+
result = ApricotEatsGorilla.soap_envelope(:wsdl => "http://example.com") do
|
27
|
+
"<id>123</id>"
|
28
|
+
end
|
29
|
+
result.should == '<env:Envelope' <<
|
30
|
+
' xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"' <<
|
31
|
+
' xmlns:wsdl="http://example.com">' <<
|
32
|
+
'<env:Body><id>123</id></env:Body></env:Envelope>'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# []
|
37
|
+
describe "[]" do
|
38
|
+
before { reset_library_options }
|
39
|
+
|
40
|
+
it "converts a given XML into a Hash" do
|
41
|
+
xml = "<root><name>Jungle Julia</name></root>"
|
42
|
+
ApricotEatsGorilla[xml].should == { :name => "Jungle Julia" }
|
43
|
+
end
|
44
|
+
|
45
|
+
it "converts a given XML with a custom root node into a Hash" do
|
46
|
+
xml = "<root><something><name>Jungle Julia</name></something></root>"
|
47
|
+
ApricotEatsGorilla[xml, "//something"].should == { :name => "Jungle Julia" }
|
48
|
+
end
|
49
|
+
|
50
|
+
it "converts a given Hash into XML" do
|
51
|
+
hash = { "apricot" => "eats gorilla" }
|
52
|
+
ApricotEatsGorilla[hash] == "<apricot>eats gorilla</apricot>"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "spec_helper")
|
2
|
+
|
3
|
+
describe ApricotEatsGorilla do
|
4
|
+
include SpecHelper
|
5
|
+
|
6
|
+
# xml_to_hash
|
7
|
+
describe "xml_to_hash" do
|
8
|
+
before { reset_library_options }
|
9
|
+
|
10
|
+
it "converts Hash keys to Symbols" do
|
11
|
+
xml = "<root><name>Jungle Julia</name></root>"
|
12
|
+
ApricotEatsGorilla.xml_to_hash(xml).should == { :name => "Jungle Julia" }
|
13
|
+
end
|
14
|
+
|
15
|
+
it "does not convert Hash keys to Symbols if this was disabled" do
|
16
|
+
ApricotEatsGorilla.disable_hash_keys_to_symbols = true
|
17
|
+
xml = "<root><name>Jungle Julia</name></root>"
|
18
|
+
ApricotEatsGorilla.xml_to_hash(xml).should == { "name" => "Jungle Julia" }
|
19
|
+
end
|
20
|
+
|
21
|
+
it "converts String values of 'true' and 'false' into TrueClass and FalseClass" do
|
22
|
+
xml = "<root><yes>true</yes><no>false</no></root>"
|
23
|
+
ApricotEatsGorilla.xml_to_hash(xml).should == { :yes => true, :no => false }
|
24
|
+
end
|
25
|
+
|
26
|
+
it "converts empty-element tags to 'nil'" do
|
27
|
+
xml = "<contact><name>Jungle Julia</name><email /></contact>"
|
28
|
+
ApricotEatsGorilla.xml_to_hash(xml).should == { :name => "Jungle Julia", :email => nil }
|
29
|
+
end
|
30
|
+
|
31
|
+
it "converts lowerCamelCase nodes to snake_case" do
|
32
|
+
xml = "<root><firstName>Jungle</firstName><lastName>Julia</lastName></root>"
|
33
|
+
ApricotEatsGorilla.xml_to_hash(xml).should == { :first_name => "Jungle", :last_name => "Julia" }
|
34
|
+
end
|
35
|
+
|
36
|
+
it "does not convert lowerCamelCase nodes to snake_case if this was disabled" do
|
37
|
+
ApricotEatsGorilla.disable_hash_keys_to_snake_case = true
|
38
|
+
xml = "<root><firstName>Jungle</firstName><lastName>Julia</lastName></root>"
|
39
|
+
ApricotEatsGorilla.xml_to_hash(xml).should == { :firstName => "Jungle", :lastName => "Julia" }
|
40
|
+
end
|
41
|
+
|
42
|
+
it "removes namespaces from nodes" do
|
43
|
+
xml = "<root><wsdl:apricot><eats>Gorilla</eats></wsdl:apricot></root>"
|
44
|
+
ApricotEatsGorilla.xml_to_hash(xml).should == { :apricot => { :eats => "Gorilla" } }
|
45
|
+
end
|
46
|
+
|
47
|
+
it "removes attributes from nodes" do
|
48
|
+
xml = '<root><contact id="123">Jungle Julia</contact></root>'
|
49
|
+
ApricotEatsGorilla.xml_to_hash(xml).should == { :contact => "Jungle Julia" }
|
50
|
+
end
|
51
|
+
|
52
|
+
it "starts translating XML at a given custom root node" do
|
53
|
+
xml = '<root><contact><name>Jungle Julia</name></contact></root>'
|
54
|
+
ApricotEatsGorilla.xml_to_hash(xml, "//contact").should == { :name => "Jungle Julia" }
|
55
|
+
end
|
56
|
+
|
57
|
+
it "returns an Array of nodes and values in case of multiple root nodes" do
|
58
|
+
xml = '<root><return><id>1</id></return><return><id>2</id></return></root>'
|
59
|
+
ApricotEatsGorilla.xml_to_hash(xml, "//return").should == [{ :id => "1" }, { :id => "2" }]
|
60
|
+
end
|
61
|
+
|
62
|
+
it "returns the value of a node if it does not contain any subnodes" do
|
63
|
+
xml = '<root><return>123</return></root>'
|
64
|
+
ApricotEatsGorilla.xml_to_hash(xml, "//return").should == "123"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "returns an Array of values in case of multiple root nodes without subnodes" do
|
68
|
+
xml = '<root><return>123</return><return>456</return></root>'
|
69
|
+
ApricotEatsGorilla.xml_to_hash(xml, "//return").should == ["123", "456"]
|
70
|
+
end
|
71
|
+
|
72
|
+
it "returns a Hash containing an Array of content for multiple subnodes" do
|
73
|
+
xml = '<root><return><items>first</items><items>second</items></return></root>'
|
74
|
+
ApricotEatsGorilla.xml_to_hash(xml, "//return").should == { :items => ["first", "second"] }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "..", "spec_helper")
|
2
|
+
|
3
|
+
describe XMLNode do
|
4
|
+
|
5
|
+
# strip_namespace!
|
6
|
+
describe "strip_namespace!" do
|
7
|
+
it "strips the namespace from the node" do
|
8
|
+
node = XMLNode.new("wsdl:apricot")
|
9
|
+
node.strip_namespace!
|
10
|
+
|
11
|
+
node.should == "apricot"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# to_snake_case!
|
16
|
+
describe "to_snake_case!" do
|
17
|
+
it "converts the node from CamelCase to snake_case" do
|
18
|
+
node = XMLNode.new("ApricotEatsGorilla")
|
19
|
+
node.to_snake_case!
|
20
|
+
|
21
|
+
node.should == "apricot_eats_gorilla"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "converts the node from lowerCamelCase to snake_case" do
|
25
|
+
node = XMLNode.new("apricotEatsGorilla")
|
26
|
+
node.to_snake_case!
|
27
|
+
|
28
|
+
node.should == "apricot_eats_gorilla"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# namespace_from_hash!
|
33
|
+
describe "namespace_from_hash!" do
|
34
|
+
it "namespaces the node if it's included in the given Hash" do
|
35
|
+
node = XMLNode.new("apricot")
|
36
|
+
node.namespace_from_hash!(:wsdl => [ :apricot ])
|
37
|
+
|
38
|
+
node.should == "apricot"
|
39
|
+
node.to_tag.should == "<wsdl:apricot />"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "does nothing if the node is not included in the given Hash" do
|
43
|
+
node = XMLNode.new("apricot")
|
44
|
+
node.namespace_from_hash!(:wsdl => [ :some_key ])
|
45
|
+
|
46
|
+
node.should == "apricot"
|
47
|
+
node.to_tag.should == "<apricot />"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# to_tag
|
52
|
+
describe "to_tag" do
|
53
|
+
it "returns an empty-element tag for a bare node" do
|
54
|
+
node = XMLNode.new("apricot")
|
55
|
+
node.to_tag.should == "<apricot />"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns a namespaced empty-element tag for a namespaced node" do
|
59
|
+
node = XMLNode.new("apricot")
|
60
|
+
node.namespace_from_hash!(:wsdl => [ :apricot ])
|
61
|
+
|
62
|
+
node.to_tag.should == "<wsdl:apricot />"
|
63
|
+
end
|
64
|
+
|
65
|
+
it "returns an empty-element tag with an attribute for an attributed node" do
|
66
|
+
node = XMLNode.new("apricot")
|
67
|
+
node.attributes = { :wsdl => "http://example.com" }
|
68
|
+
|
69
|
+
node.to_tag.should == '<apricot xmlns:wsdl="http://example.com" />'
|
70
|
+
end
|
71
|
+
|
72
|
+
it "returns a node with body content for a node with content" do
|
73
|
+
node = XMLNode.new("apricot")
|
74
|
+
node.body = "eats gorilla"
|
75
|
+
|
76
|
+
node.to_tag.should == "<apricot>eats gorilla</apricot>"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
gem "rspec", ">= 1.2.8"
|
3
|
+
require "spec"
|
4
|
+
require File.join(File.dirname(__FILE__), "..", "lib", "apricoteatsgorilla")
|
5
|
+
|
6
|
+
Spec::Runner.configure do |config|
|
7
|
+
config.mock_with :rr
|
8
|
+
end
|
9
|
+
|
10
|
+
module SpecHelper
|
11
|
+
def reset_library_options
|
12
|
+
ApricotEatsGorilla.setup do |setup|
|
13
|
+
setup.sort_keys = true
|
14
|
+
setup.disable_tag_names_to_lower_camel_case = false
|
15
|
+
setup.disable_hash_keys_to_snake_case = false
|
16
|
+
setup.disable_hash_keys_to_symbols = false
|
17
|
+
setup.nodes_to_namespace = nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
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.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Harrington
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-08-29 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -41,12 +41,25 @@ extensions: []
|
|
41
41
|
extra_rdoc_files:
|
42
42
|
- README.rdoc
|
43
43
|
files:
|
44
|
+
- .gitignore
|
44
45
|
- README.rdoc
|
45
46
|
- Rakefile
|
47
|
+
- VERSION
|
48
|
+
- apricoteatsgorilla.gemspec
|
49
|
+
- lib/apricoteatsgorilla.rb
|
50
|
+
- lib/apricoteatsgorilla/apricoteatsgorilla.rb
|
51
|
+
- lib/apricoteatsgorilla/xml_node.rb
|
52
|
+
- spec/apricoteatsgorilla/apricoteatsgorilla_hash_to_xml_spec.rb
|
53
|
+
- spec/apricoteatsgorilla/apricoteatsgorilla_spec.rb
|
54
|
+
- spec/apricoteatsgorilla/apricoteatsgorilla_xml_to_hash_spec.rb
|
55
|
+
- spec/apricoteatsgorilla/xml_node_spec.rb
|
56
|
+
- spec/spec_helper.rb
|
46
57
|
has_rdoc: true
|
47
58
|
homepage: http://github.com/smacks/apricoteatsgorilla
|
59
|
+
licenses:
|
48
60
|
post_install_message:
|
49
61
|
rdoc_options:
|
62
|
+
- --charset=UTF-8
|
50
63
|
- --title
|
51
64
|
- Apricot eats Gorilla
|
52
65
|
- --main
|
@@ -70,9 +83,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
83
|
requirements: []
|
71
84
|
|
72
85
|
rubyforge_project:
|
73
|
-
rubygems_version: 1.
|
86
|
+
rubygems_version: 1.3.5
|
74
87
|
signing_key:
|
75
88
|
specification_version: 2
|
76
|
-
summary:
|
77
|
-
test_files:
|
78
|
-
|
89
|
+
summary: SOAP communication helper.
|
90
|
+
test_files:
|
91
|
+
- spec/apricoteatsgorilla/apricoteatsgorilla_hash_to_xml_spec.rb
|
92
|
+
- spec/apricoteatsgorilla/apricoteatsgorilla_spec.rb
|
93
|
+
- spec/apricoteatsgorilla/apricoteatsgorilla_xml_to_hash_spec.rb
|
94
|
+
- spec/apricoteatsgorilla/xml_node_spec.rb
|
95
|
+
- spec/spec_helper.rb
|