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