sekken 0.1.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.
Files changed (176) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.travis.yml +11 -0
  4. data/.yardopts +6 -0
  5. data/CONTRIBUTING.md +46 -0
  6. data/Gemfile +27 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +28 -0
  9. data/Rakefile +21 -0
  10. data/donate.png +0 -0
  11. data/lib/sekken.rb +75 -0
  12. data/lib/sekken/envelope.rb +92 -0
  13. data/lib/sekken/errors.rb +9 -0
  14. data/lib/sekken/example_message.rb +41 -0
  15. data/lib/sekken/httpclient.rb +35 -0
  16. data/lib/sekken/importer.rb +77 -0
  17. data/lib/sekken/message.rb +135 -0
  18. data/lib/sekken/operation.rb +100 -0
  19. data/lib/sekken/resolver.rb +20 -0
  20. data/lib/sekken/response.rb +50 -0
  21. data/lib/sekken/version.rb +5 -0
  22. data/lib/sekken/wsdl.rb +86 -0
  23. data/lib/sekken/wsdl/binding.rb +64 -0
  24. data/lib/sekken/wsdl/binding_operation.rb +85 -0
  25. data/lib/sekken/wsdl/document.rb +83 -0
  26. data/lib/sekken/wsdl/document_collection.rb +61 -0
  27. data/lib/sekken/wsdl/input_output.rb +84 -0
  28. data/lib/sekken/wsdl/message.rb +38 -0
  29. data/lib/sekken/wsdl/operation.rb +47 -0
  30. data/lib/sekken/wsdl/port.rb +29 -0
  31. data/lib/sekken/wsdl/port_type.rb +38 -0
  32. data/lib/sekken/wsdl/port_type_operation.rb +42 -0
  33. data/lib/sekken/wsdl/service.rb +55 -0
  34. data/lib/sekken/xml/attribute.rb +13 -0
  35. data/lib/sekken/xml/element.rb +82 -0
  36. data/lib/sekken/xml/element_builder.rb +220 -0
  37. data/lib/sekken/xs/schema.rb +57 -0
  38. data/lib/sekken/xs/schema_collection.rb +49 -0
  39. data/lib/sekken/xs/types.rb +272 -0
  40. data/sekken.gemspec +42 -0
  41. data/spec/fixtures/response/another_soap_fault.xml +14 -0
  42. data/spec/fixtures/response/authentication.xml +14 -0
  43. data/spec/fixtures/response/header.xml +13 -0
  44. data/spec/fixtures/response/list.xml +18 -0
  45. data/spec/fixtures/response/multi_ref.xml +39 -0
  46. data/spec/fixtures/response/soap_fault.xml +8 -0
  47. data/spec/fixtures/response/soap_fault12.xml +18 -0
  48. data/spec/fixtures/response/taxcloud.xml +1 -0
  49. data/spec/fixtures/wsdl/amazon.wsdl +1920 -0
  50. data/spec/fixtures/wsdl/arrays_with_attributes.wsdl +117 -0
  51. data/spec/fixtures/wsdl/authentication.wsdl +63 -0
  52. data/spec/fixtures/wsdl/awse.wsdl +1510 -0
  53. data/spec/fixtures/wsdl/betfair.wsdl +2981 -0
  54. data/spec/fixtures/wsdl/blz_service.wsdl +88 -0
  55. data/spec/fixtures/wsdl/bookt/bookt.wsdl +11 -0
  56. data/spec/fixtures/wsdl/bookt/bookt0.xsd +433 -0
  57. data/spec/fixtures/wsdl/bookt/bookt1.xsd +42 -0
  58. data/spec/fixtures/wsdl/bookt/bookt10.xsd +38 -0
  59. data/spec/fixtures/wsdl/bookt/bookt11.xsd +17 -0
  60. data/spec/fixtures/wsdl/bookt/bookt12.xsd +18 -0
  61. data/spec/fixtures/wsdl/bookt/bookt13.xsd +22 -0
  62. data/spec/fixtures/wsdl/bookt/bookt14.xsd +27 -0
  63. data/spec/fixtures/wsdl/bookt/bookt15.xsd +28 -0
  64. data/spec/fixtures/wsdl/bookt/bookt2.wsdl +243 -0
  65. data/spec/fixtures/wsdl/bookt/bookt2.xsd +81 -0
  66. data/spec/fixtures/wsdl/bookt/bookt3.wsdl +286 -0
  67. data/spec/fixtures/wsdl/bookt/bookt3.xsd +61 -0
  68. data/spec/fixtures/wsdl/bookt/bookt4.xsd +35 -0
  69. data/spec/fixtures/wsdl/bookt/bookt5.xsd +22 -0
  70. data/spec/fixtures/wsdl/bookt/bookt6.xsd +26 -0
  71. data/spec/fixtures/wsdl/bookt/bookt7.xsd +18 -0
  72. data/spec/fixtures/wsdl/bookt/bookt8.xsd +22 -0
  73. data/spec/fixtures/wsdl/bookt/bookt9.xsd +29 -0
  74. data/spec/fixtures/wsdl/bronto.wsdl +3285 -0
  75. data/spec/fixtures/wsdl/bydexchange/bydexchange.wsdl +104 -0
  76. data/spec/fixtures/wsdl/bydexchange/bydexchange0.xsd +1 -0
  77. data/spec/fixtures/wsdl/bydexchange/bydexchange1.xsd +1 -0
  78. data/spec/fixtures/wsdl/bydexchange/bydexchange2.wsdl +119 -0
  79. data/spec/fixtures/wsdl/bydexchange/bydexchange2.xsd +1 -0
  80. data/spec/fixtures/wsdl/bydexchange/bydexchange3.xsd +1 -0
  81. data/spec/fixtures/wsdl/bydexchange/bydexchange4.xsd +1 -0
  82. data/spec/fixtures/wsdl/bydexchange/bydexchange5.xsd +1 -0
  83. data/spec/fixtures/wsdl/bydexchange/bydexchange6.xsd +1 -0
  84. data/spec/fixtures/wsdl/bydexchange/bydexchange7.xsd +1 -0
  85. data/spec/fixtures/wsdl/bydexchange/bydexchange8.xsd +1 -0
  86. data/spec/fixtures/wsdl/crowd.wsdl +2437 -0
  87. data/spec/fixtures/wsdl/data_exchange.wsdl +98 -0
  88. data/spec/fixtures/wsdl/document_literal_wrapped.wsdl +153 -0
  89. data/spec/fixtures/wsdl/economic.wsdl +65660 -0
  90. data/spec/fixtures/wsdl/edialog.wsdl +13148 -0
  91. data/spec/fixtures/wsdl/email_verification.wsdl +394 -0
  92. data/spec/fixtures/wsdl/equifax.wsdl +794 -0
  93. data/spec/fixtures/wsdl/geotrust.wsdl +156 -0
  94. data/spec/fixtures/wsdl/interhome.wsdl +2137 -0
  95. data/spec/fixtures/wsdl/iws.wsdl +695 -0
  96. data/spec/fixtures/wsdl/jetairways.wsdl +156 -0
  97. data/spec/fixtures/wsdl/jira.wsdl +3890 -0
  98. data/spec/fixtures/wsdl/juniper.wsdl +215 -0
  99. data/spec/fixtures/wsdl/namespaced_actions.wsdl +307 -0
  100. data/spec/fixtures/wsdl/oracle.wsdl +3629 -0
  101. data/spec/fixtures/wsdl/ratp.wsdl +955 -0
  102. data/spec/fixtures/wsdl/rio2/rio2.wsdl +74 -0
  103. data/spec/fixtures/wsdl/rio2/rio2_0.wsdl +55 -0
  104. data/spec/fixtures/wsdl/rio2/rio2_0.xsd +58 -0
  105. data/spec/fixtures/wsdl/rio2/rio2_1.xsd +41 -0
  106. data/spec/fixtures/wsdl/rio2/rio2_2.xsd +222 -0
  107. data/spec/fixtures/wsdl/rio2/rio2_3.xsd +10 -0
  108. data/spec/fixtures/wsdl/rpc_literal.wsdl +105 -0
  109. data/spec/fixtures/wsdl/spyne.wsdl +70 -0
  110. data/spec/fixtures/wsdl/stockquote.wsdl +124 -0
  111. data/spec/fixtures/wsdl/taxcloud.wsdl +934 -0
  112. data/spec/fixtures/wsdl/team_software/team_software.wsdl +542 -0
  113. data/spec/fixtures/wsdl/team_software/team_software0.xsd +448 -0
  114. data/spec/fixtures/wsdl/team_software/team_software1.xsd +41 -0
  115. data/spec/fixtures/wsdl/team_software/team_software2.xsd +258 -0
  116. data/spec/fixtures/wsdl/team_software/team_software3.xsd +14 -0
  117. data/spec/fixtures/wsdl/telefonkatalogen.wsdl +45 -0
  118. data/spec/fixtures/wsdl/temperature.wsdl +136 -0
  119. data/spec/fixtures/wsdl/wasmuth/wasmuth.wsdl +157 -0
  120. data/spec/fixtures/wsdl/wasmuth/wasmuth1.xsd +210 -0
  121. data/spec/fixtures/wsdl/wasmuth/wasmuth2.xsd +549 -0
  122. data/spec/fixtures/wsdl/xignite.wsdl +3470 -0
  123. data/spec/fixtures/wsdl/yahoo.wsdl +2425 -0
  124. data/spec/fixtures/wsdl/zanox_export_service.xml +520 -0
  125. data/spec/integration/amazon_spec.rb +51 -0
  126. data/spec/integration/authentication_spec.rb +38 -0
  127. data/spec/integration/awse_spec.rb +95 -0
  128. data/spec/integration/betfair_spec.rb +179 -0
  129. data/spec/integration/blz_service_spec.rb +46 -0
  130. data/spec/integration/bookt_spec.rb +59 -0
  131. data/spec/integration/bronto_spec.rb +178 -0
  132. data/spec/integration/bydexchange_spec.rb +40 -0
  133. data/spec/integration/crowd_spec.rb +44 -0
  134. data/spec/integration/data_exchange_spec.rb +27 -0
  135. data/spec/integration/document_literal_spec.rb +104 -0
  136. data/spec/integration/economic_spec.rb +64 -0
  137. data/spec/integration/email_verification_spec.rb +82 -0
  138. data/spec/integration/equifax_spec.rb +216 -0
  139. data/spec/integration/geotrust_spec.rb +17 -0
  140. data/spec/integration/interhome_spec.rb +156 -0
  141. data/spec/integration/iws_spec.rb +27 -0
  142. data/spec/integration/jetairways_spec.rb +142 -0
  143. data/spec/integration/jira_spec.rb +27 -0
  144. data/spec/integration/juniper_spec.rb +20 -0
  145. data/spec/integration/namespaced_actions_spec.rb +37 -0
  146. data/spec/integration/oracle_spec.rb +61 -0
  147. data/spec/integration/ratp_spec.rb +178 -0
  148. data/spec/integration/rio2_spec.rb +56 -0
  149. data/spec/integration/rpc_literal_spec.rb +101 -0
  150. data/spec/integration/spyne_spec.rb +60 -0
  151. data/spec/integration/stockquote_spec.rb +46 -0
  152. data/spec/integration/taxcloud_spec.rb +45 -0
  153. data/spec/integration/team_software_spec.rb +51 -0
  154. data/spec/integration/telefonkatalogen_spec.rb +42 -0
  155. data/spec/integration/temperature_spec.rb +71 -0
  156. data/spec/integration/wasmuth_spec.rb +47 -0
  157. data/spec/integration/xignite_spec.rb +112 -0
  158. data/spec/integration/yahoo_spec.rb +116 -0
  159. data/spec/sekken/httpclient_spec.rb +41 -0
  160. data/spec/sekken/operation/build_spec.rb +308 -0
  161. data/spec/sekken/operation/document_literal_spec.rb +53 -0
  162. data/spec/sekken/operation/example_body_spec.rb +95 -0
  163. data/spec/sekken/operation/rpc_literal_spec.rb +50 -0
  164. data/spec/sekken/operation_spec.rb +169 -0
  165. data/spec/sekken/resolver_spec.rb +38 -0
  166. data/spec/sekken/response_spec.rb +17 -0
  167. data/spec/sekken/wsdl/document_spec.rb +191 -0
  168. data/spec/sekken/wsdl_spec.rb +46 -0
  169. data/spec/sekken/xs/complex_type_spec.rb +197 -0
  170. data/spec/sekken/xs/element_spec.rb +82 -0
  171. data/spec/sekken/xs/simple_type_spec.rb +39 -0
  172. data/spec/sekken_spec.rb +128 -0
  173. data/spec/spec_helper.rb +37 -0
  174. data/spec/support/fixture.rb +19 -0
  175. data/spec/support/http_mock.rb +43 -0
  176. metadata +344 -0
@@ -0,0 +1,77 @@
1
+ require 'nokogiri'
2
+ require 'sekken/wsdl/document'
3
+
4
+ class Sekken
5
+ class Importer
6
+
7
+ def initialize(resolver, documents, schemas)
8
+ @logger = Logging.logger[self]
9
+
10
+ @resolver = resolver
11
+ @documents = documents
12
+ @schemas = schemas
13
+ end
14
+
15
+ def import(location)
16
+ @import_locations = []
17
+
18
+ @logger.info("Resolving WSDL document #{location.inspect}.")
19
+ import_document(location) do |document|
20
+ @documents << document
21
+ @schemas.push(document.schemas)
22
+ end
23
+
24
+ # resolve xml schema imports
25
+ import_schemas do |schema_location|
26
+ @logger.info("Resolving XML schema import #{schema_location.inspect}.")
27
+
28
+ import_document(schema_location) do |document|
29
+ @schemas.push(document.schemas)
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def import_document(location, &block)
37
+ if @import_locations.include? location
38
+ @logger.info("Skipping already imported location #{location.inspect}.")
39
+ return
40
+ end
41
+
42
+ xml = @resolver.resolve(location)
43
+ @import_locations << location
44
+
45
+ document = WSDL::Document.new Nokogiri.XML(xml), @schemas
46
+ block.call(document)
47
+
48
+ # resolve wsdl imports
49
+ document.imports.each do |import_location|
50
+ @logger.info("Resolving WSDL import #{import_location.inspect}.")
51
+ import_document(import_location, &block)
52
+ end
53
+ end
54
+
55
+ def import_schemas
56
+ @schemas.each do |schema|
57
+ schema.imports.each do |namespace, schema_location|
58
+ next unless schema_location
59
+
60
+ unless absolute_url? schema_location
61
+ @logger.warn("Skipping XML Schema import #{schema_location.inspect}.")
62
+ next
63
+ end
64
+
65
+ # TODO: also skip if the schema was already imported
66
+
67
+ yield(schema_location)
68
+ end
69
+ end
70
+ end
71
+
72
+ def absolute_url?(location)
73
+ location =~ Resolver::URL_PATTERN
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,135 @@
1
+ require 'builder'
2
+
3
+ class Sekken
4
+ class Message
5
+
6
+ ATTRIBUTE_PREFIX = '_'
7
+
8
+ def initialize(envelope, parts)
9
+ @logger = Logging.logger[self]
10
+
11
+ @envelope = envelope
12
+ @parts = parts
13
+ end
14
+
15
+ def build(message)
16
+ builder = Builder::XmlMarkup.new(indent: 2, margin: 2)
17
+
18
+ build_elements(@parts, message.dup, builder)
19
+ builder.target!
20
+ end
21
+
22
+ private
23
+
24
+ def build_elements(elements, message, xml)
25
+ elements.each do |element|
26
+ name = element.name
27
+ symbol_name = name.to_sym
28
+
29
+ value = extract_value(name, symbol_name, message)
30
+
31
+ if value == :unspecified
32
+ @logger.debug("Skipping (optional?) element #{symbol_name.inspect} with no value.")
33
+ next
34
+ end
35
+
36
+ tag = [symbol_name]
37
+
38
+ if element.form == 'qualified'
39
+ nsid = @envelope.register_namespace(element.namespace)
40
+ tag.unshift(nsid)
41
+ end
42
+
43
+ case
44
+ when element.simple_type?
45
+ build_simple_type_element(element, xml, tag, value)
46
+
47
+ when element.complex_type?
48
+ build_complex_type_element(element, xml, tag, value)
49
+
50
+ end
51
+ end
52
+ end
53
+
54
+ def build_simple_type_element(element, xml, tag, value)
55
+ if element.singular?
56
+ if value.kind_of? Array
57
+ raise ArgumentError, "Unexpected Array for the #{tag.last.inspect} simple type"
58
+ end
59
+ if value.is_a? Hash
60
+ attributes, value = extract_attributes(value)
61
+ xml.tag! *tag, value[tag[1]], attributes
62
+ else
63
+ xml.tag! *tag, value
64
+ end
65
+ else
66
+ unless value.kind_of? Array
67
+ raise ArgumentError, "Expected an Array of values for the #{tag.last.inspect} simple type"
68
+ end
69
+
70
+ value.each do |val|
71
+ xml.tag! *tag, val
72
+ end
73
+ end
74
+ end
75
+
76
+ def build_complex_type_element(element, xml, tag, value)
77
+ if element.singular?
78
+ unless value.kind_of? Hash
79
+ raise ArgumentError, "Expected a Hash for the #{tag.last.inspect} complex type"
80
+ end
81
+
82
+ build_complex_tag(element, tag, value, xml)
83
+ else
84
+ unless value.kind_of? Array
85
+ raise ArgumentError, "Expected an Array of Hashes for the #{tag.last.inspect} complex type"
86
+ end
87
+
88
+ value.each do |val|
89
+ build_complex_tag(element, tag, val, xml)
90
+ end
91
+ end
92
+ end
93
+
94
+ def build_complex_tag(element, tag, value, xml)
95
+ attributes, value = extract_attributes(value)
96
+ children = element.children
97
+
98
+ if children.count > 0
99
+ xml.tag! *tag, attributes do |xml|
100
+ build_elements(children, value, xml)
101
+ end
102
+ elsif value && value[tag[1]]
103
+ xml.tag! *tag, value[tag[1]], attributes
104
+ else
105
+ xml.tag! *tag, attributes
106
+ end
107
+ end
108
+
109
+ # Private: extracts the value from the message by name or symbol_name.
110
+ # Respects nil values and returns a special symbol for actual missing values.
111
+ def extract_value(name, symbol_name, message)
112
+ if message.include? name
113
+ message[name]
114
+ elsif message.include? symbol_name
115
+ message[symbol_name]
116
+ else
117
+ :unspecified
118
+ end
119
+ end
120
+
121
+ def extract_attributes(hash)
122
+ attributes = {}
123
+
124
+ hash.dup.each do |k, v|
125
+ next unless k.to_s[0, 1] == ATTRIBUTE_PREFIX
126
+
127
+ attributes[k.to_s[1..-1]] = v
128
+ hash.delete(k)
129
+ end
130
+
131
+ [attributes, hash]
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,100 @@
1
+ require 'sekken/response'
2
+ require 'sekken/envelope'
3
+ require 'sekken/example_message'
4
+
5
+ class Sekken
6
+ class Operation
7
+
8
+ ENCODING = 'UTF-8'
9
+
10
+ CONTENT_TYPE = {
11
+ '1.1' => 'text/xml;charset=%s',
12
+ '1.2' => 'application/soap+xml;charset=%s'
13
+ }
14
+
15
+ def initialize(operation, wsdl, http)
16
+ @operation = operation
17
+ @wsdl = wsdl
18
+ @http = http
19
+
20
+ @endpoint = operation.endpoint
21
+ @soap_version = operation.soap_version
22
+ @soap_action = operation.soap_action
23
+ @encoding = ENCODING
24
+ end
25
+
26
+ # Public: Accessor for the SOAP endpoint.
27
+ attr_accessor :endpoint
28
+
29
+ # Public: Accessor for the SOAP version.
30
+ attr_accessor :soap_version
31
+
32
+ # Public: Accessor for the SOAPAction HTTP header.
33
+ attr_accessor :soap_action
34
+
35
+ # Public: Accessor for the encoding. Defaults to 'UTF-8'.
36
+ attr_accessor :encoding
37
+
38
+ # Public: Returns a Hash of HTTP headers to send.
39
+ def http_headers
40
+ return @http_headers if @http_headers
41
+ headers = {}
42
+
43
+ headers['SOAPAction'] = %{"#{soap_action}"} if soap_action
44
+ headers['Content-Type'] = CONTENT_TYPE[soap_version] % encoding
45
+
46
+ @http_headers = headers
47
+ end
48
+
49
+ # Public: Sets the Hash of HTTP headers.
50
+ attr_writer :http_headers
51
+
52
+ # Public: Sets the request header Hash.
53
+ attr_accessor :header
54
+
55
+ # Public: Create an example request header Hash.
56
+ def example_header
57
+ ExampleMessage.build(@operation.input.header_parts)
58
+ end
59
+
60
+ # Public: Sets the request body Hash.
61
+ attr_accessor :body
62
+
63
+ # Public: Create an example request body Hash.
64
+ def example_body
65
+ ExampleMessage.build(@operation.input.body_parts)
66
+ end
67
+
68
+ # Public: Returns the input body parts used to build the request body.
69
+ def body_parts
70
+ @operation.input.body_parts.inject([]) { |memo, part| memo + part.to_a }
71
+ end
72
+
73
+ # Public: Build the request XML for this operation.
74
+ def build
75
+ Envelope.new(@operation, header, body).to_s
76
+ end
77
+
78
+ # Public: Sets the request envelope XML. Use in place of body().
79
+ attr_accessor :xml_envelope
80
+
81
+ # Public: Call the operation.
82
+ def call
83
+ message = (xml_envelope != nil ? xml_envelope : build)
84
+
85
+ raw_response = @http.post(endpoint, http_headers, message)
86
+ Response.new(raw_response)
87
+ end
88
+
89
+ # Public: Returns the input style for this operation.
90
+ def input_style
91
+ @input_style ||= @operation.input_style
92
+ end
93
+
94
+ # Public: Returns the output style for this operation.
95
+ def output_style
96
+ @output_style ||= @operation.output_style
97
+ end
98
+
99
+ end
100
+ end
@@ -0,0 +1,20 @@
1
+ class Sekken
2
+ class Resolver
3
+
4
+ URL_PATTERN = /^http[s]?:/
5
+ XML_PATTERN = /^</
6
+
7
+ def initialize(http)
8
+ @http = http
9
+ end
10
+
11
+ def resolve(location)
12
+ case location
13
+ when URL_PATTERN then @http.get(location)
14
+ when XML_PATTERN then location
15
+ else File.read(location)
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,50 @@
1
+ require "nori"
2
+
3
+ class Sekken
4
+ class Response
5
+
6
+ def initialize(raw_response)
7
+ @raw_response = raw_response
8
+ end
9
+
10
+ def raw
11
+ @raw_response
12
+ end
13
+
14
+ def body
15
+ hash[:envelope][:body]
16
+ end
17
+ alias to_hash body
18
+
19
+ def header
20
+ hash[:envelope][:header]
21
+ end
22
+
23
+ def hash
24
+ @hash ||= nori.parse(raw)
25
+ end
26
+
27
+ def doc
28
+ @doc ||= Nokogiri.XML(raw)
29
+ end
30
+
31
+ def xpath(path, namespaces = nil)
32
+ doc.xpath(path, namespaces || xml_namespaces)
33
+ end
34
+
35
+ private
36
+
37
+ def nori
38
+ return @nori if @nori
39
+
40
+ nori_options = {
41
+ strip_namespaces: true,
42
+ convert_tags_to: lambda { |tag| tag.snakecase.to_sym }
43
+ }
44
+
45
+ non_nil_nori_options = nori_options.reject { |_, value| value.nil? }
46
+ @nori = Nori.new(non_nil_nori_options)
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,5 @@
1
+ class Sekken
2
+
3
+ VERSION = '0.1.0'
4
+
5
+ end
@@ -0,0 +1,86 @@
1
+ require 'sekken/wsdl/operation'
2
+ require 'sekken/wsdl/document_collection'
3
+ require 'sekken/xs/schema_collection'
4
+ require 'sekken/resolver'
5
+ require 'sekken/importer'
6
+
7
+ class Sekken
8
+ class WSDL
9
+
10
+ def initialize(wsdl, http)
11
+ @documents = WSDL::DocumentCollection.new
12
+ @schemas = XS::SchemaCollection.new
13
+
14
+ resolver = Resolver.new(http)
15
+ importer = Importer.new(resolver, @documents, @schemas)
16
+ importer.import(wsdl)
17
+ end
18
+
19
+ # Public: Returns the DocumentCollection.
20
+ attr_reader :documents
21
+
22
+ # Public: Returns the SchemaCollection.
23
+ attr_reader :schemas
24
+
25
+ # Public: Returns the name of the service.
26
+ def service_name
27
+ @documents.service_name
28
+ end
29
+
30
+ # Public: Returns a Hash of services and ports defined by the WSDL.
31
+ def services
32
+ @documents.services.values.inject({}) { |memo, service| memo.merge service.to_hash }
33
+ end
34
+
35
+ # Public: Returns an Hash of operation names to Operations by service and port name.
36
+ def operations(service_name, port_name)
37
+ verify_service_and_port_exist! service_name, port_name
38
+
39
+ port = @documents.service_port(service_name, port_name)
40
+ binding = port.fetch_binding(@documents)
41
+
42
+ binding.operations.keys
43
+ end
44
+
45
+ # Public: Returns an Operation by service, port and operation name.
46
+ def operation(service_name, port_name, operation_name)
47
+ verify_operation_exists! service_name, port_name, operation_name
48
+
49
+ port = @documents.service_port(service_name, port_name)
50
+ endpoint = port.location
51
+
52
+ binding = port.fetch_binding(@documents)
53
+ binding_operation = binding.operations.fetch(operation_name)
54
+
55
+ port_type = binding.fetch_port_type(@documents)
56
+ port_type_operation = port_type.operations.fetch(operation_name)
57
+
58
+ Operation.new(operation_name, endpoint, binding_operation, port_type_operation, self)
59
+ end
60
+
61
+ private
62
+
63
+ # Private: Raises a useful error in case the operation does not exist.
64
+ def verify_operation_exists!(service_name, port_name, operation_name)
65
+ operations = operations(service_name, port_name)
66
+
67
+ unless operations.include? operation_name
68
+ raise ArgumentError, "Unknown operation #{operation_name.inspect} for " \
69
+ "service #{service_name.inspect} and port #{port_name.inspect}.\n" \
70
+ "You may want to try one of #{operations.inspect}."
71
+ end
72
+ end
73
+
74
+ # Private: Raises a useful error in case the service or port does not exist.
75
+ def verify_service_and_port_exist!(service_name, port_name)
76
+ service = services[service_name]
77
+ port = service[:ports][port_name] if service
78
+
79
+ unless port
80
+ raise ArgumentError, "Unknown service #{service_name.inspect} or port #{port_name.inspect}.\n" \
81
+ "Here is a list of known services and port:\n" + services.inspect
82
+ end
83
+ end
84
+
85
+ end
86
+ end