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 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: