lolsoap 0.2.0 → 0.3.0

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
@@ -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.prefix, @type.sub_type(name.to_s), name, *args, &block)
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)
@@ -26,7 +26,7 @@ module LolSoap
26
26
  # b.some 'data'
27
27
  # end
28
28
  def body(klass = Builder)
29
- builder = klass.new(input, operation.input)
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 input_type
49
+ def input
50
50
  operation.input
51
51
  end
52
52
 
53
- def output_type
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 input; @input; end
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 = doc.create_element 'Body'
88
- @input = doc.create_element input_type.name
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
- @input.namespace = namespaces[input_type.prefix]
99
+ @content.namespace = namespaces[input.prefix]
92
100
 
93
- @body << @input
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 = load_types(parser)
30
- @operations = load_operations(parser)
31
- @endpoint = parser.endpoint
32
- @namespaces = parser.namespaces
33
- @prefixes = parser.prefixes
34
- @soap_version = parser.soap_version
35
- end
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
- # Namespaces used by the types (a subset of #namespaces)
58
- def type_namespaces
59
- Hash[@types.values.map { |type| [type.prefix, namespaces[type.prefix]] }]
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], type(op[:input]), type(op[:output]))]
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 load_types(parser)
91
+ def load_type_namespaces(parser)
82
92
  Hash[
83
- parser.types.map do |prefixed_name, type|
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, Element.new(self, name, el[:type], el[:singular])]
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
@@ -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, type_name, singular = true)
6
- @wsdl = wsdl
7
- @name = name
8
- @type_name = type_name
9
- @singular = singular
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 type
17
- @type ||= wsdl.type(@type_name)
21
+ def inspect
22
+ "<#{self.class} name=#{prefix_and_name.inspect} type=#{type.to_s.inspect}>"
18
23
  end
19
24
 
20
- def inspect
21
- "<#{self.class} name=#{name.inspect} type=#{@type_name.inspect}>"
25
+ def prefix_and_name
26
+ "#{prefix}:#{name}"
22
27
  end
23
28
 
24
29
  private
@@ -0,0 +1,9 @@
1
+ class LolSoap::WSDL
2
+ class ImmediateTypeReference
3
+ attr_reader :type
4
+
5
+ def initialize(type)
6
+ @type = type
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ class LolSoap::WSDL
2
+ class NamedTypeReference
3
+ attr_reader :name, :wsdl
4
+
5
+ def initialize(name, wsdl)
6
+ @name = name
7
+ @wsdl = wsdl
8
+ end
9
+
10
+ def type
11
+ wsdl.type(name)
12
+ end
13
+ end
14
+ end
@@ -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=\"#{prefix}:#{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
@@ -3,7 +3,7 @@ require 'nokogiri'
3
3
  module LolSoap
4
4
  # @private
5
5
  class WSDLParser
6
- class Type
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
- Hash[
22
- node.xpath('.//xs:element', parser.ns).map do |element|
23
- max_occurs = element.attribute('maxOccurs').to_s
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
- prefix_and_name(element.attr('name')).last,
72
+ element.name,
27
73
  {
28
- :type => prefix_and_name(element.attr('type')).join(':'),
29
- :singular => max_occurs.empty? || max_occurs == '1'
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 attributes
37
- node.xpath('.//xs:attribute/@name', parser.ns).map(&:text)
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 prefix_and_name(string)
41
- parser.prefix_and_name(string, target_namespace)
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
- schemas.each do |schema|
83
- target_namespace = schema.attr('targetNamespace').to_s
84
-
85
- schema.xpath('xs:element[@name] | xs:complexType[@name]', ns).each do |node|
86
- type = Type.new(self, node, target_namespace)
87
-
88
- types[type.name_with_prefix] = {
89
- :name => type.name,
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.2.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-05-15"
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
- <complexType name="xsd3:TradePriceRequest">
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="tickerSymbol" type="xs:string" maxOccurs="5"/>
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:TradePriceRequest"/>
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:TradePriceRequest', doc.namespaces)
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:TradePriceRequest/xsd1:tickerSymbol', doc.namespaces)
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:TradePriceRequest/xsd1:specialTickerSymbol/xsd2:name', doc.namespaces)
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:TradePriceRequest/@id', doc.namespaces)
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 1
9
+ subject.operations.length.must_equal 2
10
10
  subject.operations['GetLastTradePrice'].tap do |o|
11
- o.input.must_equal subject.types['xsd1:TradePriceRequest']
12
- o.action.must_equal 'http://example.com/GetLastTradePrice'
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
@@ -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[1], 'bar' do
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[1], 'bar', 'baz' do
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
@@ -106,16 +106,16 @@ module LolSoap
106
106
  end
107
107
  end
108
108
 
109
- describe '#input_type' do
109
+ describe '#input' do
110
110
  it "returns the operation's input" do
111
- subject.input_type.must_equal operation.input
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.output_type.must_equal 'lol'
118
+ subject.output.must_equal 'lol'
119
119
  end
120
120
  end
121
121
 
@@ -12,7 +12,7 @@ module LolSoap
12
12
  :operations => {
13
13
  'washHands' => {
14
14
  :action => 'urn:washHands',
15
- :input => 'bla:Brush',
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
- :type => 'bla:Color',
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
- :elements => {
36
- 'name' => {
37
- :type => 'xs:string',
38
- :singular => true
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
- 'hex' => {
41
- :type => 'xs:string',
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 subject
59
- op.action.must_equal "urn:washHands"
60
- op.input.must_equal subject.types['bla:Brush']
61
- op.output.must_equal subject.types['bla:Color']
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 2
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.must_equal subject.types['bla:Color']
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:Color').must_equal subject.types['bla:Color']
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:TradePrice' => {
61
+ 'xsd1:HistoricalPriceRequest' => {
52
62
  :prefix => 'xsd1',
53
- :name => 'TradePrice',
63
+ :name => 'HistoricalPriceRequest',
54
64
  :elements => {
55
- 'price' => {
56
- :type => 'xs:float',
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' => 'xsd1:TradePriceRequest',
81
- 'GetLastTradePriceOutput' => 'xsd1:TradePrice'
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:TradePriceRequest',
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:TradePriceRequest',
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) { OpenStruct.new }
7
- subject { Element.new(wsdl, 'foo', 'a:WashHandsRequest', true) }
6
+ let(:wsdl) { MiniTest::Mock.new }
7
+ let(:type_reference) { MiniTest::Mock.new }
8
+ let(:type) { Object.new }
8
9
 
9
- describe '#type' do
10
- let(:wsdl) { MiniTest::Mock.new }
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
- it 'ignores the namespace and gets the type from the wsdl' do
13
- type = Object.new
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.2.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-05-15 00:00:00.000000000 Z
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: 2454390744862534994
167
+ hash: 413746061
166
168
  required_rubygems_version: !ruby/object:Gem::Requirement
167
169
  none: false
168
170
  requirements: