johnreitano-savon 0.7.2.1 → 0.7.7.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,8 +6,7 @@ module Net
6
6
  @address, @port = address, port
7
7
  end
8
8
 
9
- # Convenience method for setting SSL client authentication
10
- # through a Hash of +options+.
9
+ # Convenience method for setting SSL client authentication through a Hash of +options+.
11
10
  def ssl_client_auth(options)
12
11
  self.use_ssl = true
13
12
  self.cert = options[:cert] if options[:cert]
@@ -1,8 +1,6 @@
1
1
  class Object
2
2
 
3
- # Returns +true+ if the Object is false, empty, or a whitespace string.
4
- # For example, "", false, nil, [], and {} are blank.
5
- # Implementation from ActiveSupport.
3
+ # Returns +true+ if the Object is nil, false or empty. Implementation from ActiveSupport.
6
4
  def blank?
7
5
  respond_to?(:empty?) ? empty? : !self
8
6
  end unless defined? blank?
@@ -26,22 +26,41 @@ class String
26
26
  str
27
27
  end
28
28
 
29
+ # Returns whether the String starts with a given +prefix+.
30
+ def starts_with?(prefix)
31
+ prefix = prefix.to_s
32
+ self[0, prefix.length] == prefix
33
+ end unless defined? starts_with?
34
+
35
+ # Returns whether the String ends with a given +suffix+.
36
+ def ends_with?(suffix)
37
+ suffix = suffix.to_s
38
+ self[-suffix.length, suffix.length] == suffix
39
+ end unless defined? ends_with?
40
+
29
41
  # Returns the String without namespace.
30
42
  def strip_namespace
31
- gsub /(.+:)(.+)/, '\2'
43
+ split(":").last
32
44
  end
33
45
 
34
- # Translates SOAP response values to more convenient Ruby Objects.
46
+ # Translates SOAP response values to Ruby Objects.
35
47
  def map_soap_response
36
- return DateTime.parse( self ) if Savon::SOAPDateTimeRegexp === self
48
+ return DateTime.parse(self) if Savon::SOAP::DateTimeRegexp === self
37
49
  return true if self.strip.downcase == "true"
38
50
  return false if self.strip.downcase == "false"
39
51
  self
40
52
  end
41
53
 
42
54
  # Returns the String as a SOAP request compliant value.
55
+ # Escapes special characters for XML.
43
56
  def to_soap_value
44
- to_s
57
+ str = dup
58
+ str.gsub! "&", "&"
59
+ str.gsub! '"', """
60
+ str.gsub! "'", "'"
61
+ str.gsub! "<", "&lt;"
62
+ str.gsub! ">", "&gt;"
63
+ str
45
64
  end
46
65
 
47
66
  end
@@ -1,10 +1,10 @@
1
1
  module URI
2
- class HTTP
2
+ class Generic
3
3
 
4
4
  # Returns whether the URI hints to SSL.
5
5
  def ssl?
6
- /^https/ === @scheme
6
+ !@scheme ? nil : @scheme.starts_with?("https")
7
7
  end
8
8
 
9
9
  end
10
- end
10
+ end
@@ -0,0 +1,56 @@
1
+ module Savon
2
+
3
+ # = Savon::Logger
4
+ #
5
+ # Savon::Logger can be mixed into classes to provide logging behavior.
6
+ #
7
+ # By default, the Logger mixin uses {Ruby's Logger}[http://ruby-doc.org/stdlib/libdoc/logger/rdoc/]
8
+ # from the standard library, a log level of :debug and is pointing to STDOUT.
9
+ module Logger
10
+
11
+ module ClassMethods
12
+
13
+ # Sets whether to log.
14
+ def log=(log)
15
+ @log = log
16
+ end
17
+
18
+ # Returns whether to log. Defaults to +true+.
19
+ def log?
20
+ @log != false
21
+ end
22
+
23
+ # Sets the logger.
24
+ def logger=(logger)
25
+ @logger = logger
26
+ end
27
+
28
+ # Returns the logger. Defaults to an instance of +Logger+ writing to STDOUT.
29
+ def logger
30
+ @logger ||= ::Logger.new STDOUT
31
+ end
32
+
33
+ # Sets the log level.
34
+ def log_level=(log_level)
35
+ @log_level = log_level
36
+ end
37
+
38
+ # Returns the log level. Defaults to +debug+.
39
+ def log_level
40
+ @log_level ||= :debug
41
+ end
42
+
43
+ end
44
+
45
+ # Extends the class including this module with its ClassMethods.
46
+ def self.included(base)
47
+ base.extend ClassMethods
48
+ end
49
+
50
+ # Logs a given +message+.
51
+ def log(message)
52
+ self.class.logger.send self.class.log_level, message if self.class.log?
53
+ end
54
+
55
+ end
56
+ end
data/lib/savon/request.rb CHANGED
@@ -1,51 +1,50 @@
1
1
  module Savon
2
2
 
3
- # == Savon::Request
3
+ # = Savon::Request
4
4
  #
5
- # Handles both WSDL and SOAP HTTP requests.
5
+ # Savon::Request handles both WSDL and SOAP requests.
6
+ #
7
+ # == The Net::HTTP object
8
+ #
9
+ # You can access the Net::HTTP object used for both WSDL and SOAP requests via:
10
+ #
11
+ # client.request.http
12
+ #
13
+ # Here's an example of how to set open and read timeouts on the Net::HTTP object.
14
+ #
15
+ # client.request.http.open_timeout = 30
16
+ # client.request.http.read_timeout = 30
17
+ #
18
+ # Please refer to the {Net::HTTP documentation}[http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/]
19
+ # for more information.
20
+ #
21
+ # == HTTP basic authentication
22
+ #
23
+ # Setting credentials for HTTP basic authentication:
24
+ #
25
+ # client.request.basic_auth "username", "password"
26
+ #
27
+ # == SSL client authentication
28
+ #
29
+ # You can use the methods provided by Net::HTTP to set SSL client authentication or use a shortcut:
30
+ #
31
+ # client.request.http.ssl_client_auth(
32
+ # :cert => OpenSSL::X509::Certificate.new(File.read("client_cert.pem")),
33
+ # :key => OpenSSL::PKey::RSA.new(File.read("client_key.pem"), "password if one exists"),
34
+ # :ca_file => "cacert.pem",
35
+ # :verify_mode => OpenSSL::SSL::VERIFY_PEER
36
+ # )
37
+ #
38
+ # == HTTP headers
39
+ #
40
+ # There's an accessor for the Hash of HTTP headers sent with any SOAP call:
41
+ #
42
+ # client.request.headers["custom"] = "header"
6
43
  class Request
44
+ include Logger
7
45
 
8
46
  # Content-Types by SOAP version.
9
- ContentType = { 1 => "text/xml", 2 => "application/soap+xml" }
10
-
11
- # Whether to log HTTP requests.
12
- @@log = true
13
-
14
- # The default logger.
15
- @@logger = Logger.new STDOUT
16
-
17
- # The default log level.
18
- @@log_level = :debug
19
-
20
- # Sets whether to log HTTP requests.
21
- def self.log=(log)
22
- @@log = log
23
- end
24
-
25
- # Returns whether to log HTTP requests.
26
- def self.log?
27
- @@log
28
- end
29
-
30
- # Sets the logger.
31
- def self.logger=(logger)
32
- @@logger = logger
33
- end
34
-
35
- # Returns the logger.
36
- def self.logger
37
- @@logger
38
- end
39
-
40
- # Sets the log level.
41
- def self.log_level=(log_level)
42
- @@log_level = log_level
43
- end
44
-
45
- # Returns the log level.
46
- def self.log_level
47
- @@log_level
48
- end
47
+ ContentType = { 1 => "text/xml;charset=UTF-8", 2 => "application/soap+xml;charset=UTF-8" }
49
48
 
50
49
  # Expects a SOAP +endpoint+ String. Also accepts an optional Hash
51
50
  # of +options+ for specifying a proxy server.
@@ -75,6 +74,12 @@ module Savon
75
74
  @basic_auth = [username, password]
76
75
  end
77
76
 
77
+ # Sets the +username+ and +password+ for NTLM authentication
78
+ # if +username+ does not work try 'domain\username'
79
+ def ntlm_auth(username, password)
80
+ @ntlm_auth = [username, password]
81
+ end
82
+
78
83
  # Retrieves WSDL document and returns the Net::HTTP response.
79
84
  def wsdl
80
85
  log "Retrieving WSDL from: #{@endpoint}"
@@ -83,8 +88,7 @@ module Savon
83
88
  http.start { |h| h.request request(:wsdl) }
84
89
  end
85
90
 
86
- # Executes a SOAP request using a given Savon::SOAP instance and
87
- # returns the Net::HTTP response.
91
+ # Executes a SOAP request using a given Savon::SOAP instance and returns the Net::HTTP response.
88
92
  def soap(soap)
89
93
  @soap = soap
90
94
  http.endpoint @soap.endpoint.host, @soap.endpoint.port
@@ -108,7 +112,7 @@ module Savon
108
112
  # Logs the SOAP request.
109
113
  def log_request
110
114
  log "SOAP request: #{@soap.endpoint}"
111
- log headers.merge(soap_headers).map { |key, value| "#{key}: #{value}" }.join(", ")
115
+ log soap_headers.merge(headers).map { |key, value| "#{key}: #{value}" }.join(", ")
112
116
  log @soap.to_xml
113
117
  end
114
118
 
@@ -118,14 +122,21 @@ module Savon
118
122
  log @response.body
119
123
  end
120
124
 
121
- # Returns a Net::HTTP request for a given +type+. Yields the request
122
- # to an optional block.
125
+ # Returns a Net::HTTP request for a given +type+. Yields the request to an optional block.
123
126
  def request(type)
124
127
  request = case type
125
- when :wsdl then Net::HTTP::Get.new @endpoint.to_s
126
- when :soap then Net::HTTP::Post.new @soap.endpoint.to_s, headers.merge(soap_headers)
128
+ when :wsdl then Net::HTTP::Get.new @endpoint.request_uri, headers
129
+ when :soap then Net::HTTP::Post.new @soap.endpoint.request_uri, soap_headers.merge(headers)
130
+ end
131
+
132
+ case
133
+ when @basic_auth
134
+ request.basic_auth(*@basic_auth)
135
+ when @ntlm_auth
136
+ log "Attempting NTLM Authentication"
137
+ request.ntlm_auth(*@ntlm_auth)
127
138
  end
128
- request.basic_auth *@basic_auth if @basic_auth
139
+ request.basic_auth(*@basic_auth) if @basic_auth
129
140
  yield request if block_given?
130
141
  request
131
142
  end
@@ -135,15 +146,5 @@ module Savon
135
146
  { "Content-Type" => ContentType[@soap.version], "SOAPAction" => @soap.action }
136
147
  end
137
148
 
138
- # Logs a given +message+.
139
- def log(message)
140
- self.class.logger.send self.class.log_level, message if log?
141
- end
142
-
143
- # Returns whether to log.
144
- def log?
145
- self.class.log? && self.class.logger.respond_to?(self.class.log_level)
146
- end
147
-
148
149
  end
149
150
  end
@@ -1,10 +1,66 @@
1
1
  module Savon
2
2
 
3
- # == Savon::Response
3
+ # = Savon::Response
4
4
  #
5
- # Represents the HTTP and SOAP response.
5
+ # Savon::Response represents both HTTP and SOAP response.
6
+ #
7
+ # == SOAP fault
8
+ #
9
+ # Assuming the default behavior of raising errors is disabled, you can ask the response object
10
+ # if there was a SOAP fault or an HTTP error and get the SOAP fault or HTTP error message.
11
+ #
12
+ # response.soap_fault?
13
+ # # => true
14
+ #
15
+ # response.soap_fault
16
+ # # => "(soap:Server) Fault occurred while processing."
17
+ #
18
+ # response.http_error?
19
+ # # => true
20
+ #
21
+ # response.http_error
22
+ # # => "Not found (404)"
23
+ #
24
+ # == Response as XML
25
+ #
26
+ # To get the raw SOAP response XML, you can call to_xml or to_s on the response object.
27
+ #
28
+ # response.to_xml
29
+ # => "<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
30
+ # => "..."
31
+ # => "</soap:Envelope>"
32
+ #
33
+ # == Response as a Hash
34
+ #
35
+ # You can also let Savon translate the SOAP response body to a Hash.
36
+ #
37
+ # response.to_hash
38
+ # => { :findUserByIdResponse => {
39
+ # => :id => "123",
40
+ # => :username => "eve"
41
+ # => :active => true
42
+ # => }
43
+ #
44
+ # When translating the SOAP response to a Hash, some XML tags and values are converted to more
45
+ # convenient Ruby objects. Translation is done through John Nunemaker's {Crack}[http://github.com/jnunemaker/crack]
46
+ # library along with some custom mapping.
47
+ #
48
+ # * XML tags (Hash keys) are converted to snake_case Symbols and namespaces are stripped off
49
+ # * SOAP xs:nil values are converted to nil objects
50
+ # * XML values specified in xs:DateTime format are converted to DateTime objects
51
+ # * XML values of "true" and "false" are converted to TrueClass and FalseClass
52
+ #
53
+ # == Net::HTTP response
54
+ #
55
+ # If for some reason you need to access the Net::HTTP response object ... you can.
56
+ #
57
+ # bc. response.http
58
+ # => #<Net::HTTPOK:0x7f749a1aa4a8>
6
59
  class Response
7
60
 
61
+ # The maximum HTTP response code considered to be OK.
62
+ MaxNonErrorResponseCode = 299
63
+
8
64
  # The global setting of whether to raise errors.
9
65
  @@raise_errors = true
10
66
 
@@ -28,7 +84,7 @@ module Savon
28
84
 
29
85
  # Returns whether there was a SOAP fault.
30
86
  def soap_fault?
31
- @soap_fault ? true : false
87
+ !@soap_fault.blank?
32
88
  end
33
89
 
34
90
  # Returns the SOAP fault message.
@@ -36,7 +92,7 @@ module Savon
36
92
 
37
93
  # Returns whether there was an HTTP error.
38
94
  def http_error?
39
- @http_error ? true : false
95
+ !@http_error.blank?
40
96
  end
41
97
 
42
98
  # Returns the HTTP error message.
@@ -54,13 +110,13 @@ module Savon
54
110
 
55
111
  # Returns the HTTP response object.
56
112
  attr_reader :http
57
-
113
+
58
114
  alias :to_s :to_xml
59
115
 
60
116
  private
61
117
 
62
- # Handles SOAP faults. Raises a Savon::SOAPFault unless the default
63
- # behavior of raising errors was turned off.
118
+ # Handles SOAP faults. Raises a Savon::SOAPFault unless the default behavior of raising errors
119
+ # was turned off.
64
120
  def handle_soap_fault
65
121
  if soap_fault_message
66
122
  @soap_fault = soap_fault_message
@@ -73,8 +129,8 @@ module Savon
73
129
  @soap_fault_message ||= soap_fault_message_by_version to_hash[:fault]
74
130
  end
75
131
 
76
- # Expects a Hash that might contain information about a SOAP fault.
77
- # Returns the SOAP fault message in case one was found.
132
+ # Expects a Hash that might contain information about a SOAP fault. Returns the SOAP fault
133
+ # message in case one was found.
78
134
  def soap_fault_message_by_version(soap_fault)
79
135
  return unless soap_fault
80
136
 
@@ -85,10 +141,10 @@ module Savon
85
141
  end
86
142
  end
87
143
 
88
- # Handles HTTP errors. Raises a Savon::HTTPError unless the default
89
- # behavior of raising errors was turned off.
144
+ # Handles HTTP errors. Raises a Savon::HTTPError unless the default behavior of raising errors
145
+ # was turned off.
90
146
  def handle_http_error
91
- if @http.code.to_i >= 300
147
+ if @http.code.to_i > MaxNonErrorResponseCode
92
148
  @http_error = "#{@http.message} (#{@http.code})"
93
149
  @http_error << ": #{@http.body}" unless @http.body.empty?
94
150
  raise Savon::HTTPError, http_error if self.class.raise_errors?
data/lib/savon/soap.rb CHANGED
@@ -1,12 +1,125 @@
1
1
  module Savon
2
2
 
3
- # == Savon::SOAP
3
+ # = Savon::SOAP
4
4
  #
5
- # Represents the SOAP parameters and envelope.
5
+ # Savon::SOAP represents the SOAP request. Pass a block to your SOAP call and the SOAP object is
6
+ # passed to it as the first argument. The object allows setting the SOAP version, header, body
7
+ # and namespaces per request.
8
+ #
9
+ # == Body
10
+ #
11
+ # The body method lets you specify parameters to be received by the SOAP action.
12
+ #
13
+ # You can either pass in a hash (which will be translated to XML via Hash.to_soap_xml):
14
+ #
15
+ # response = client.get_user_by_id do |soap|
16
+ # soap.body = { :id => 123 }
17
+ # end
18
+ #
19
+ # Or a string containing the raw XML:
20
+ #
21
+ # response = client.get_user_by_id do |soap|
22
+ # soap.body = "<id>123</id>"
23
+ # end
24
+ #
25
+ # Request output:
26
+ #
27
+ # <env:Envelope
28
+ # xmlns:wsdl="http://example.com/user/1.0/UserService"
29
+ # xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
30
+ # <env:Body>
31
+ # <wsdl:getUserById><id>123</id></wsdl:getUserById>
32
+ # </env:Body>
33
+ # </env:Envelope>
34
+ #
35
+ # Please look at the documentation of Hash.to_soap_xml for some more information.
36
+ #
37
+ # == Version
38
+ #
39
+ # Savon defaults to SOAP 1.1. In case your service uses SOAP 1.2, you can use the version method
40
+ # to change the default per request.
41
+ #
42
+ # response = client.get_all_users do |soap|
43
+ # soap.version = 2
44
+ # end
45
+ #
46
+ # You can also change the default to SOAP 1.2 for all request:
47
+ #
48
+ # Savon::SOAP.version = 2
49
+ #
50
+ # == Header
51
+ #
52
+ # If you need to add custom XML into the SOAP header, you can use the header method.
53
+ #
54
+ # The value is expected to be a hash (which will be translated to XML via Hash.to_soap_xml):
55
+ #
56
+ # response = client.get_all_users do |soap|
57
+ # soap.header["specialApiKey"] = "secret"
58
+ # end
59
+ #
60
+ # Or a string containing the raw XML:
61
+ #
62
+ # response = client.get_all_users do |soap|
63
+ # soap.header = "<specialApiKey>secret</specialApiKey>"
64
+ # end
65
+ #
66
+ # Request output:
67
+ #
68
+ # <env:Envelope
69
+ # xmlns:wsdl="http://example.com/user/1.0/UserService"
70
+ # xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
71
+ # <env:Header>
72
+ # <specialApiKey>secret</specialApiKey>
73
+ # </env:Header>
74
+ # <env:Body>
75
+ # <wsdl:getAllUsers></wsdl:getAllUsers>
76
+ # </env:Body>
77
+ # </env:Envelope>
78
+ #
79
+ # == Namespaces
80
+ #
81
+ # The namespaces method contains a hash of attributes for the SOAP envelope. You can overwrite it
82
+ # or add additional attributes.
83
+ #
84
+ # response = client.get_all_users do |soap|
85
+ # soap.namespaces["xmlns:domains"] = "http://domains.example.com"
86
+ # end
87
+ #
88
+ # Request output:
89
+ #
90
+ # <env:Envelope
91
+ # xmlns:wsdl="http://example.com/user/1.0/UserService"
92
+ # xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"
93
+ # xmlns:domains="http://domains.example.com">
94
+ # <env:Body>
95
+ # <wsdl:getAllUsers></wsdl:getAllUsers>
96
+ # </env:Body>
97
+ # </env:Envelope>
98
+ #
99
+ # == Input
100
+ #
101
+ # You can change the name of the SOAP input tag in case you need to.
102
+ #
103
+ # response = client.get_all_users do |soap|
104
+ # soap.input = "GetAllUsersRequest"
105
+ # end
106
+ #
107
+ # Request output:
108
+ #
109
+ # <env:Envelope
110
+ # xmlns:wsdl="http://example.com/user/1.0/UserService"
111
+ # xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
112
+ # <env:Body>
113
+ # <wsdl:GetAllUsersRequest></wsdl:GetAllUsersRequest>
114
+ # </env:Body>
115
+ # </env:Envelope>
6
116
  class SOAP
7
117
 
118
+ # Supported SOAP versions.
119
+ Versions = [1, 2]
120
+
8
121
  # SOAP namespaces by SOAP version.
9
- SOAPNamespace = {
122
+ Namespace = {
10
123
  1 => "http://schemas.xmlsoap.org/soap/envelope/",
11
124
  2 => "http://www.w3.org/2003/05/soap-envelope"
12
125
  }
@@ -14,6 +127,12 @@ module Savon
14
127
  # Content-Types by SOAP version.
15
128
  ContentType = { 1 => "text/xml", 2 => "application/soap+xml" }
16
129
 
130
+ # SOAP xs:dateTime format.
131
+ DateTimeFormat = "%Y-%m-%dT%H:%M:%SZ"
132
+
133
+ # SOAP xs:dateTime Regexp.
134
+ DateTimeRegexp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/
135
+
17
136
  # The global SOAP version.
18
137
  @@version = 1
19
138
 
@@ -24,11 +143,11 @@ module Savon
24
143
 
25
144
  # Sets the global SOAP version.
26
145
  def self.version=(version)
27
- @@version = version if Savon::SOAPVersions.include? version
146
+ @@version = version if Versions.include? version
28
147
  end
29
148
 
30
- # Sets the global SOAP header. Expected to be a Hash that can be translated
31
- # to XML via Hash.to_soap_xml or any other Object responding to to_s.
149
+ # Sets the global SOAP header. Expected to be a Hash that can be translated to XML via
150
+ # Hash.to_soap_xml or any other Object responding to to_s.
32
151
  def self.header=(header)
33
152
  @@header = header
34
153
  end
@@ -38,20 +157,22 @@ module Savon
38
157
  @@header ||= {}
39
158
  end
40
159
 
41
- # Sets the global namespaces. Expected to be a Hash containing the
42
- # namespaces (keys) and the corresponding URI's (values).
160
+ # Sets the global namespaces. Expected to be a Hash containing the namespaces (keys) and the
161
+ # corresponding URI's (values).
43
162
  def self.namespaces=(namespaces)
44
163
  @@namespaces = namespaces if namespaces.kind_of? Hash
45
164
  end
46
165
 
47
- # Returns the global namespaces. A Hash containing the namespaces (keys)
48
- # and the corresponding URI's (values).
166
+ # Returns the global namespaces. A Hash containing the namespaces (keys) and the corresponding
167
+ # URI's (values).
49
168
  def self.namespaces
50
169
  @@namespaces ||= {}
51
170
  end
52
171
 
53
- # Initialzes the SOAP object.
54
- def initialize
172
+ # Initialzes the SOAP object. Expects a SOAP +operation+ Hash along with an +endpoint+.
173
+ def initialize(action, input, endpoint)
174
+ @action, @input = action, input
175
+ @endpoint = endpoint.kind_of?(URI) ? endpoint : URI(endpoint)
55
176
  @builder = Builder::XmlMarkup.new
56
177
  end
57
178
 
@@ -77,8 +198,8 @@ module Savon
77
198
  # Accessor for the SOAP endpoint.
78
199
  attr_accessor :endpoint
79
200
 
80
- # Sets the SOAP header. Expected to be a Hash that can be translated
81
- # to XML via Hash.to_soap_xml or any other Object responding to to_s.
201
+ # Sets the SOAP header. Expected to be a Hash that can be translated to XML via Hash.to_soap_xml
202
+ # or any other Object responding to to_s.
82
203
  attr_writer :header
83
204
 
84
205
  # Returns the SOAP header. Defaults to an empty Hash.
@@ -86,28 +207,32 @@ module Savon
86
207
  @header ||= {}
87
208
  end
88
209
 
89
- # Sets the SOAP body. Expected to be a Hash that can be translated to
90
- # XML via Hash.to_soap_xml or any other Object responding to to_s.
91
- attr_writer :body
210
+ # Accessor for the SOAP body. Expected to be a Hash that can be translated to XML via Hash.to_soap_xml
211
+ # or any other Object responding to to_s.
212
+ attr_accessor :body
213
+
214
+ # Accessor for overwriting the default SOAP request. Let's you specify completely custom XML.
215
+ attr_accessor :xml
92
216
 
93
- # Sets the namespaces. Expected to be a Hash containing the namespaces
94
- # (keys) and the corresponding URI's (values).
217
+ # Sets the namespaces. Expected to be a Hash containing the namespaces (keys) and the
218
+ # corresponding URI's (values).
95
219
  attr_writer :namespaces
96
220
 
97
- # Returns the namespaces. A Hash containing the namespaces (keys)
98
- # and the corresponding URI's (values).
221
+ # Returns the namespaces. A Hash containing the namespaces (keys) and the corresponding URI's
222
+ # (values). Defaults to a Hash containing an +xmlns:env+ key and the namespace for the current
223
+ # SOAP version.
99
224
  def namespaces
100
- @namespaces ||= { "xmlns:env" => SOAPNamespace[version] }
225
+ @namespaces ||= { "xmlns:env" => Namespace[version] }
101
226
  end
102
227
 
103
- # Convenience method for setting the "xmlns:wsdl" namespace.
228
+ # Convenience method for setting the +xmlns:wsdl+ namespace.
104
229
  def namespace=(namespace)
105
230
  namespaces["xmlns:wsdl"] = namespace
106
231
  end
107
232
 
108
233
  # Sets the SOAP version.
109
234
  def version=(version)
110
- @version = version if Savon::SOAPVersions.include? version
235
+ @version = version if Versions.include? version
111
236
  end
112
237
 
113
238
  # Returns the SOAP version. Defaults to the global default.
@@ -117,60 +242,61 @@ module Savon
117
242
 
118
243
  # Returns the SOAP envelope XML.
119
244
  def to_xml
120
- unless @xml_body
121
- @xml_body = @builder.env :Envelope, all_namespaces do |xml|
122
- xml_header xml
245
+ unless @xml
246
+ @builder.instruct!
247
+ @xml = @builder.env :Envelope, merged_namespaces do |xml|
248
+ xml.env(:Header) { xml << merged_header } unless merged_header.empty?
123
249
  xml_body xml
124
250
  end
125
251
  end
126
- @xml_body
252
+ @xml
127
253
  end
128
254
 
129
255
  private
130
256
 
131
- # Adds a SOAP XML header to a given +xml+ Object.
132
- def xml_header(xml)
133
- xml.env(:Header) do
134
- xml << all_header + wsse_header
135
- end
136
- end
137
-
138
257
  # Returns a String containing the global and per request header.
139
- def all_header
258
+ def merged_header
140
259
  if self.class.header.kind_of?(Hash) && header.kind_of?(Hash)
141
- self.class.header.merge(header).to_soap_xml
260
+ merged_header = self.class.header.merge(header).to_soap_xml
142
261
  else
143
- self.class.header.to_s + header.to_s
262
+ global_header = self.class.header.to_soap_xml rescue self.class.header.to_s
263
+ request_header = header.to_soap_xml rescue header.to_s
264
+ merged_header = global_header + request_header
144
265
  end
266
+ merged_header + wsse_header
267
+ end
268
+
269
+ # Returns the WSSE header or an empty String in case WSSE was not set.
270
+ def wsse_header
271
+ @wsse.respond_to?(:header) ? @wsse.header : ""
145
272
  end
146
273
 
147
274
  # Adds a SOAP XML body to a given +xml+ Object.
148
275
  def xml_body(xml)
149
276
  xml.env(:Body) do
150
- xml.tag!(:wsdl, *input_array) do
151
- xml << (@body.to_soap_xml rescue @body.to_s)
152
- end
277
+ xml.tag!(:wsdl, *input_array) { xml << (@body.to_soap_xml rescue @body.to_s) }
153
278
  end
154
279
  end
155
280
 
156
281
  # Returns a Hash containing the global and per request namespaces.
157
- def all_namespaces
282
+ def merged_namespaces
158
283
  self.class.namespaces.merge namespaces
159
284
  end
160
285
 
161
- # Returns an Array of SOAP input names to append to the :wsdl namespace.
162
- # Defaults to use the name of the SOAP action and may be an empty Array
163
- # in case the specified SOAP input seems invalid.
286
+ # Returns an Array of SOAP input names to append to the wsdl namespace. Defaults to use the
287
+ # name of the SOAP action. May return an empty Array in case the specified SOAP input seems
288
+ # to be invalid.
164
289
  def input_array
165
- return [input.to_sym] unless input.blank?
166
- return [action.to_sym] unless action.blank?
167
- []
168
- end
169
-
170
- # Returns the WSSE header or an empty String in case WSSE was not set.
171
- def wsse_header
172
- @wsse.respond_to?(:header) ? @wsse.header : ""
290
+ if input.kind_of?(Array) && !input.blank?
291
+ [input[0].to_sym, input[1]]
292
+ elsif !input.blank?
293
+ [input.to_sym]
294
+ elsif !action.blank?
295
+ [action.to_sym]
296
+ else
297
+ []
298
+ end
173
299
  end
174
300
 
175
301
  end
176
- end
302
+ end