smacks-apricoteatsgorilla 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|