savon_with_adapter 2.4.1
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 +14 -0
- data/.travis.yml +11 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +1042 -0
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +18 -0
- data/LICENSE +20 -0
- data/README.md +81 -0
- data/Rakefile +14 -0
- data/donate.png +0 -0
- data/lib/savon.rb +27 -0
- data/lib/savon/block_interface.rb +26 -0
- data/lib/savon/builder.rb +166 -0
- data/lib/savon/client.rb +89 -0
- data/lib/savon/core_ext/string.rb +29 -0
- data/lib/savon/header.rb +70 -0
- data/lib/savon/http_error.rb +27 -0
- data/lib/savon/log_message.rb +48 -0
- data/lib/savon/message.rb +35 -0
- data/lib/savon/mock.rb +5 -0
- data/lib/savon/mock/expectation.rb +71 -0
- data/lib/savon/mock/spec_helper.rb +62 -0
- data/lib/savon/model.rb +80 -0
- data/lib/savon/operation.rb +127 -0
- data/lib/savon/options.rb +336 -0
- data/lib/savon/qualified_message.rb +49 -0
- data/lib/savon/request.rb +89 -0
- data/lib/savon/request_logger.rb +48 -0
- data/lib/savon/response.rb +112 -0
- data/lib/savon/soap_fault.rb +48 -0
- data/lib/savon/version.rb +3 -0
- data/savon.gemspec +52 -0
- data/spec/fixtures/gzip/message.gz +0 -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/ssl/client_cert.pem +16 -0
- data/spec/fixtures/ssl/client_encrypted_key.pem +30 -0
- data/spec/fixtures/ssl/client_encrypted_key_cert.pem +24 -0
- data/spec/fixtures/ssl/client_key.pem +15 -0
- data/spec/fixtures/wsdl/authentication.xml +63 -0
- data/spec/fixtures/wsdl/betfair.xml +2981 -0
- data/spec/fixtures/wsdl/edialog.xml +15416 -0
- data/spec/fixtures/wsdl/interhome.xml +2137 -0
- data/spec/fixtures/wsdl/lower_camel.xml +52 -0
- data/spec/fixtures/wsdl/multiple_namespaces.xml +92 -0
- data/spec/fixtures/wsdl/multiple_types.xml +60 -0
- data/spec/fixtures/wsdl/taxcloud.xml +934 -0
- data/spec/fixtures/wsdl/team_software.xml +1 -0
- data/spec/fixtures/wsdl/vies.xml +176 -0
- data/spec/fixtures/wsdl/wasmuth.xml +153 -0
- data/spec/integration/centra_spec.rb +72 -0
- data/spec/integration/email_example_spec.rb +32 -0
- data/spec/integration/random_quote_spec.rb +23 -0
- data/spec/integration/ratp_example_spec.rb +28 -0
- data/spec/integration/stockquote_example_spec.rb +28 -0
- data/spec/integration/support/application.rb +82 -0
- data/spec/integration/support/server.rb +84 -0
- data/spec/integration/temperature_example_spec.rb +46 -0
- data/spec/integration/zipcode_example_spec.rb +42 -0
- data/spec/savon/builder_spec.rb +86 -0
- data/spec/savon/client_spec.rb +198 -0
- data/spec/savon/core_ext/string_spec.rb +37 -0
- data/spec/savon/features/message_tag_spec.rb +61 -0
- data/spec/savon/http_error_spec.rb +49 -0
- data/spec/savon/log_message_spec.rb +33 -0
- data/spec/savon/message_spec.rb +40 -0
- data/spec/savon/mock_spec.rb +157 -0
- data/spec/savon/model_spec.rb +154 -0
- data/spec/savon/observers_spec.rb +92 -0
- data/spec/savon/operation_spec.rb +211 -0
- data/spec/savon/options_spec.rb +772 -0
- data/spec/savon/request_spec.rb +493 -0
- data/spec/savon/response_spec.rb +258 -0
- data/spec/savon/soap_fault_spec.rb +126 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/endpoint.rb +25 -0
- data/spec/support/fixture.rb +39 -0
- data/spec/support/integration.rb +9 -0
- data/spec/support/stdout.rb +25 -0
- metadata +310 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
|
2
|
+
module Savon
|
3
|
+
module CoreExt
|
4
|
+
module String
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
unless "savon".respond_to?(:snakecase)
|
8
|
+
base.send(:include, Extension)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module Extension
|
13
|
+
def snakecase
|
14
|
+
str = dup
|
15
|
+
str.gsub! /::/, '/'
|
16
|
+
str.gsub! /([A-Z]+)([A-Z][a-z])/, '\1_\2'
|
17
|
+
str.gsub! /([a-z\d])([A-Z])/, '\1_\2'
|
18
|
+
str.tr! ".", "_"
|
19
|
+
str.tr! "-", "_"
|
20
|
+
str.downcase!
|
21
|
+
str
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
String.send :include, Savon::CoreExt::String
|
data/lib/savon/header.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require "akami"
|
2
|
+
require "gyoku"
|
3
|
+
|
4
|
+
module Savon
|
5
|
+
class Header
|
6
|
+
|
7
|
+
def initialize(globals, locals)
|
8
|
+
@gyoku_options = { :key_converter => globals[:convert_request_keys_to] }
|
9
|
+
|
10
|
+
@wsse_auth = globals[:wsse_auth]
|
11
|
+
@wsse_timestamp = globals[:wsse_timestamp]
|
12
|
+
|
13
|
+
@global_header = globals[:soap_header]
|
14
|
+
@local_header = locals[:soap_header]
|
15
|
+
|
16
|
+
@header = build
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_reader :local_header, :global_header, :gyoku_options,
|
20
|
+
:wsse_auth, :wsse_timestamp
|
21
|
+
|
22
|
+
def empty?
|
23
|
+
@header.empty?
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
@header
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def build
|
33
|
+
build_header + build_wsse_header
|
34
|
+
end
|
35
|
+
|
36
|
+
def build_header
|
37
|
+
header =
|
38
|
+
if global_header.kind_of?(Hash) && local_header.kind_of?(Hash)
|
39
|
+
global_header.merge(local_header)
|
40
|
+
elsif local_header
|
41
|
+
local_header
|
42
|
+
else
|
43
|
+
global_header
|
44
|
+
end
|
45
|
+
|
46
|
+
convert_to_xml(header)
|
47
|
+
end
|
48
|
+
|
49
|
+
def build_wsse_header
|
50
|
+
wsse_header = akami
|
51
|
+
wsse_header.respond_to?(:to_xml) ? wsse_header.to_xml : ""
|
52
|
+
end
|
53
|
+
|
54
|
+
def convert_to_xml(hash_or_string)
|
55
|
+
if hash_or_string.kind_of? Hash
|
56
|
+
Gyoku.xml(hash_or_string, gyoku_options)
|
57
|
+
else
|
58
|
+
hash_or_string.to_s
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def akami
|
63
|
+
wsse = Akami.wsse
|
64
|
+
wsse.credentials(*wsse_auth) if wsse_auth
|
65
|
+
wsse.timestamp = wsse_timestamp if wsse_timestamp
|
66
|
+
wsse
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "savon"
|
2
|
+
|
3
|
+
module Savon
|
4
|
+
class HTTPError < Error
|
5
|
+
|
6
|
+
def self.present?(http)
|
7
|
+
http.error?
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(http)
|
11
|
+
@http = http
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :http
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
message = "HTTP error (#{@http.code})"
|
18
|
+
message << ": #{@http.body}" unless @http.body.empty?
|
19
|
+
message
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_hash
|
23
|
+
{ :code => @http.code, :headers => @http.headers, :body => @http.body }
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
module Savon
|
4
|
+
class LogMessage
|
5
|
+
|
6
|
+
def initialize(message, filters = [], pretty_print = false)
|
7
|
+
@message = message
|
8
|
+
@filters = filters
|
9
|
+
@pretty_print = pretty_print
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
message_is_xml = @message =~ /^</
|
14
|
+
has_filters = @filters.any?
|
15
|
+
pretty_print = @pretty_print
|
16
|
+
|
17
|
+
return @message unless message_is_xml
|
18
|
+
return @message unless has_filters || pretty_print
|
19
|
+
|
20
|
+
document = Nokogiri.XML(@message)
|
21
|
+
document = apply_filter(document) if has_filters
|
22
|
+
document.to_xml(nokogiri_options)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def apply_filter(document)
|
28
|
+
return document unless document.errors.empty?
|
29
|
+
|
30
|
+
@filters.each do |filter|
|
31
|
+
apply_filter! document, filter
|
32
|
+
end
|
33
|
+
|
34
|
+
document
|
35
|
+
end
|
36
|
+
|
37
|
+
def apply_filter!(document, filter)
|
38
|
+
document.xpath("//*[local-name()='#{filter}']").each do |node|
|
39
|
+
node.content = "***FILTERED***"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def nokogiri_options
|
44
|
+
@pretty_print ? { :indent => 2 } : {}
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require "savon/qualified_message"
|
2
|
+
require "gyoku"
|
3
|
+
|
4
|
+
module Savon
|
5
|
+
class Message
|
6
|
+
|
7
|
+
def initialize(message_tag, namespace_identifier, types, used_namespaces, message, element_form_default, key_converter)
|
8
|
+
@message_tag = message_tag
|
9
|
+
@namespace_identifier = namespace_identifier
|
10
|
+
@types = types
|
11
|
+
@used_namespaces = used_namespaces
|
12
|
+
|
13
|
+
@message = message
|
14
|
+
@element_form_default = element_form_default
|
15
|
+
@key_converter = key_converter
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
return @message.to_s unless @message.kind_of? Hash
|
20
|
+
|
21
|
+
if @element_form_default == :qualified
|
22
|
+
@message = QualifiedMessage.new(@types, @used_namespaces, @key_converter).to_hash(@message, [@message_tag.to_s])
|
23
|
+
end
|
24
|
+
|
25
|
+
gyoku_options = {
|
26
|
+
:element_form_default => @element_form_default,
|
27
|
+
:namespace => @namespace_identifier,
|
28
|
+
:key_converter => @key_converter
|
29
|
+
}
|
30
|
+
|
31
|
+
Gyoku.xml(@message, gyoku_options)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
data/lib/savon/mock.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require "httpi"
|
2
|
+
|
3
|
+
module Savon
|
4
|
+
class MockExpectation
|
5
|
+
|
6
|
+
def initialize(operation_name)
|
7
|
+
@expected = { :operation_name => operation_name }
|
8
|
+
@actual = nil
|
9
|
+
end
|
10
|
+
|
11
|
+
def with(locals)
|
12
|
+
@expected[:message] = locals[:message]
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def returns(response)
|
17
|
+
response = { :code => 200, :headers => {}, :body => response } if response.kind_of?(String)
|
18
|
+
@response = response
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def actual(operation_name, builder, globals, locals)
|
23
|
+
@actual = {
|
24
|
+
:operation_name => operation_name,
|
25
|
+
:message => locals[:message]
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def verify!
|
30
|
+
unless @actual
|
31
|
+
raise ExpectationError, "Expected a request to the #{@expected[:operation_name].inspect} operation, " \
|
32
|
+
"but no request was executed."
|
33
|
+
end
|
34
|
+
|
35
|
+
verify_operation_name!
|
36
|
+
verify_message!
|
37
|
+
end
|
38
|
+
|
39
|
+
def response!
|
40
|
+
unless @response
|
41
|
+
raise ExpectationError, "This expectation was not set up with a response."
|
42
|
+
end
|
43
|
+
|
44
|
+
HTTPI::Response.new(@response[:code], @response[:headers], @response[:body])
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def verify_operation_name!
|
50
|
+
unless @expected[:operation_name] == @actual[:operation_name]
|
51
|
+
raise ExpectationError, "Expected a request to the #{@expected[:operation_name].inspect} operation.\n" \
|
52
|
+
"Received a request to the #{@actual[:operation_name].inspect} operation instead."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def verify_message!
|
57
|
+
return if @expected[:message] == :any
|
58
|
+
unless @expected[:message] == @actual[:message]
|
59
|
+
expected_message = " with this message: #{@expected[:message].inspect}" if @expected[:message]
|
60
|
+
expected_message ||= " with no message."
|
61
|
+
|
62
|
+
actual_message = " with this message: #{@actual[:message].inspect}" if @actual[:message]
|
63
|
+
actual_message ||= " with no message."
|
64
|
+
|
65
|
+
raise ExpectationError, "Expected a request to the #{@expected[:operation_name].inspect} operation\n#{expected_message}\n" \
|
66
|
+
"Received a request to the #{@actual[:operation_name].inspect} operation\n#{actual_message}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require "savon/mock"
|
2
|
+
|
3
|
+
module Savon
|
4
|
+
module SpecHelper
|
5
|
+
|
6
|
+
class Interface
|
7
|
+
|
8
|
+
def mock!
|
9
|
+
Savon.observers << self
|
10
|
+
end
|
11
|
+
|
12
|
+
def unmock!
|
13
|
+
Savon.observers.clear
|
14
|
+
end
|
15
|
+
|
16
|
+
def expects(operation_name)
|
17
|
+
expectation = MockExpectation.new(operation_name)
|
18
|
+
expectations << expectation
|
19
|
+
expectation
|
20
|
+
end
|
21
|
+
|
22
|
+
def expectations
|
23
|
+
@expectations ||= []
|
24
|
+
end
|
25
|
+
|
26
|
+
def notify(operation_name, builder, globals, locals)
|
27
|
+
expectation = expectations.shift
|
28
|
+
|
29
|
+
if expectation
|
30
|
+
expectation.actual(operation_name, builder, globals, locals)
|
31
|
+
|
32
|
+
expectation.verify!
|
33
|
+
expectation.response!
|
34
|
+
else
|
35
|
+
raise ExpectationError, "Unexpected request to the #{operation_name.inspect} operation."
|
36
|
+
end
|
37
|
+
rescue ExpectationError
|
38
|
+
@expectations.clear
|
39
|
+
raise
|
40
|
+
end
|
41
|
+
|
42
|
+
def verify!
|
43
|
+
return if expectations.empty?
|
44
|
+
expectations.each(&:verify!)
|
45
|
+
rescue ExpectationError
|
46
|
+
@expectations.clear
|
47
|
+
raise
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
def savon
|
53
|
+
@savon ||= Interface.new
|
54
|
+
end
|
55
|
+
|
56
|
+
def verify_mocks_for_rspec
|
57
|
+
super if defined? super
|
58
|
+
savon.verify!
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
data/lib/savon/model.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
module Savon
|
2
|
+
module Model
|
3
|
+
|
4
|
+
def self.extended(base)
|
5
|
+
base.setup
|
6
|
+
end
|
7
|
+
|
8
|
+
def setup
|
9
|
+
class_operation_module
|
10
|
+
instance_operation_module
|
11
|
+
end
|
12
|
+
|
13
|
+
# Accepts one or more SOAP operations and generates both class and instance methods named
|
14
|
+
# after the given operations. Each generated method accepts an optional SOAP message Hash.
|
15
|
+
def operations(*operations)
|
16
|
+
operations.each do |operation|
|
17
|
+
define_class_operation(operation)
|
18
|
+
define_instance_operation(operation)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# Defines a class-level SOAP operation.
|
25
|
+
def define_class_operation(operation)
|
26
|
+
class_operation_module.module_eval %{
|
27
|
+
def #{operation.to_s.snakecase}(locals = {})
|
28
|
+
client.call #{operation.inspect}, locals
|
29
|
+
end
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
# Defines an instance-level SOAP operation.
|
34
|
+
def define_instance_operation(operation)
|
35
|
+
instance_operation_module.module_eval %{
|
36
|
+
def #{operation.to_s.snakecase}(locals = {})
|
37
|
+
self.class.#{operation.to_s.snakecase} locals
|
38
|
+
end
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
# Class methods.
|
43
|
+
def class_operation_module
|
44
|
+
@class_operation_module ||= Module.new {
|
45
|
+
|
46
|
+
def client(globals = {})
|
47
|
+
@client ||= Savon::Client.new(globals)
|
48
|
+
rescue InitializationError
|
49
|
+
raise_initialization_error!
|
50
|
+
end
|
51
|
+
|
52
|
+
def global(option, *value)
|
53
|
+
client.globals[option] = value
|
54
|
+
end
|
55
|
+
|
56
|
+
def raise_initialization_error!
|
57
|
+
raise InitializationError,
|
58
|
+
"Expected the model to be initialized with either a WSDL document or the SOAP endpoint and target namespace options.\n" \
|
59
|
+
"Make sure to setup the model by calling the .client class method before calling the .global method.\n\n" \
|
60
|
+
"client(wsdl: '/Users/me/project/service.wsdl') # to use a local WSDL document\n" \
|
61
|
+
"client(wsdl: 'http://example.com?wsdl') # to use a remote WSDL document\n" \
|
62
|
+
"client(endpoint: 'http://example.com', namespace: 'http://v1.example.com') # if you don't have a WSDL document"
|
63
|
+
end
|
64
|
+
|
65
|
+
}.tap { |mod| extend(mod) }
|
66
|
+
end
|
67
|
+
|
68
|
+
# Instance methods.
|
69
|
+
def instance_operation_module
|
70
|
+
@instance_operation_module ||= Module.new {
|
71
|
+
|
72
|
+
def client
|
73
|
+
self.class.client
|
74
|
+
end
|
75
|
+
|
76
|
+
}.tap { |mod| include(mod) }
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require "savon/options"
|
2
|
+
require "savon/block_interface"
|
3
|
+
require "savon/request"
|
4
|
+
require "savon/builder"
|
5
|
+
require "savon/response"
|
6
|
+
require "savon/request_logger"
|
7
|
+
|
8
|
+
module Savon
|
9
|
+
class Operation
|
10
|
+
|
11
|
+
def self.create(operation_name, wsdl, globals)
|
12
|
+
if wsdl.document?
|
13
|
+
ensure_name_is_symbol! operation_name
|
14
|
+
ensure_exists! operation_name, wsdl
|
15
|
+
end
|
16
|
+
|
17
|
+
new(operation_name, wsdl, globals)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.ensure_exists!(operation_name, wsdl)
|
21
|
+
unless wsdl.soap_actions.include? operation_name
|
22
|
+
raise UnknownOperationError, "Unable to find SOAP operation: #{operation_name.inspect}\n" \
|
23
|
+
"Operations provided by your service: #{wsdl.soap_actions.inspect}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.ensure_name_is_symbol!(operation_name)
|
28
|
+
unless operation_name.kind_of? Symbol
|
29
|
+
raise ArgumentError, "Expected the first parameter (the name of the operation to call) to be a symbol\n" \
|
30
|
+
"Actual: #{operation_name.inspect} (#{operation_name.class})"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def initialize(name, wsdl, globals)
|
35
|
+
@name = name
|
36
|
+
@wsdl = wsdl
|
37
|
+
@globals = globals
|
38
|
+
|
39
|
+
@logger = RequestLogger.new(globals)
|
40
|
+
end
|
41
|
+
|
42
|
+
def build(locals = {}, &block)
|
43
|
+
set_locals(locals, block)
|
44
|
+
Builder.new(@name, @wsdl, @globals, @locals)
|
45
|
+
end
|
46
|
+
|
47
|
+
def call(locals = {}, &block)
|
48
|
+
builder = build(locals, &block)
|
49
|
+
|
50
|
+
response = Savon.notify_observers(@name, builder, @globals, @locals)
|
51
|
+
response ||= call_with_logging build_request(builder)
|
52
|
+
|
53
|
+
raise_expected_httpi_response! unless response.kind_of?(HTTPI::Response)
|
54
|
+
|
55
|
+
create_response(response)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def create_response(response)
|
61
|
+
if multipart_supported?
|
62
|
+
Multipart::Response.new(response, @globals, @locals)
|
63
|
+
else
|
64
|
+
Response.new(response, @globals, @locals)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def multipart_supported?
|
69
|
+
return false unless @globals[:multipart] || @locals[:multipart]
|
70
|
+
|
71
|
+
if Savon.const_defined? :Multipart
|
72
|
+
true
|
73
|
+
else
|
74
|
+
raise 'Unable to find Savon::Multipart. Make sure the savon-multipart gem is installed and loaded.'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def set_locals(locals, block)
|
79
|
+
locals = LocalOptions.new(locals)
|
80
|
+
BlockInterface.new(locals).evaluate(block) if block
|
81
|
+
|
82
|
+
@locals = locals
|
83
|
+
end
|
84
|
+
|
85
|
+
def call_with_logging(request)
|
86
|
+
@logger.log(request) { HTTPI.post(request, @globals[:adapter]) }
|
87
|
+
end
|
88
|
+
|
89
|
+
def build_request(builder)
|
90
|
+
request = SOAPRequest.new(@globals).build(
|
91
|
+
:soap_action => soap_action,
|
92
|
+
:cookies => @locals[:cookies]
|
93
|
+
)
|
94
|
+
|
95
|
+
request.url = endpoint
|
96
|
+
request.body = builder.to_s
|
97
|
+
|
98
|
+
# TODO: could HTTPI do this automatically in case the header
|
99
|
+
# was not specified manually? [dh, 2013-01-04]
|
100
|
+
request.headers["Content-Length"] = request.body.bytesize.to_s
|
101
|
+
|
102
|
+
request
|
103
|
+
end
|
104
|
+
|
105
|
+
def soap_action
|
106
|
+
# soap_action explicitly set to something falsy
|
107
|
+
return if @locals.include?(:soap_action) && !@locals[:soap_action]
|
108
|
+
|
109
|
+
# get the soap_action from local options
|
110
|
+
soap_action = @locals[:soap_action]
|
111
|
+
# with no local option, but a wsdl, ask it for the soap_action
|
112
|
+
soap_action ||= @wsdl.soap_action(@name.to_sym) if @wsdl.document?
|
113
|
+
# if there is no soap_action up to this point, fallback to a simple default
|
114
|
+
soap_action ||= Gyoku.xml_tag(@name, :key_converter => @globals[:convert_request_keys_to])
|
115
|
+
end
|
116
|
+
|
117
|
+
def endpoint
|
118
|
+
@globals[:endpoint] || @wsdl.endpoint
|
119
|
+
end
|
120
|
+
|
121
|
+
def raise_expected_httpi_response!
|
122
|
+
raise Error, "Observers need to return an HTTPI::Response to mock " \
|
123
|
+
"the request or nil to execute the request."
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|