savon_with_adapter 2.4.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|