smacks-apricoteatsgorilla 0.2.5 → 0.2.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 +4 -7
- data/lib/apricoteatsgorilla.rb +43 -29
- data/tests/apricoteatsgorilla_test.rb +125 -0
- metadata +4 -6
- data/tests/apricot_eats_gorilla_testsuite.rb +0 -3
- data/tests/hash_to_xml_test.rb +0 -43
- data/tests/xml_to_hash_test.rb +0 -66
data/README.rdoc
CHANGED
@@ -1,11 +1,8 @@
|
|
1
1
|
= Apricot eats Gorilla
|
2
2
|
|
3
|
-
Apricot eats Gorilla
|
4
|
-
It's based on CobraVsMongoose but
|
5
|
-
|
6
|
-
|
7
|
-
Its initial purpose was to convert SOAP response messages to Hashes,
|
8
|
-
but it quickly evolved into a more general translation tool.
|
3
|
+
Apricot eats Gorilla is a helper for working with XML and SOAP messages.
|
4
|
+
It's based on CobraVsMongoose but without REXML and the BadgerFish convention.
|
5
|
+
Also it offers some extras for working with SOAP messages.
|
9
6
|
|
10
7
|
== Install
|
11
8
|
|
@@ -68,4 +65,4 @@ And it gets converted into a nice little Hash:
|
|
68
65
|
|
69
66
|
== More information
|
70
67
|
|
71
|
-
Take a look at the tests for some more examples.
|
68
|
+
Take a look at the tests for some more examples.
|
data/lib/apricoteatsgorilla.rb
CHANGED
@@ -2,22 +2,20 @@
|
|
2
2
|
require 'rubygems'
|
3
3
|
require 'hpricot'
|
4
4
|
|
5
|
-
# Apricot eats Gorilla
|
6
|
-
# It's based on CobraVsMongoose but
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# Its initial purpose was to convert SOAP response messages to Hashes,
|
10
|
-
# but it quickly evolved into a more general translation tool.
|
5
|
+
# Apricot eats Gorilla is a helper for working with XML and SOAP messages.
|
6
|
+
# It's based on CobraVsMongoose but without REXML and the BadgerFish convention.
|
7
|
+
# Also it offers some extras for working with SOAP messages.
|
11
8
|
class ApricotEatsGorilla
|
12
|
-
|
13
9
|
class << self
|
10
|
+
|
11
|
+
# Flag to enable optional sorting of Hash keys. Especially useful for
|
12
|
+
# comparing expected values with actual results while testing.
|
14
13
|
attr_accessor :sort_keys
|
15
14
|
|
16
15
|
# Converts XML into a Hash. Starts parsing at root node by default.
|
17
16
|
# Call with XPath expession (Hpricot search) as second parameter to define
|
18
17
|
# a custom root node. The root node itself will not be included in the Hash.
|
19
18
|
#
|
20
|
-
# E.g.
|
21
19
|
# xml = "<dude><likes>beer</likes><hates>appletini</hates></dude>"
|
22
20
|
# ApricotEatsGorilla.xml_to_hash(xml)
|
23
21
|
# # => { "hates" => "appletini", "likes" => "beer" }
|
@@ -29,8 +27,7 @@ class ApricotEatsGorilla
|
|
29
27
|
end
|
30
28
|
|
31
29
|
# Converts a Hash to XML.
|
32
|
-
#
|
33
|
-
# E.g.
|
30
|
+
#
|
34
31
|
# hash = { "dude" => { "likes" => "beer", "hates" => "appletini" } }
|
35
32
|
# ApricotEatsGorilla.hash_to_xml(hash)
|
36
33
|
# # => "<dude><hates>appletini</hates><likes>beer</likes></dude>"
|
@@ -38,24 +35,52 @@ class ApricotEatsGorilla
|
|
38
35
|
nested_data_to_xml(hash.keys.first, hash.values.first)
|
39
36
|
end
|
40
37
|
|
38
|
+
# Builds a SOAP envelope and includes the content from an expected block
|
39
|
+
# into the envelope body. Pass in a Hash of namespaces and their URI to
|
40
|
+
# set custom namespaces.
|
41
|
+
#
|
42
|
+
# <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
|
43
|
+
# <env:Body>
|
44
|
+
# yield
|
45
|
+
# </env:Body>
|
46
|
+
# </env:Envelope>
|
47
|
+
def soap_envelope(namespaces = {})
|
48
|
+
namespaces["env"] = "http://schemas.xmlsoap.org/soap/envelope/"
|
49
|
+
tag("env:Envelope", namespaces) do
|
50
|
+
tag("env:Body") do
|
51
|
+
yield if block_given?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Creates an XML tag. Expects a block for tag content.
|
57
|
+
# Defaults to an empty element tag in case no block was supplied.
|
58
|
+
def tag(name, attributes = {})
|
59
|
+
return "<#{name} />" unless block_given?
|
60
|
+
|
61
|
+
attr = opt_order(attributes).map { |k, v| sprintf(' xmlns:%s="%s"', k, v) }.to_s
|
62
|
+
body = (yield && !yield.empty?) ? yield : ""
|
63
|
+
"<#{name}#{attr}>" << body << "</#{name}>"
|
64
|
+
end
|
65
|
+
|
41
66
|
private
|
42
67
|
|
43
68
|
# Converts XML into a Hash.
|
44
69
|
def xml_node_to_hash(node)
|
45
70
|
this_node = {}
|
46
|
-
|
47
71
|
node.each_child do |child|
|
72
|
+
# hpricot 0.6.1 returns an empty array, while 0.8 returns nil
|
48
73
|
if child.children.nil? || child.children.empty?
|
49
74
|
key, value = child.name, nil
|
50
75
|
elsif child.children.size == 1 && child.children.first.text?
|
51
|
-
key, value = child.name,
|
76
|
+
key, value = child.name, booleanize(child.children.first.inner_text)
|
52
77
|
else
|
53
78
|
key, value = child.name, xml_node_to_hash(child)
|
54
79
|
end
|
55
80
|
|
56
81
|
current = this_node[key]
|
57
82
|
case current
|
58
|
-
when Array
|
83
|
+
when Array
|
59
84
|
this_node[key] << value
|
60
85
|
when nil
|
61
86
|
this_node[key] = value
|
@@ -63,7 +88,6 @@ class ApricotEatsGorilla
|
|
63
88
|
this_node[key] = [current.dup, value]
|
64
89
|
end
|
65
90
|
end
|
66
|
-
|
67
91
|
this_node
|
68
92
|
end
|
69
93
|
|
@@ -71,15 +95,15 @@ class ApricotEatsGorilla
|
|
71
95
|
def nested_data_to_xml(name, item)
|
72
96
|
case item
|
73
97
|
when String
|
74
|
-
|
98
|
+
tag(name) { item }
|
75
99
|
when Array
|
76
100
|
item.map { |subitem| nested_data_to_xml(name, subitem) }.join
|
77
101
|
when Hash
|
78
|
-
|
102
|
+
tag(name) do
|
79
103
|
opt_order(item).map { |tag, value|
|
80
104
|
case value
|
81
105
|
when String
|
82
|
-
|
106
|
+
tag(tag) { value }
|
83
107
|
when Array
|
84
108
|
value.map { |subitem| nested_data_to_xml(tag, subitem) }.join
|
85
109
|
when Hash
|
@@ -90,17 +114,7 @@ class ApricotEatsGorilla
|
|
90
114
|
end
|
91
115
|
end
|
92
116
|
|
93
|
-
#
|
94
|
-
# Defaults to an empty element tag in case no block was supplied.
|
95
|
-
def make_tag(name)
|
96
|
-
body = yield
|
97
|
-
if body && !body.empty?
|
98
|
-
"<#{name}>" << body << "</#{name}>"
|
99
|
-
else
|
100
|
-
"<#{name} />"
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
117
|
+
# Returns a sorted version of a given Hash in case :sort_keys is enabled.
|
104
118
|
def opt_order(hash)
|
105
119
|
if sort_keys
|
106
120
|
hash.sort_by{ |kv| kv.first }
|
@@ -117,7 +131,7 @@ class ApricotEatsGorilla
|
|
117
131
|
|
118
132
|
# Helper to convert "true" and "false" strings to boolean values.
|
119
133
|
# Returns the original string in case it doesn't match "true" or "false".
|
120
|
-
def
|
134
|
+
def booleanize(string)
|
121
135
|
return true if string == "true"
|
122
136
|
return false if string == "false"
|
123
137
|
string
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'test/unit'
|
3
|
+
require File.join(File.dirname(__FILE__), "..", "lib", "apricoteatsgorilla")
|
4
|
+
|
5
|
+
class ApricotEatsGorillaTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
ApricotEatsGorilla.sort_keys = true
|
9
|
+
end
|
10
|
+
|
11
|
+
# xml_to_hash
|
12
|
+
def test_xml_to_hash_with_soap_response_example
|
13
|
+
xml = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
14
|
+
<soap:Body>
|
15
|
+
<ns2:authenticateResponse xmlns:ns2="http://v1_0.ws.example.com/">
|
16
|
+
<return>
|
17
|
+
<authValue>
|
18
|
+
<token>secret</token>
|
19
|
+
<client>example</client>
|
20
|
+
</authValue>
|
21
|
+
</return>
|
22
|
+
</ns2:authenticateResponse>
|
23
|
+
</soap:Body>
|
24
|
+
</soap:Envelope>'
|
25
|
+
expected = { 'authValue' => { 'token' => 'secret', 'client' => 'example' } }
|
26
|
+
|
27
|
+
result = ApricotEatsGorilla.xml_to_hash(xml, '//return')
|
28
|
+
assert_equal expected, result
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_xml_to_hash_make_sure_boolean_values_get_converted_to_boolean_objects
|
32
|
+
xml = '<root><yes>true</yes><no>false</no><txt>something</txt></root>'
|
33
|
+
expected = { 'yes' => true, 'no' => false, 'txt' => 'something' }
|
34
|
+
|
35
|
+
result = ApricotEatsGorilla.xml_to_hash(xml)
|
36
|
+
assert_equal expected, result
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_xml_to_hash_make_sure_empty_element_tags_get_converted_to_nil
|
40
|
+
xml = '<contact><name>Jungle Julia</name><email /><phone/></contact>'
|
41
|
+
expected = { 'name' => 'Jungle Julia', 'email' => nil, 'phone' => nil }
|
42
|
+
|
43
|
+
result = ApricotEatsGorilla.xml_to_hash(xml)
|
44
|
+
assert_equal expected, result
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_xml_to_hash_make_sure_node_attributes_get_removed
|
48
|
+
xml = '<todo><paint subject="chair" color="#000000">black</paint></todo>'
|
49
|
+
expected = { 'paint' => 'black' }
|
50
|
+
|
51
|
+
result = ApricotEatsGorilla.xml_to_hash(xml)
|
52
|
+
assert_equal expected, result
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_xml_to_hash_make_sure_node_groups_with_text_values_get_converted_to_arrays
|
56
|
+
xml = '<root><items>first</items><items>second</items></root>'
|
57
|
+
expected = { 'items' => [ 'first', 'second' ] }
|
58
|
+
|
59
|
+
result = ApricotEatsGorilla.xml_to_hash(xml)
|
60
|
+
assert_equal expected, result
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_xml_to_hash_make_sure_node_groups_with_nesting_get_converted_to_arrays_with_hashes
|
64
|
+
xml = '<root><items><name>first</name></items><items><name>second</name></items></root>'
|
65
|
+
expected = { 'items' => [ { 'name' => 'first' }, { 'name' => 'second' } ] }
|
66
|
+
|
67
|
+
result = ApricotEatsGorilla.xml_to_hash(xml)
|
68
|
+
assert_equal expected, result
|
69
|
+
end
|
70
|
+
|
71
|
+
# hash_to_xml
|
72
|
+
def test_hash_to_xml_with_simple_hash
|
73
|
+
hash = { "dude" => "likes beer" }
|
74
|
+
expected = "<dude>likes beer</dude>"
|
75
|
+
|
76
|
+
result = ApricotEatsGorilla.hash_to_xml(hash)
|
77
|
+
assert_equal expected, result
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_hash_to_xml_with_nested_hash
|
81
|
+
hash = { "dude" => { "likes" => "beer", "hates" => "appletini" } }
|
82
|
+
expected = "<dude><hates>appletini</hates><likes>beer</likes></dude>"
|
83
|
+
|
84
|
+
result = ApricotEatsGorilla.hash_to_xml(hash)
|
85
|
+
assert_equal expected, result
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_hash_to_xml_with_nested_hash_and_array
|
89
|
+
hash = { "dude" => { "likes" => [ "beer", "helicopters" ] } }
|
90
|
+
expected = "<dude><likes>beer</likes><likes>helicopters</likes></dude>"
|
91
|
+
|
92
|
+
result = ApricotEatsGorilla.hash_to_xml(hash)
|
93
|
+
assert_equal expected, result
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_hash_to_xml_with_nested_hash_and_array_containing_a_hash
|
97
|
+
hash = { "dude" => { "likes" => [ { "beer" => "a lot" }, { "helicopters" => "a little more" } ] } }
|
98
|
+
expected = "<dude><likes><beer>a lot</beer></likes><likes><helicopters>a little more</helicopters></likes></dude>"
|
99
|
+
|
100
|
+
result = ApricotEatsGorilla.hash_to_xml(hash)
|
101
|
+
assert_equal expected, result
|
102
|
+
end
|
103
|
+
|
104
|
+
# soap_envelope
|
105
|
+
def test_soap_envelope_without_namespace_and_block_returns_pure_envelope
|
106
|
+
expected = '<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">' <<
|
107
|
+
'<env:Body></env:Body></env:Envelope>'
|
108
|
+
|
109
|
+
result = ApricotEatsGorilla.soap_envelope
|
110
|
+
assert_equal expected, result
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_soap_envelope_with_namespace_and_block_returns_envelope_with_namespace_and_content
|
114
|
+
expected = '<env:Envelope ' <<
|
115
|
+
'xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" ' <<
|
116
|
+
'xmlns:wsdl="http://example.com">' <<
|
117
|
+
'<env:Body><id>123</id></env:Body></env:Envelope>'
|
118
|
+
|
119
|
+
result = ApricotEatsGorilla.soap_envelope("wsdl" => "http://example.com") do
|
120
|
+
"<id>123</id>"
|
121
|
+
end
|
122
|
+
assert_equal expected, result
|
123
|
+
end
|
124
|
+
|
125
|
+
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.2.
|
4
|
+
version: 0.2.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
|
25
|
+
description: Apricot eats Gorilla is a helper for working with XML and SOAP messages.
|
26
26
|
email:
|
27
27
|
executables: []
|
28
28
|
|
@@ -59,8 +59,6 @@ rubyforge_project:
|
|
59
59
|
rubygems_version: 1.2.0
|
60
60
|
signing_key:
|
61
61
|
specification_version: 2
|
62
|
-
summary: Apricot eats Gorilla
|
62
|
+
summary: Apricot eats Gorilla is a helper for working with XML and SOAP messages.
|
63
63
|
test_files:
|
64
|
-
- tests/
|
65
|
-
- tests/hash_to_xml_test.rb
|
66
|
-
- tests/xml_to_hash_test.rb
|
64
|
+
- tests/apricoteatsgorilla_test.rb
|
data/tests/hash_to_xml_test.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
require 'test/unit'
|
3
|
-
require File.join(File.dirname(__FILE__), "..", "lib", "apricoteatsgorilla")
|
4
|
-
|
5
|
-
class HashToXmlTest < Test::Unit::TestCase
|
6
|
-
|
7
|
-
def setup
|
8
|
-
ApricotEatsGorilla.sort_keys = true
|
9
|
-
end
|
10
|
-
|
11
|
-
def test_dead_simple
|
12
|
-
hash = { "dude" => "likes beer" }
|
13
|
-
expected = "<dude>likes beer</dude>"
|
14
|
-
|
15
|
-
result = ApricotEatsGorilla.hash_to_xml(hash)
|
16
|
-
assert_equal expected, result
|
17
|
-
end
|
18
|
-
|
19
|
-
def test_nested_hash
|
20
|
-
hash = { "dude" => { "likes" => "beer", "hates" => "appletini" } }
|
21
|
-
expected = "<dude><hates>appletini</hates><likes>beer</likes></dude>"
|
22
|
-
|
23
|
-
result = ApricotEatsGorilla.hash_to_xml(hash)
|
24
|
-
assert_equal expected, result
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_nested_hash_with_array
|
28
|
-
hash = { "dude" => { "likes" => [ "beer", "helicopters" ] } }
|
29
|
-
expected = "<dude><likes>beer</likes><likes>helicopters</likes></dude>"
|
30
|
-
|
31
|
-
result = ApricotEatsGorilla.hash_to_xml(hash)
|
32
|
-
assert_equal expected, result
|
33
|
-
end
|
34
|
-
|
35
|
-
def test_nested_hash_with_array_containing_a_hash
|
36
|
-
hash = { "dude" => { "likes" => [ { "beer" => "a lot" }, { "helicopters" => "a little more" } ] } }
|
37
|
-
expected = "<dude><likes><beer>a lot</beer></likes><likes><helicopters>a little more</helicopters></likes></dude>"
|
38
|
-
|
39
|
-
result = ApricotEatsGorilla.hash_to_xml(hash)
|
40
|
-
assert_equal expected, result
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
data/tests/xml_to_hash_test.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
require 'test/unit'
|
3
|
-
require File.join(File.dirname(__FILE__), "..", "lib", "apricoteatsgorilla")
|
4
|
-
|
5
|
-
class XmlToHashTest < Test::Unit::TestCase
|
6
|
-
|
7
|
-
def test_soap_response_example
|
8
|
-
xml = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
|
9
|
-
<soap:Body>
|
10
|
-
<ns2:authenticateResponse xmlns:ns2="http://v1_0.ws.example.com/">
|
11
|
-
<return>
|
12
|
-
<authValue>
|
13
|
-
<token>secret</token>
|
14
|
-
<client>example</client>
|
15
|
-
</authValue>
|
16
|
-
</return>
|
17
|
-
</ns2:authenticateResponse>
|
18
|
-
</soap:Body>
|
19
|
-
</soap:Envelope>'
|
20
|
-
expected = { 'authValue' => { 'token' => 'secret', 'client' => 'example' } }
|
21
|
-
|
22
|
-
result = ApricotEatsGorilla.xml_to_hash(xml, '//return')
|
23
|
-
assert_equal expected, result
|
24
|
-
end
|
25
|
-
|
26
|
-
def test_that_boolean_string_values_are_converted_to_actual_boolean_objects
|
27
|
-
xml = '<root><yes>true</yes><no>false</no><txt>something</txt></root>'
|
28
|
-
expected = { 'yes' => true, 'no' => false, 'txt' => 'something' }
|
29
|
-
|
30
|
-
result = ApricotEatsGorilla.xml_to_hash(xml)
|
31
|
-
assert_equal expected, result
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_that_empty_element_tags_are_converted_to_nil
|
35
|
-
xml = '<contact><name>Jungle Julia</name><email /><phone/></contact>'
|
36
|
-
expected = { 'name' => 'Jungle Julia', 'email' => nil, 'phone' => nil }
|
37
|
-
|
38
|
-
result = ApricotEatsGorilla.xml_to_hash(xml)
|
39
|
-
assert_equal expected, result
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_that_attributes_get_removed
|
43
|
-
xml = '<todo><paint subject="chair" color="#000000">black</paint></todo>'
|
44
|
-
expected = { 'paint' => 'black' }
|
45
|
-
|
46
|
-
result = ApricotEatsGorilla.xml_to_hash(xml)
|
47
|
-
assert_equal expected, result
|
48
|
-
end
|
49
|
-
|
50
|
-
def test_that_node_groups_with_text_values_get_converted_to_arrays
|
51
|
-
xml = '<root><items>first</items><items>second</items></root>'
|
52
|
-
expected = { 'items' => [ 'first', 'second' ] }
|
53
|
-
|
54
|
-
result = ApricotEatsGorilla.xml_to_hash(xml)
|
55
|
-
assert_equal expected, result
|
56
|
-
end
|
57
|
-
|
58
|
-
def test_that_node_groups_with_nesting_get_converted_to_arrays_with_hashes
|
59
|
-
xml = '<root><items><name>first</name></items><items><name>second</name></items></root>'
|
60
|
-
expected = { 'items' => [ { 'name' => 'first' }, { 'name' => 'second' } ] }
|
61
|
-
|
62
|
-
result = ApricotEatsGorilla.xml_to_hash(xml)
|
63
|
-
assert_equal expected, result
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|