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.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.travis.yml +11 -0
- data/.yardopts +6 -0
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +27 -0
- data/MIT-LICENSE +20 -0
- data/README.md +28 -0
- data/Rakefile +21 -0
- data/donate.png +0 -0
- data/lib/sekken.rb +75 -0
- data/lib/sekken/envelope.rb +92 -0
- data/lib/sekken/errors.rb +9 -0
- data/lib/sekken/example_message.rb +41 -0
- data/lib/sekken/httpclient.rb +35 -0
- data/lib/sekken/importer.rb +77 -0
- data/lib/sekken/message.rb +135 -0
- data/lib/sekken/operation.rb +100 -0
- data/lib/sekken/resolver.rb +20 -0
- data/lib/sekken/response.rb +50 -0
- data/lib/sekken/version.rb +5 -0
- data/lib/sekken/wsdl.rb +86 -0
- data/lib/sekken/wsdl/binding.rb +64 -0
- data/lib/sekken/wsdl/binding_operation.rb +85 -0
- data/lib/sekken/wsdl/document.rb +83 -0
- data/lib/sekken/wsdl/document_collection.rb +61 -0
- data/lib/sekken/wsdl/input_output.rb +84 -0
- data/lib/sekken/wsdl/message.rb +38 -0
- data/lib/sekken/wsdl/operation.rb +47 -0
- data/lib/sekken/wsdl/port.rb +29 -0
- data/lib/sekken/wsdl/port_type.rb +38 -0
- data/lib/sekken/wsdl/port_type_operation.rb +42 -0
- data/lib/sekken/wsdl/service.rb +55 -0
- data/lib/sekken/xml/attribute.rb +13 -0
- data/lib/sekken/xml/element.rb +82 -0
- data/lib/sekken/xml/element_builder.rb +220 -0
- data/lib/sekken/xs/schema.rb +57 -0
- data/lib/sekken/xs/schema_collection.rb +49 -0
- data/lib/sekken/xs/types.rb +272 -0
- data/sekken.gemspec +42 -0
- data/spec/fixtures/response/another_soap_fault.xml +14 -0
- data/spec/fixtures/response/authentication.xml +14 -0
- data/spec/fixtures/response/header.xml +13 -0
- data/spec/fixtures/response/list.xml +18 -0
- data/spec/fixtures/response/multi_ref.xml +39 -0
- data/spec/fixtures/response/soap_fault.xml +8 -0
- data/spec/fixtures/response/soap_fault12.xml +18 -0
- data/spec/fixtures/response/taxcloud.xml +1 -0
- data/spec/fixtures/wsdl/amazon.wsdl +1920 -0
- data/spec/fixtures/wsdl/arrays_with_attributes.wsdl +117 -0
- data/spec/fixtures/wsdl/authentication.wsdl +63 -0
- data/spec/fixtures/wsdl/awse.wsdl +1510 -0
- data/spec/fixtures/wsdl/betfair.wsdl +2981 -0
- data/spec/fixtures/wsdl/blz_service.wsdl +88 -0
- data/spec/fixtures/wsdl/bookt/bookt.wsdl +11 -0
- data/spec/fixtures/wsdl/bookt/bookt0.xsd +433 -0
- data/spec/fixtures/wsdl/bookt/bookt1.xsd +42 -0
- data/spec/fixtures/wsdl/bookt/bookt10.xsd +38 -0
- data/spec/fixtures/wsdl/bookt/bookt11.xsd +17 -0
- data/spec/fixtures/wsdl/bookt/bookt12.xsd +18 -0
- data/spec/fixtures/wsdl/bookt/bookt13.xsd +22 -0
- data/spec/fixtures/wsdl/bookt/bookt14.xsd +27 -0
- data/spec/fixtures/wsdl/bookt/bookt15.xsd +28 -0
- data/spec/fixtures/wsdl/bookt/bookt2.wsdl +243 -0
- data/spec/fixtures/wsdl/bookt/bookt2.xsd +81 -0
- data/spec/fixtures/wsdl/bookt/bookt3.wsdl +286 -0
- data/spec/fixtures/wsdl/bookt/bookt3.xsd +61 -0
- data/spec/fixtures/wsdl/bookt/bookt4.xsd +35 -0
- data/spec/fixtures/wsdl/bookt/bookt5.xsd +22 -0
- data/spec/fixtures/wsdl/bookt/bookt6.xsd +26 -0
- data/spec/fixtures/wsdl/bookt/bookt7.xsd +18 -0
- data/spec/fixtures/wsdl/bookt/bookt8.xsd +22 -0
- data/spec/fixtures/wsdl/bookt/bookt9.xsd +29 -0
- data/spec/fixtures/wsdl/bronto.wsdl +3285 -0
- data/spec/fixtures/wsdl/bydexchange/bydexchange.wsdl +104 -0
- data/spec/fixtures/wsdl/bydexchange/bydexchange0.xsd +1 -0
- data/spec/fixtures/wsdl/bydexchange/bydexchange1.xsd +1 -0
- data/spec/fixtures/wsdl/bydexchange/bydexchange2.wsdl +119 -0
- data/spec/fixtures/wsdl/bydexchange/bydexchange2.xsd +1 -0
- data/spec/fixtures/wsdl/bydexchange/bydexchange3.xsd +1 -0
- data/spec/fixtures/wsdl/bydexchange/bydexchange4.xsd +1 -0
- data/spec/fixtures/wsdl/bydexchange/bydexchange5.xsd +1 -0
- data/spec/fixtures/wsdl/bydexchange/bydexchange6.xsd +1 -0
- data/spec/fixtures/wsdl/bydexchange/bydexchange7.xsd +1 -0
- data/spec/fixtures/wsdl/bydexchange/bydexchange8.xsd +1 -0
- data/spec/fixtures/wsdl/crowd.wsdl +2437 -0
- data/spec/fixtures/wsdl/data_exchange.wsdl +98 -0
- data/spec/fixtures/wsdl/document_literal_wrapped.wsdl +153 -0
- data/spec/fixtures/wsdl/economic.wsdl +65660 -0
- data/spec/fixtures/wsdl/edialog.wsdl +13148 -0
- data/spec/fixtures/wsdl/email_verification.wsdl +394 -0
- data/spec/fixtures/wsdl/equifax.wsdl +794 -0
- data/spec/fixtures/wsdl/geotrust.wsdl +156 -0
- data/spec/fixtures/wsdl/interhome.wsdl +2137 -0
- data/spec/fixtures/wsdl/iws.wsdl +695 -0
- data/spec/fixtures/wsdl/jetairways.wsdl +156 -0
- data/spec/fixtures/wsdl/jira.wsdl +3890 -0
- data/spec/fixtures/wsdl/juniper.wsdl +215 -0
- data/spec/fixtures/wsdl/namespaced_actions.wsdl +307 -0
- data/spec/fixtures/wsdl/oracle.wsdl +3629 -0
- data/spec/fixtures/wsdl/ratp.wsdl +955 -0
- data/spec/fixtures/wsdl/rio2/rio2.wsdl +74 -0
- data/spec/fixtures/wsdl/rio2/rio2_0.wsdl +55 -0
- data/spec/fixtures/wsdl/rio2/rio2_0.xsd +58 -0
- data/spec/fixtures/wsdl/rio2/rio2_1.xsd +41 -0
- data/spec/fixtures/wsdl/rio2/rio2_2.xsd +222 -0
- data/spec/fixtures/wsdl/rio2/rio2_3.xsd +10 -0
- data/spec/fixtures/wsdl/rpc_literal.wsdl +105 -0
- data/spec/fixtures/wsdl/spyne.wsdl +70 -0
- data/spec/fixtures/wsdl/stockquote.wsdl +124 -0
- data/spec/fixtures/wsdl/taxcloud.wsdl +934 -0
- data/spec/fixtures/wsdl/team_software/team_software.wsdl +542 -0
- data/spec/fixtures/wsdl/team_software/team_software0.xsd +448 -0
- data/spec/fixtures/wsdl/team_software/team_software1.xsd +41 -0
- data/spec/fixtures/wsdl/team_software/team_software2.xsd +258 -0
- data/spec/fixtures/wsdl/team_software/team_software3.xsd +14 -0
- data/spec/fixtures/wsdl/telefonkatalogen.wsdl +45 -0
- data/spec/fixtures/wsdl/temperature.wsdl +136 -0
- data/spec/fixtures/wsdl/wasmuth/wasmuth.wsdl +157 -0
- data/spec/fixtures/wsdl/wasmuth/wasmuth1.xsd +210 -0
- data/spec/fixtures/wsdl/wasmuth/wasmuth2.xsd +549 -0
- data/spec/fixtures/wsdl/xignite.wsdl +3470 -0
- data/spec/fixtures/wsdl/yahoo.wsdl +2425 -0
- data/spec/fixtures/wsdl/zanox_export_service.xml +520 -0
- data/spec/integration/amazon_spec.rb +51 -0
- data/spec/integration/authentication_spec.rb +38 -0
- data/spec/integration/awse_spec.rb +95 -0
- data/spec/integration/betfair_spec.rb +179 -0
- data/spec/integration/blz_service_spec.rb +46 -0
- data/spec/integration/bookt_spec.rb +59 -0
- data/spec/integration/bronto_spec.rb +178 -0
- data/spec/integration/bydexchange_spec.rb +40 -0
- data/spec/integration/crowd_spec.rb +44 -0
- data/spec/integration/data_exchange_spec.rb +27 -0
- data/spec/integration/document_literal_spec.rb +104 -0
- data/spec/integration/economic_spec.rb +64 -0
- data/spec/integration/email_verification_spec.rb +82 -0
- data/spec/integration/equifax_spec.rb +216 -0
- data/spec/integration/geotrust_spec.rb +17 -0
- data/spec/integration/interhome_spec.rb +156 -0
- data/spec/integration/iws_spec.rb +27 -0
- data/spec/integration/jetairways_spec.rb +142 -0
- data/spec/integration/jira_spec.rb +27 -0
- data/spec/integration/juniper_spec.rb +20 -0
- data/spec/integration/namespaced_actions_spec.rb +37 -0
- data/spec/integration/oracle_spec.rb +61 -0
- data/spec/integration/ratp_spec.rb +178 -0
- data/spec/integration/rio2_spec.rb +56 -0
- data/spec/integration/rpc_literal_spec.rb +101 -0
- data/spec/integration/spyne_spec.rb +60 -0
- data/spec/integration/stockquote_spec.rb +46 -0
- data/spec/integration/taxcloud_spec.rb +45 -0
- data/spec/integration/team_software_spec.rb +51 -0
- data/spec/integration/telefonkatalogen_spec.rb +42 -0
- data/spec/integration/temperature_spec.rb +71 -0
- data/spec/integration/wasmuth_spec.rb +47 -0
- data/spec/integration/xignite_spec.rb +112 -0
- data/spec/integration/yahoo_spec.rb +116 -0
- data/spec/sekken/httpclient_spec.rb +41 -0
- data/spec/sekken/operation/build_spec.rb +308 -0
- data/spec/sekken/operation/document_literal_spec.rb +53 -0
- data/spec/sekken/operation/example_body_spec.rb +95 -0
- data/spec/sekken/operation/rpc_literal_spec.rb +50 -0
- data/spec/sekken/operation_spec.rb +169 -0
- data/spec/sekken/resolver_spec.rb +38 -0
- data/spec/sekken/response_spec.rb +17 -0
- data/spec/sekken/wsdl/document_spec.rb +191 -0
- data/spec/sekken/wsdl_spec.rb +46 -0
- data/spec/sekken/xs/complex_type_spec.rb +197 -0
- data/spec/sekken/xs/element_spec.rb +82 -0
- data/spec/sekken/xs/simple_type_spec.rb +39 -0
- data/spec/sekken_spec.rb +128 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/support/fixture.rb +19 -0
- data/spec/support/http_mock.rb +43 -0
- 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
|
data/lib/sekken/wsdl.rb
ADDED
|
@@ -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
|