lolsoap 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/lolsoap/builder.rb +5 -1
- data/lib/lolsoap/envelope.rb +16 -8
- data/lib/lolsoap/wsdl.rb +69 -32
- data/lib/lolsoap/wsdl/element.rb +15 -10
- data/lib/lolsoap/wsdl/immediate_type_reference.rb +9 -0
- data/lib/lolsoap/wsdl/named_type_reference.rb +14 -0
- data/lib/lolsoap/wsdl/type.rb +9 -1
- data/lib/lolsoap/wsdl_parser.rb +107 -24
- data/lolsoap.gemspec +4 -2
- data/test/fixtures/stock_quote.wsdl +62 -5
- data/test/integration/test_envelope.rb +4 -4
- data/test/integration/test_wsdl.rb +3 -3
- data/test/unit/test_builder.rb +11 -3
- data/test/unit/test_envelope.rb +3 -3
- data/test/unit/test_wsdl.rb +61 -26
- data/test/unit/test_wsdl_parser.rb +110 -10
- data/test/unit/wsdl/test_element.rb +10 -7
- metadata +5 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/lolsoap/builder.rb
CHANGED
@@ -52,13 +52,17 @@ module LolSoap
|
|
52
52
|
# Add a tag manually, rather than through method_missing. This is so you can still
|
53
53
|
# add tags for the very small number of tags that are also existing methods.
|
54
54
|
def __tag__(name, *args, &block)
|
55
|
-
__prefixed_tag__(@type.
|
55
|
+
__prefixed_tag__(@type.element_prefix(name.to_s), @type.sub_type(name.to_s), name, *args, &block)
|
56
56
|
end
|
57
57
|
|
58
58
|
def __attribute__(name, value)
|
59
59
|
@node[name.to_s] = value.to_s
|
60
60
|
end
|
61
61
|
|
62
|
+
def __content__(value)
|
63
|
+
@node.content = value
|
64
|
+
end
|
65
|
+
|
62
66
|
# @private
|
63
67
|
def __prefixed_tag__(prefix, sub_type, name, *args)
|
64
68
|
sub_node = @node.document.create_element(name.to_s, *args)
|
data/lib/lolsoap/envelope.rb
CHANGED
@@ -26,7 +26,7 @@ module LolSoap
|
|
26
26
|
# b.some 'data'
|
27
27
|
# end
|
28
28
|
def body(klass = Builder)
|
29
|
-
builder = klass.new(
|
29
|
+
builder = klass.new(content, input_type)
|
30
30
|
yield builder if block_given?
|
31
31
|
builder
|
32
32
|
end
|
@@ -46,14 +46,22 @@ module LolSoap
|
|
46
46
|
operation.action
|
47
47
|
end
|
48
48
|
|
49
|
-
def
|
49
|
+
def input
|
50
50
|
operation.input
|
51
51
|
end
|
52
52
|
|
53
|
-
def
|
53
|
+
def input_type
|
54
|
+
input.type
|
55
|
+
end
|
56
|
+
|
57
|
+
def output
|
54
58
|
operation.output
|
55
59
|
end
|
56
60
|
|
61
|
+
def output_type
|
62
|
+
output.type
|
63
|
+
end
|
64
|
+
|
57
65
|
def to_xml(options = {})
|
58
66
|
doc.to_xml(options)
|
59
67
|
end
|
@@ -73,7 +81,7 @@ module LolSoap
|
|
73
81
|
private
|
74
82
|
|
75
83
|
# @private
|
76
|
-
def
|
84
|
+
def content; @content; end
|
77
85
|
|
78
86
|
# @private
|
79
87
|
def initialize_doc
|
@@ -84,13 +92,13 @@ module LolSoap
|
|
84
92
|
|
85
93
|
@header = doc.create_element 'Header'
|
86
94
|
|
87
|
-
@body
|
88
|
-
@
|
95
|
+
@body = doc.create_element 'Body'
|
96
|
+
@content = doc.create_element input.name
|
89
97
|
|
90
98
|
[root, @header, @body].each { |el| el.namespace = namespaces[soap_prefix] }
|
91
|
-
@
|
99
|
+
@content.namespace = namespaces[input.prefix]
|
92
100
|
|
93
|
-
@body << @
|
101
|
+
@body << @content
|
94
102
|
root << @header
|
95
103
|
root << @body
|
96
104
|
end
|
data/lib/lolsoap/wsdl.rb
CHANGED
@@ -4,6 +4,8 @@ module LolSoap
|
|
4
4
|
class WSDL
|
5
5
|
require 'lolsoap/wsdl/operation'
|
6
6
|
require 'lolsoap/wsdl/type'
|
7
|
+
require 'lolsoap/wsdl/named_type_reference'
|
8
|
+
require 'lolsoap/wsdl/immediate_type_reference'
|
7
9
|
require 'lolsoap/wsdl/null_type'
|
8
10
|
require 'lolsoap/wsdl/element'
|
9
11
|
require 'lolsoap/wsdl/null_element'
|
@@ -19,6 +21,9 @@ module LolSoap
|
|
19
21
|
# Hash of namespaces used in the WSDL document (keys are prefixes)
|
20
22
|
attr_reader :namespaces
|
21
23
|
|
24
|
+
# Namespaces used by the types (a subset of #namespaces)
|
25
|
+
attr_reader :type_namespaces
|
26
|
+
|
22
27
|
# Hash of namespace prefixes used in the WSDL document (keys are namespace URIs)
|
23
28
|
attr_reader :prefixes
|
24
29
|
|
@@ -26,22 +31,13 @@ module LolSoap
|
|
26
31
|
attr_reader :soap_version
|
27
32
|
|
28
33
|
def initialize(parser)
|
29
|
-
@types
|
30
|
-
@operations
|
31
|
-
@endpoint
|
32
|
-
@namespaces
|
33
|
-
@
|
34
|
-
@
|
35
|
-
|
36
|
-
|
37
|
-
# Hash of operations that are supports by the SOAP service
|
38
|
-
def operations
|
39
|
-
@operations.dup
|
40
|
-
end
|
41
|
-
|
42
|
-
# Get a single operation
|
43
|
-
def operation(name)
|
44
|
-
@operations.fetch(name)
|
34
|
+
@types = load_types(parser)
|
35
|
+
@operations = load_operations(parser)
|
36
|
+
@endpoint = parser.endpoint
|
37
|
+
@namespaces = parser.namespaces
|
38
|
+
@type_namespaces = load_type_namespaces(parser)
|
39
|
+
@prefixes = parser.prefixes
|
40
|
+
@soap_version = parser.soap_version
|
45
41
|
end
|
46
42
|
|
47
43
|
# Hash of types declared by the service
|
@@ -54,9 +50,14 @@ module LolSoap
|
|
54
50
|
@types.fetch(name) { NullType.new }
|
55
51
|
end
|
56
52
|
|
57
|
-
#
|
58
|
-
def
|
59
|
-
|
53
|
+
# Hash of operations that are supports by the SOAP service
|
54
|
+
def operations
|
55
|
+
@operations.dup
|
56
|
+
end
|
57
|
+
|
58
|
+
# Get a single operation
|
59
|
+
def operation(name)
|
60
|
+
@operations.fetch(name)
|
60
61
|
end
|
61
62
|
|
62
63
|
def inspect
|
@@ -68,39 +69,75 @@ module LolSoap
|
|
68
69
|
|
69
70
|
private
|
70
71
|
|
72
|
+
# @private
|
73
|
+
def load_types(parser)
|
74
|
+
Hash[
|
75
|
+
parser.types.map do |prefixed_name, type|
|
76
|
+
[prefixed_name, build_type(type)]
|
77
|
+
end
|
78
|
+
]
|
79
|
+
end
|
80
|
+
|
71
81
|
# @private
|
72
82
|
def load_operations(parser)
|
73
83
|
Hash[
|
74
84
|
parser.operations.map do |k, op|
|
75
|
-
[k, Operation.new(self, op[:action],
|
85
|
+
[k, Operation.new(self, op[:action], message_format(op[:input], parser), message_format(op[:output], parser))]
|
76
86
|
end
|
77
87
|
]
|
78
88
|
end
|
79
89
|
|
80
90
|
# @private
|
81
|
-
def
|
91
|
+
def load_type_namespaces(parser)
|
82
92
|
Hash[
|
83
|
-
parser.types.map do |
|
84
|
-
[
|
85
|
-
prefixed_name,
|
86
|
-
Type.new(
|
87
|
-
type[:name],
|
88
|
-
type[:prefix],
|
89
|
-
build_elements(type[:elements]),
|
90
|
-
type[:attributes]
|
91
|
-
)
|
92
|
-
]
|
93
|
+
parser.types.merge(parser.elements).values.map do |el|
|
94
|
+
[el[:prefix], namespaces[el[:prefix]]]
|
93
95
|
end
|
94
96
|
]
|
95
97
|
end
|
96
98
|
|
99
|
+
# @private
|
100
|
+
def build_type(params)
|
101
|
+
Type.new(
|
102
|
+
params[:name],
|
103
|
+
params[:prefix],
|
104
|
+
build_elements(params[:elements]),
|
105
|
+
params[:attributes]
|
106
|
+
)
|
107
|
+
end
|
108
|
+
|
97
109
|
# @private
|
98
110
|
def build_elements(elements)
|
99
111
|
Hash[
|
100
112
|
elements.map do |name, el|
|
101
|
-
[name,
|
113
|
+
[name, build_element(el)]
|
102
114
|
end
|
103
115
|
]
|
104
116
|
end
|
117
|
+
|
118
|
+
# @private
|
119
|
+
def build_element(params)
|
120
|
+
Element.new(
|
121
|
+
self,
|
122
|
+
params[:name],
|
123
|
+
params[:prefix],
|
124
|
+
type_reference(params[:type]),
|
125
|
+
params[:singular]
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
# @private
|
130
|
+
def type_reference(type)
|
131
|
+
if type.respond_to?(:to_str)
|
132
|
+
NamedTypeReference.new(type, self)
|
133
|
+
else
|
134
|
+
ImmediateTypeReference.new(build_type(type))
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# @private
|
139
|
+
def message_format(element, parser)
|
140
|
+
build_element(parser.elements[element])
|
141
|
+
end
|
105
142
|
end
|
106
143
|
end
|
data/lib/lolsoap/wsdl/element.rb
CHANGED
@@ -1,24 +1,29 @@
|
|
1
1
|
class LolSoap::WSDL
|
2
2
|
class Element
|
3
|
-
attr_reader :name
|
3
|
+
attr_reader :name, :prefix, :type_reference
|
4
4
|
|
5
|
-
def initialize(wsdl, name,
|
6
|
-
@wsdl
|
7
|
-
@name
|
8
|
-
@
|
9
|
-
@
|
5
|
+
def initialize(wsdl, name, prefix, type_reference, singular = true)
|
6
|
+
@wsdl = wsdl
|
7
|
+
@name = name
|
8
|
+
@prefix = prefix
|
9
|
+
@type_reference = type_reference
|
10
|
+
@singular = singular
|
11
|
+
end
|
12
|
+
|
13
|
+
def type
|
14
|
+
type_reference.type
|
10
15
|
end
|
11
16
|
|
12
17
|
def singular?
|
13
18
|
@singular == true
|
14
19
|
end
|
15
20
|
|
16
|
-
def
|
17
|
-
|
21
|
+
def inspect
|
22
|
+
"<#{self.class} name=#{prefix_and_name.inspect} type=#{type.to_s.inspect}>"
|
18
23
|
end
|
19
24
|
|
20
|
-
def
|
21
|
-
"
|
25
|
+
def prefix_and_name
|
26
|
+
"#{prefix}:#{name}"
|
22
27
|
end
|
23
28
|
|
24
29
|
private
|
data/lib/lolsoap/wsdl/type.rb
CHANGED
@@ -19,6 +19,10 @@ class LolSoap::WSDL
|
|
19
19
|
@elements.fetch(name) { NullElement.new }
|
20
20
|
end
|
21
21
|
|
22
|
+
def element_prefix(name)
|
23
|
+
@elements.fetch(name, self).prefix
|
24
|
+
end
|
25
|
+
|
22
26
|
def sub_type(name)
|
23
27
|
element(name).type
|
24
28
|
end
|
@@ -32,9 +36,13 @@ class LolSoap::WSDL
|
|
32
36
|
end
|
33
37
|
|
34
38
|
def inspect
|
35
|
-
"<#{self.class} name=\"#{
|
39
|
+
"<#{self.class} name=\"#{prefix_and_name.inspect}\" " \
|
36
40
|
"elements=#{elements.inspect} " \
|
37
41
|
"attributes=#{attributes.inspect}>"
|
38
42
|
end
|
43
|
+
|
44
|
+
def prefix_and_name
|
45
|
+
"#{prefix}:#{name}"
|
46
|
+
end
|
39
47
|
end
|
40
48
|
end
|
data/lib/lolsoap/wsdl_parser.rb
CHANGED
@@ -3,7 +3,7 @@ require 'nokogiri'
|
|
3
3
|
module LolSoap
|
4
4
|
# @private
|
5
5
|
class WSDLParser
|
6
|
-
class
|
6
|
+
class Node
|
7
7
|
attr_reader :parser, :node, :target_namespace, :name, :prefix
|
8
8
|
|
9
9
|
def initialize(parser, node, target_namespace)
|
@@ -17,28 +17,84 @@ module LolSoap
|
|
17
17
|
"#{prefix}:#{name}"
|
18
18
|
end
|
19
19
|
|
20
|
+
def prefix_and_name(string)
|
21
|
+
parser.prefix_and_name(string, target_namespace)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Element < Node
|
26
|
+
def type
|
27
|
+
if complex_type = node.at_xpath('xs:complexType', parser.ns)
|
28
|
+
type = Type.new(parser, complex_type, target_namespace)
|
29
|
+
{
|
30
|
+
:elements => type.elements,
|
31
|
+
:attributes => type.attributes
|
32
|
+
}
|
33
|
+
else
|
34
|
+
prefix_and_name(node.attr('type').to_s).join(':')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def singular
|
39
|
+
max_occurs.empty? || max_occurs == '1'
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def max_occurs
|
45
|
+
@max_occurs ||= node.attribute('maxOccurs').to_s
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Type < Node
|
20
50
|
def elements
|
21
|
-
|
22
|
-
|
23
|
-
|
51
|
+
parent_elements.merge(own_elements)
|
52
|
+
end
|
53
|
+
|
54
|
+
def attributes
|
55
|
+
parent_attributes + own_attributes
|
56
|
+
end
|
57
|
+
|
58
|
+
def base_type
|
59
|
+
@base_type ||= begin
|
60
|
+
if extension = node.at_xpath('xs:complexContent/xs:extension/@base', parser.ns)
|
61
|
+
parser.type(extension.to_s)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
24
67
|
|
68
|
+
def own_elements
|
69
|
+
Hash[
|
70
|
+
element_nodes.map do |element|
|
25
71
|
[
|
26
|
-
|
72
|
+
element.name,
|
27
73
|
{
|
28
|
-
:
|
29
|
-
:
|
74
|
+
:name => element.name,
|
75
|
+
:prefix => element.prefix,
|
76
|
+
:type => element.type,
|
77
|
+
:singular => element.singular
|
30
78
|
}
|
31
79
|
]
|
32
80
|
end
|
33
81
|
]
|
34
82
|
end
|
35
83
|
|
36
|
-
def
|
37
|
-
node.xpath('
|
84
|
+
def element_nodes
|
85
|
+
node.xpath('*/xs:element | */*/xs:element | xs:complexContent/xs:extension/*/xs:element | xs:complexContent/xs:extension/*/*/xs:element', parser.ns).map { |el| Element.new(parser, el, target_namespace) }
|
38
86
|
end
|
39
87
|
|
40
|
-
def
|
41
|
-
|
88
|
+
def parent_elements
|
89
|
+
base_type ? base_type.elements : {}
|
90
|
+
end
|
91
|
+
|
92
|
+
def own_attributes
|
93
|
+
node.xpath('xs:attribute/@name | */xs:extension/xs:attribute/@name', parser.ns).map(&:text)
|
94
|
+
end
|
95
|
+
|
96
|
+
def parent_attributes
|
97
|
+
base_type ? base_type.attributes : []
|
42
98
|
end
|
43
99
|
end
|
44
100
|
|
@@ -79,24 +135,41 @@ module LolSoap
|
|
79
135
|
def types
|
80
136
|
@types ||= begin
|
81
137
|
types = {}
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
type
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
:prefix => type.prefix,
|
91
|
-
:elements => type.elements,
|
92
|
-
:attributes => type.attributes
|
93
|
-
}
|
94
|
-
end
|
138
|
+
each_node('xs:complexType[not(@abstract)]') do |node, target_ns|
|
139
|
+
type = Type.new(self, node, target_ns)
|
140
|
+
types[type.name_with_prefix] = {
|
141
|
+
:name => type.name,
|
142
|
+
:prefix => type.prefix,
|
143
|
+
:elements => type.elements,
|
144
|
+
:attributes => type.attributes
|
145
|
+
}
|
95
146
|
end
|
96
147
|
types
|
97
148
|
end
|
98
149
|
end
|
99
150
|
|
151
|
+
def type(name)
|
152
|
+
name = prefix_and_name(name).last
|
153
|
+
node = doc.at_xpath("//xs:complexType[@name='#{name}']", ns)
|
154
|
+
target_namespace = node.at_xpath('parent::xs:schema/@targetNamespace', ns).to_s
|
155
|
+
Type.new(self, node, target_namespace)
|
156
|
+
end
|
157
|
+
|
158
|
+
def elements
|
159
|
+
@elements ||= begin
|
160
|
+
elements = {}
|
161
|
+
each_node('xs:element') do |node, target_ns|
|
162
|
+
element = Element.new(self, node, target_ns)
|
163
|
+
elements[element.name_with_prefix] = {
|
164
|
+
:name => element.name,
|
165
|
+
:prefix => element.prefix,
|
166
|
+
:type => element.type
|
167
|
+
}
|
168
|
+
end
|
169
|
+
elements
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
100
173
|
def messages
|
101
174
|
@messages ||= Hash[
|
102
175
|
doc.xpath('/d:definitions/d:message', ns).map do |msg|
|
@@ -165,5 +238,15 @@ module LolSoap
|
|
165
238
|
|
166
239
|
[prefix, name]
|
167
240
|
end
|
241
|
+
|
242
|
+
def each_node(xpath)
|
243
|
+
schemas.each do |schema|
|
244
|
+
target_namespace = schema.attr('targetNamespace').to_s
|
245
|
+
|
246
|
+
schema.xpath(xpath, ns).each do |node|
|
247
|
+
yield node, target_namespace
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
168
251
|
end
|
169
252
|
end
|
data/lolsoap.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "lolsoap"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jon Leighton"]
|
12
|
-
s.date = "2013-
|
12
|
+
s.date = "2013-06-24"
|
13
13
|
s.description = "A library for dealing with SOAP requests and responses. We tear our hair out so you don't have to."
|
14
14
|
s.email = "j@jonathanleighton.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -37,6 +37,8 @@ Gem::Specification.new do |s|
|
|
37
37
|
"lib/lolsoap/response.rb",
|
38
38
|
"lib/lolsoap/wsdl.rb",
|
39
39
|
"lib/lolsoap/wsdl/element.rb",
|
40
|
+
"lib/lolsoap/wsdl/immediate_type_reference.rb",
|
41
|
+
"lib/lolsoap/wsdl/named_type_reference.rb",
|
40
42
|
"lib/lolsoap/wsdl/null_element.rb",
|
41
43
|
"lib/lolsoap/wsdl/null_type.rb",
|
42
44
|
"lib/lolsoap/wsdl/operation.rb",
|
@@ -20,12 +20,48 @@
|
|
20
20
|
</all>
|
21
21
|
</complexType>
|
22
22
|
</element>
|
23
|
-
<
|
23
|
+
<element name="tradePriceRequest" type="TradePriceRequest" />
|
24
|
+
<complexType name="xsd1:TradePriceRequest">
|
25
|
+
<complexContent>
|
26
|
+
<extension base="xsd1:BaseRequest">
|
27
|
+
<sequence>
|
28
|
+
<element name="tickerSymbol" type="xs:string" maxOccurs="5"/>
|
29
|
+
<element name="specialTickerSymbol" type="xsd2:TickerSymbol" maxOccurs="unbounded"/>
|
30
|
+
</sequence>
|
31
|
+
<attribute name="id" type="xs:string"/>
|
32
|
+
</extension>
|
33
|
+
</complexContent>
|
34
|
+
</complexType>
|
35
|
+
<element name="xsd1:HistoricalPrice">
|
36
|
+
<complexType>
|
37
|
+
<sequence>
|
38
|
+
<element name="date" type="xs:date"/>
|
39
|
+
<element name="price" type="xs:float"/>
|
40
|
+
</sequence>
|
41
|
+
</complexType>
|
42
|
+
</element>
|
43
|
+
<element name="historicalPriceRequest" type="HistoricalPriceRequest" />
|
44
|
+
<complexType name="xsd1:HistoricalPriceRequest">
|
45
|
+
<complexContent>
|
46
|
+
<extension base="xsd1:BaseRequest">
|
47
|
+
<sequence>
|
48
|
+
<element name="dateRange">
|
49
|
+
<complexType>
|
50
|
+
<sequence>
|
51
|
+
<element name="startDate" maxOccurs="1" type="xs:string" />
|
52
|
+
<element name="endDate" maxOccurs="1" type="xs:string" />
|
53
|
+
</sequence>
|
54
|
+
</complexType>
|
55
|
+
</element>
|
56
|
+
</sequence>
|
57
|
+
</extension>
|
58
|
+
</complexContent>
|
59
|
+
</complexType>
|
60
|
+
<complexType abstract="true" name="BaseRequest">
|
24
61
|
<sequence>
|
25
|
-
<element name="
|
26
|
-
<element name="specialTickerSymbol" type="xsd2:TickerSymbol" maxOccurs="unbounded"/>
|
27
|
-
<attribute name="id" type="xs:string"/>
|
62
|
+
<element name="accountId" type="xs:string" maxOccurs="1"/>
|
28
63
|
</sequence>
|
64
|
+
<attribute name="signature" type="xs:string"/>
|
29
65
|
</complexType>
|
30
66
|
</schema>
|
31
67
|
|
@@ -40,18 +76,30 @@
|
|
40
76
|
</types>
|
41
77
|
|
42
78
|
<message name="GetLastTradePriceInput">
|
43
|
-
<part name="body" element="xsd1:
|
79
|
+
<part name="body" element="xsd1:tradePriceRequest"/>
|
44
80
|
</message>
|
45
81
|
|
46
82
|
<message name="GetLastTradePriceOutput">
|
47
83
|
<part name="body" element="xsd3:TradePrice"/>
|
48
84
|
</message>
|
49
85
|
|
86
|
+
<message name="GetHistoricalPriceInput">
|
87
|
+
<part name="body" element="xsd1:historicalPriceRequest"/>
|
88
|
+
</message>
|
89
|
+
|
90
|
+
<message name="GetHistoricalPriceOutput">
|
91
|
+
<part name="body" element="xsd1:HistoricalPrice"/>
|
92
|
+
</message>
|
93
|
+
|
50
94
|
<portType name="StockQuotePortType">
|
51
95
|
<operation name="GetLastTradePrice">
|
52
96
|
<input message="tns:GetLastTradePriceInput"/>
|
53
97
|
<output message="tns:GetLastTradePriceOutput"/>
|
54
98
|
</operation>
|
99
|
+
<operation name="GetHistoricalPrice">
|
100
|
+
<input message="tns:GetHistoricalPriceInput"/>
|
101
|
+
<output message="tns:GetHistoricalPriceOutput"/>
|
102
|
+
</operation>
|
55
103
|
</portType>
|
56
104
|
|
57
105
|
<binding name="StockQuoteSoapBinding" type="tns:StockQuotePortType">
|
@@ -65,6 +113,15 @@
|
|
65
113
|
<soap:body use="literal"/>
|
66
114
|
</output>
|
67
115
|
</operation>
|
116
|
+
<operation name="GetHistoricalPrice">
|
117
|
+
<soap:operation soapAction="http://example.com/GetHistoricalPrice"/>
|
118
|
+
<input>
|
119
|
+
<soap:body use="literal"/>
|
120
|
+
</input>
|
121
|
+
<output>
|
122
|
+
<soap:body use="literal"/>
|
123
|
+
</output>
|
124
|
+
</operation>
|
68
125
|
</binding>
|
69
126
|
|
70
127
|
<service name="StockQuoteService">
|
@@ -10,7 +10,7 @@ module LolSoap
|
|
10
10
|
let(:doc) { subject.doc }
|
11
11
|
|
12
12
|
it 'creates an empty envelope' do
|
13
|
-
body = doc.at_xpath('/soap:Envelope/soap:Body/xsd1:
|
13
|
+
body = doc.at_xpath('/soap:Envelope/soap:Body/xsd1:tradePriceRequest', doc.namespaces)
|
14
14
|
body.wont_equal nil
|
15
15
|
end
|
16
16
|
|
@@ -24,15 +24,15 @@ module LolSoap
|
|
24
24
|
b.id 42
|
25
25
|
end
|
26
26
|
|
27
|
-
el = doc.at_xpath('//xsd1:
|
27
|
+
el = doc.at_xpath('//xsd1:tradePriceRequest/xsd1:tickerSymbol', doc.namespaces)
|
28
28
|
el.wont_equal nil
|
29
29
|
el.text.to_s.must_equal 'LOCO2'
|
30
30
|
|
31
|
-
el = doc.at_xpath('//xsd1:
|
31
|
+
el = doc.at_xpath('//xsd1:tradePriceRequest/xsd1:specialTickerSymbol/xsd2:name', doc.namespaces)
|
32
32
|
el.wont_equal nil
|
33
33
|
el.text.to_s.must_equal 'LOCOLOCOLOCO'
|
34
34
|
|
35
|
-
attr = doc.at_xpath('//xsd1:
|
35
|
+
attr = doc.at_xpath('//xsd1:tradePriceRequest/@id', doc.namespaces)
|
36
36
|
attr.to_s.must_equal "42"
|
37
37
|
end
|
38
38
|
|
@@ -6,10 +6,10 @@ module LolSoap
|
|
6
6
|
subject { WSDL.parse(File.read(TEST_ROOT + '/fixtures/stock_quote.wsdl')) }
|
7
7
|
|
8
8
|
it 'should successfully parse a WSDL document' do
|
9
|
-
subject.operations.length.must_equal
|
9
|
+
subject.operations.length.must_equal 2
|
10
10
|
subject.operations['GetLastTradePrice'].tap do |o|
|
11
|
-
o.input.must_equal
|
12
|
-
o.action.must_equal
|
11
|
+
o.input.name.must_equal 'tradePriceRequest'
|
12
|
+
o.action.must_equal 'http://example.com/GetLastTradePrice'
|
13
13
|
end
|
14
14
|
|
15
15
|
subject.types.length.must_equal 3
|
data/test/unit/test_builder.rb
CHANGED
@@ -15,6 +15,10 @@ module LolSoap
|
|
15
15
|
end
|
16
16
|
let(:type) do
|
17
17
|
type = OpenStruct.new(:prefix => 'a')
|
18
|
+
def type.element_prefix(name)
|
19
|
+
@element_prefixes = { 'bar' => 'b' }
|
20
|
+
@element_prefixes.fetch(name) { 'a' }
|
21
|
+
end
|
18
22
|
def type.has_attribute?(*); false; end
|
19
23
|
def type.sub_type(name)
|
20
24
|
@sub_types ||= { 'foo' => Object.new, 'bar' => Object.new, 'clone' => Object.new }
|
@@ -47,7 +51,7 @@ module LolSoap
|
|
47
51
|
end
|
48
52
|
|
49
53
|
it 'yields to a block, if given' do
|
50
|
-
expect_node_added node.namespace_scopes[
|
54
|
+
expect_node_added node.namespace_scopes[0], 'bar' do
|
51
55
|
block = nil
|
52
56
|
ret = subject.__tag__(:bar) { |b| block = b }
|
53
57
|
block.object_id.must_equal ret.object_id
|
@@ -57,7 +61,7 @@ module LolSoap
|
|
57
61
|
|
58
62
|
describe 'method missing' do
|
59
63
|
it 'delegates to __tag__' do
|
60
|
-
expect_node_added node.namespace_scopes[
|
64
|
+
expect_node_added node.namespace_scopes[0], 'bar', 'baz' do
|
61
65
|
subject.bar 'baz'
|
62
66
|
end
|
63
67
|
end
|
@@ -67,6 +71,11 @@ module LolSoap
|
|
67
71
|
subject.clone
|
68
72
|
end
|
69
73
|
end
|
74
|
+
|
75
|
+
it 'sets content' do
|
76
|
+
subject.__content__ 'zomg'
|
77
|
+
node.content.must_equal 'zomg'
|
78
|
+
end
|
70
79
|
end
|
71
80
|
|
72
81
|
it 'responds to anything' do
|
@@ -91,6 +100,5 @@ module LolSoap
|
|
91
100
|
subject.__type__.must_equal type
|
92
101
|
end
|
93
102
|
end
|
94
|
-
|
95
103
|
end
|
96
104
|
end
|
data/test/unit/test_envelope.rb
CHANGED
@@ -106,16 +106,16 @@ module LolSoap
|
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
|
-
describe '#
|
109
|
+
describe '#input' do
|
110
110
|
it "returns the operation's input" do
|
111
|
-
subject.
|
111
|
+
subject.input.must_equal operation.input
|
112
112
|
end
|
113
113
|
end
|
114
114
|
|
115
115
|
describe '#output' do
|
116
116
|
it "returns the operation's output" do
|
117
117
|
operation.output = 'lol'
|
118
|
-
subject.
|
118
|
+
subject.output.must_equal 'lol'
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
data/test/unit/test_wsdl.rb
CHANGED
@@ -12,7 +12,7 @@ module LolSoap
|
|
12
12
|
:operations => {
|
13
13
|
'washHands' => {
|
14
14
|
:action => 'urn:washHands',
|
15
|
-
:input => 'bla:
|
15
|
+
:input => 'bla:brush',
|
16
16
|
:output => 'bla:Color'
|
17
17
|
}
|
18
18
|
},
|
@@ -20,30 +20,64 @@ module LolSoap
|
|
20
20
|
'bla:Brush' => {
|
21
21
|
:elements => {
|
22
22
|
'handleColor' => {
|
23
|
-
:
|
23
|
+
:name => 'handleColor',
|
24
|
+
:prefix => 'bla',
|
25
|
+
:type => {
|
26
|
+
:elements => {
|
27
|
+
'name' => {
|
28
|
+
:name => 'name',
|
29
|
+
:prefix => 'bla',
|
30
|
+
:type => 'xs:string',
|
31
|
+
:singular => true
|
32
|
+
},
|
33
|
+
'hex' => {
|
34
|
+
:name => 'hex',
|
35
|
+
:prefix => 'bla',
|
36
|
+
:type => 'xs:string',
|
37
|
+
:singular => true
|
38
|
+
}
|
39
|
+
},
|
40
|
+
:attributes => []
|
41
|
+
},
|
24
42
|
:singular => true
|
25
43
|
},
|
26
44
|
'age' => {
|
45
|
+
:name => 'age',
|
46
|
+
:prefix => 'bla',
|
27
47
|
:type => 'xs:int',
|
28
48
|
:singular => false
|
29
49
|
}
|
30
50
|
},
|
31
51
|
:attributes => ['id'],
|
32
52
|
:prefix => 'bla'
|
53
|
+
}
|
54
|
+
},
|
55
|
+
:elements => {
|
56
|
+
'bla:brush' => {
|
57
|
+
:name => 'brush',
|
58
|
+
:prefix => 'bla',
|
59
|
+
:type => 'bla:Brush'
|
33
60
|
},
|
34
61
|
'bla:Color' => {
|
35
|
-
:
|
36
|
-
|
37
|
-
|
38
|
-
|
62
|
+
:name => 'Color',
|
63
|
+
:prefix => 'bla',
|
64
|
+
:type => {
|
65
|
+
:elements => {
|
66
|
+
'name' => {
|
67
|
+
:name => 'name',
|
68
|
+
:prefix => 'bla',
|
69
|
+
:type => 'xs:string',
|
70
|
+
:singular => true
|
71
|
+
},
|
72
|
+
'hex' => {
|
73
|
+
:name => 'hex',
|
74
|
+
:prefix => 'bla',
|
75
|
+
:type => 'xs:string',
|
76
|
+
:singular => true
|
77
|
+
}
|
39
78
|
},
|
40
|
-
|
41
|
-
|
42
|
-
:singular => true
|
43
|
-
}
|
44
|
-
},
|
45
|
-
:attributes => [],
|
46
|
-
:prefix => 'bla'
|
79
|
+
:attributes => []
|
80
|
+
}
|
47
81
|
}
|
48
82
|
}
|
49
83
|
)
|
@@ -55,10 +89,13 @@ module LolSoap
|
|
55
89
|
it 'returns a hash of operations' do
|
56
90
|
subject.operations.length.must_equal 1
|
57
91
|
subject.operations['washHands'].tap do |op|
|
58
|
-
op.wsdl.must_equal
|
59
|
-
op.action.must_equal
|
60
|
-
op.input.must_equal
|
61
|
-
op.output.
|
92
|
+
op.wsdl.must_equal subject
|
93
|
+
op.action.must_equal 'urn:washHands'
|
94
|
+
op.input.name.must_equal 'brush'
|
95
|
+
op.output.tap do |output|
|
96
|
+
output.is_a?(WSDL::Element).must_equal(true)
|
97
|
+
output.type.elements.keys.sort.must_equal %w(hex name)
|
98
|
+
end
|
62
99
|
end
|
63
100
|
end
|
64
101
|
end
|
@@ -84,28 +121,26 @@ module LolSoap
|
|
84
121
|
|
85
122
|
describe '#types' do
|
86
123
|
it 'returns a hash of types' do
|
87
|
-
subject.types.length.must_equal
|
124
|
+
subject.types.length.must_equal 1
|
88
125
|
|
89
126
|
subject.types['bla:Brush'].tap do |t|
|
90
127
|
t.elements.length.must_equal 2
|
91
|
-
t.element('handleColor').type.
|
128
|
+
t.element('handleColor').type.tap do |type|
|
129
|
+
type.is_a?(WSDL::Type).must_equal true
|
130
|
+
type.elements.keys.sort.must_equal %w(hex name)
|
131
|
+
end
|
132
|
+
t.element('handleColor').prefix.must_equal 'bla'
|
92
133
|
t.element('handleColor').singular?.must_equal true
|
93
134
|
t.element('age').type.must_equal WSDL::NullType.new
|
94
135
|
t.element('age').singular?.must_equal false
|
95
136
|
t.attributes.must_equal ['id']
|
96
137
|
end
|
97
|
-
|
98
|
-
subject.types['bla:Color'].tap do |t|
|
99
|
-
t.elements.length.must_equal 2
|
100
|
-
t.element('name').type.must_equal WSDL::NullType.new
|
101
|
-
t.element('hex').type.must_equal WSDL::NullType.new
|
102
|
-
end
|
103
138
|
end
|
104
139
|
end
|
105
140
|
|
106
141
|
describe '#type' do
|
107
142
|
it 'returns a single type' do
|
108
|
-
subject.type('bla:
|
143
|
+
subject.type('bla:Brush').must_equal subject.types['bla:Brush']
|
109
144
|
end
|
110
145
|
|
111
146
|
it 'returns a null object if a type is missing' do
|
@@ -37,33 +37,69 @@ module LolSoap
|
|
37
37
|
:prefix => 'xsd1',
|
38
38
|
:name => 'TradePriceRequest',
|
39
39
|
:elements => {
|
40
|
+
'accountId' => {
|
41
|
+
:name => 'accountId',
|
42
|
+
:prefix => 'xsd1',
|
43
|
+
:type => 'xs:string',
|
44
|
+
:singular => true
|
45
|
+
},
|
40
46
|
'tickerSymbol' => {
|
47
|
+
:name => 'tickerSymbol',
|
48
|
+
:prefix => 'xsd1',
|
41
49
|
:type => 'xs:string',
|
42
50
|
:singular => false
|
43
51
|
},
|
44
52
|
'specialTickerSymbol' => {
|
53
|
+
:name => 'specialTickerSymbol',
|
54
|
+
:prefix => 'xsd1',
|
45
55
|
:type => 'xsd2:TickerSymbol',
|
46
56
|
:singular => false
|
47
57
|
}
|
48
58
|
},
|
49
|
-
:attributes => ['id']
|
59
|
+
:attributes => ['signature', 'id']
|
50
60
|
},
|
51
|
-
'xsd1:
|
61
|
+
'xsd1:HistoricalPriceRequest' => {
|
52
62
|
:prefix => 'xsd1',
|
53
|
-
:name => '
|
63
|
+
:name => 'HistoricalPriceRequest',
|
54
64
|
:elements => {
|
55
|
-
'
|
56
|
-
:
|
65
|
+
'accountId' => {
|
66
|
+
:name => 'accountId',
|
67
|
+
:prefix => 'xsd1',
|
68
|
+
:type => 'xs:string',
|
69
|
+
:singular => true
|
70
|
+
},
|
71
|
+
'dateRange' => {
|
72
|
+
:name => 'dateRange',
|
73
|
+
:prefix => 'xsd1',
|
74
|
+
:type => {
|
75
|
+
:elements => {
|
76
|
+
'startDate' => {
|
77
|
+
:name => 'startDate',
|
78
|
+
:prefix => 'xsd1',
|
79
|
+
:type => 'xs:string',
|
80
|
+
:singular => true
|
81
|
+
},
|
82
|
+
'endDate' => {
|
83
|
+
:name => 'endDate',
|
84
|
+
:prefix => 'xsd1',
|
85
|
+
:type => 'xs:string',
|
86
|
+
:singular => true
|
87
|
+
}
|
88
|
+
},
|
89
|
+
:attributes => []
|
90
|
+
},
|
57
91
|
:singular => true
|
58
92
|
}
|
59
93
|
},
|
60
|
-
:attributes => []
|
94
|
+
:attributes => ['signature']
|
61
95
|
},
|
62
96
|
'xsd2:TickerSymbol' => {
|
63
97
|
:prefix => 'xsd2',
|
64
98
|
:name => 'TickerSymbol',
|
65
99
|
:elements => {
|
66
100
|
'name' => {
|
101
|
+
:name => 'name',
|
102
|
+
:prefix => 'xsd2',
|
67
103
|
:type => 'xs:string',
|
68
104
|
:singular => true
|
69
105
|
}
|
@@ -74,11 +110,66 @@ module LolSoap
|
|
74
110
|
end
|
75
111
|
end
|
76
112
|
|
113
|
+
describe '#elements' do
|
114
|
+
it 'returns the elements with inline types' do
|
115
|
+
subject.elements.must_equal({
|
116
|
+
"xsd1:tradePriceRequest" => {
|
117
|
+
:name => "tradePriceRequest",
|
118
|
+
:prefix => "xsd1",
|
119
|
+
:type => "xsd1:TradePriceRequest"
|
120
|
+
},
|
121
|
+
"xsd1:TradePrice" => {
|
122
|
+
:name => "TradePrice",
|
123
|
+
:prefix => "xsd1",
|
124
|
+
:type => {
|
125
|
+
:elements => {
|
126
|
+
'price' => {
|
127
|
+
:name => 'price',
|
128
|
+
:prefix => 'xsd1',
|
129
|
+
:type => 'xs:float',
|
130
|
+
:singular => true
|
131
|
+
}
|
132
|
+
},
|
133
|
+
:attributes => []
|
134
|
+
}
|
135
|
+
},
|
136
|
+
"xsd1:historicalPriceRequest" => {
|
137
|
+
:name => "historicalPriceRequest",
|
138
|
+
:prefix => "xsd1",
|
139
|
+
:type => "xsd1:HistoricalPriceRequest"
|
140
|
+
},
|
141
|
+
"xsd1:HistoricalPrice" => {
|
142
|
+
:name => "HistoricalPrice",
|
143
|
+
:prefix => "xsd1",
|
144
|
+
:type => {
|
145
|
+
:elements => {
|
146
|
+
'date' => {
|
147
|
+
:name => 'date',
|
148
|
+
:prefix => 'xsd1',
|
149
|
+
:type => 'xs:date',
|
150
|
+
:singular => true
|
151
|
+
},
|
152
|
+
'price' => {
|
153
|
+
:name => 'price',
|
154
|
+
:prefix => 'xsd1',
|
155
|
+
:type => 'xs:float',
|
156
|
+
:singular => true
|
157
|
+
}
|
158
|
+
},
|
159
|
+
:attributes => []
|
160
|
+
}
|
161
|
+
}
|
162
|
+
})
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
77
166
|
describe '#messages' do
|
78
167
|
it 'maps message names to types' do
|
79
168
|
subject.messages.must_equal({
|
80
|
-
'GetLastTradePriceInput'
|
81
|
-
'GetLastTradePriceOutput'
|
169
|
+
'GetLastTradePriceInput' => 'xsd1:tradePriceRequest',
|
170
|
+
'GetLastTradePriceOutput' => 'xsd1:TradePrice',
|
171
|
+
'GetHistoricalPriceInput' => 'xsd1:historicalPriceRequest',
|
172
|
+
'GetHistoricalPriceOutput' => 'xsd1:HistoricalPrice'
|
82
173
|
})
|
83
174
|
end
|
84
175
|
end
|
@@ -87,8 +178,12 @@ module LolSoap
|
|
87
178
|
it 'is a hash containing input and output types' do
|
88
179
|
subject.port_type_operations.must_equal({
|
89
180
|
'GetLastTradePrice' => {
|
90
|
-
:input => 'xsd1:
|
181
|
+
:input => 'xsd1:tradePriceRequest',
|
91
182
|
:output => 'xsd1:TradePrice'
|
183
|
+
},
|
184
|
+
'GetHistoricalPrice' => {
|
185
|
+
:input => 'xsd1:historicalPriceRequest',
|
186
|
+
:output => 'xsd1:HistoricalPrice'
|
92
187
|
}
|
93
188
|
})
|
94
189
|
end
|
@@ -99,8 +194,13 @@ module LolSoap
|
|
99
194
|
subject.operations.must_equal({
|
100
195
|
'GetLastTradePrice' => {
|
101
196
|
:action => 'http://example.com/GetLastTradePrice',
|
102
|
-
:input => 'xsd1:
|
197
|
+
:input => 'xsd1:tradePriceRequest',
|
103
198
|
:output => 'xsd1:TradePrice'
|
199
|
+
},
|
200
|
+
'GetHistoricalPrice' => {
|
201
|
+
:action => 'http://example.com/GetHistoricalPrice',
|
202
|
+
:input => 'xsd1:historicalPriceRequest',
|
203
|
+
:output => 'xsd1:HistoricalPrice'
|
104
204
|
}
|
105
205
|
})
|
106
206
|
end
|
@@ -3,15 +3,18 @@ require 'lolsoap/wsdl'
|
|
3
3
|
|
4
4
|
class LolSoap::WSDL
|
5
5
|
describe Element do
|
6
|
-
let(:wsdl)
|
7
|
-
|
6
|
+
let(:wsdl) { MiniTest::Mock.new }
|
7
|
+
let(:type_reference) { MiniTest::Mock.new }
|
8
|
+
let(:type) { Object.new }
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
subject { Element.new(wsdl, 'bar', 'foo', type_reference, true) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
type_reference.expect(:type, type)
|
14
|
+
end
|
11
15
|
|
12
|
-
|
13
|
-
|
14
|
-
wsdl.expect(:type, type, ['WashHandsRequest'])
|
16
|
+
describe '#type' do
|
17
|
+
it 'returns the type via the reference' do
|
15
18
|
subject.type.must_equal type
|
16
19
|
end
|
17
20
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lolsoap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-06-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: nokogiri
|
@@ -120,6 +120,8 @@ files:
|
|
120
120
|
- lib/lolsoap/response.rb
|
121
121
|
- lib/lolsoap/wsdl.rb
|
122
122
|
- lib/lolsoap/wsdl/element.rb
|
123
|
+
- lib/lolsoap/wsdl/immediate_type_reference.rb
|
124
|
+
- lib/lolsoap/wsdl/named_type_reference.rb
|
123
125
|
- lib/lolsoap/wsdl/null_element.rb
|
124
126
|
- lib/lolsoap/wsdl/null_type.rb
|
125
127
|
- lib/lolsoap/wsdl/operation.rb
|
@@ -162,7 +164,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
162
164
|
version: '0'
|
163
165
|
segments:
|
164
166
|
- 0
|
165
|
-
hash:
|
167
|
+
hash: 413746061
|
166
168
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
167
169
|
none: false
|
168
170
|
requirements:
|