savon 0.6.0 → 0.7.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 (51) hide show
  1. data/CHANGELOG +112 -0
  2. data/README.textile +42 -35
  3. data/Rakefile +28 -33
  4. data/lib/savon/client.rb +42 -19
  5. data/lib/savon/core_ext/hash.rb +35 -22
  6. data/lib/savon/core_ext/net_http.rb +20 -0
  7. data/lib/savon/core_ext/object.rb +7 -0
  8. data/lib/savon/core_ext/string.rb +1 -1
  9. data/lib/savon/core_ext.rb +2 -2
  10. data/lib/savon/request.rb +73 -33
  11. data/lib/savon/response.rb +23 -36
  12. data/lib/savon/soap.rb +63 -30
  13. data/lib/savon/wsdl.rb +82 -35
  14. data/lib/savon/wsse.rb +41 -35
  15. data/lib/savon.rb +3 -2
  16. data/spec/basic_spec_helper.rb +12 -0
  17. data/spec/endpoint_helper.rb +22 -0
  18. data/spec/fixtures/response/response_fixture.rb +36 -0
  19. data/spec/fixtures/response/xml/authentication.xml +14 -0
  20. data/spec/fixtures/response/xml/multi_ref.xml +39 -0
  21. data/spec/fixtures/response/xml/soap_fault12.xml +18 -0
  22. data/spec/fixtures/wsdl/wsdl_fixture.rb +37 -0
  23. data/spec/fixtures/wsdl/xml/authentication.xml +63 -0
  24. data/spec/fixtures/wsdl/xml/namespaced_actions.xml +307 -0
  25. data/spec/fixtures/wsdl/xml/no_namespace.xml +115 -0
  26. data/spec/http_stubs.rb +17 -19
  27. data/spec/integration/http_basic_auth_spec.rb +12 -0
  28. data/spec/integration/server.rb +51 -0
  29. data/spec/savon/client_spec.rb +52 -44
  30. data/spec/savon/core_ext/datetime_spec.rb +2 -2
  31. data/spec/savon/core_ext/hash_spec.rb +34 -31
  32. data/spec/savon/core_ext/net_http_spec.rb +38 -0
  33. data/spec/savon/core_ext/object_spec.rb +16 -2
  34. data/spec/savon/core_ext/string_spec.rb +4 -4
  35. data/spec/savon/core_ext/symbol_spec.rb +1 -1
  36. data/spec/savon/core_ext/uri_spec.rb +1 -1
  37. data/spec/savon/request_spec.rb +49 -63
  38. data/spec/savon/response_spec.rb +48 -51
  39. data/spec/savon/savon_spec.rb +12 -19
  40. data/spec/savon/soap_spec.rb +81 -90
  41. data/spec/savon/wsdl_spec.rb +62 -30
  42. data/spec/savon/wsse_spec.rb +58 -84
  43. data/spec/spec_helper.rb +3 -13
  44. metadata +29 -15
  45. data/VERSION +0 -1
  46. data/spec/fixtures/multiple_user_response.xml +0 -22
  47. data/spec/fixtures/user_fixture.rb +0 -54
  48. data/spec/fixtures/user_response.xml +0 -15
  49. data/spec/fixtures/user_wsdl.xml +0 -124
  50. data/spec/spec_helper_methods.rb +0 -33
  51. /data/spec/fixtures/{soap_fault.xml → response/xml/soap_fault.xml} +0 -0
data/lib/savon/request.rb CHANGED
@@ -8,66 +8,97 @@ module Savon
8
8
  # Content-Types by SOAP version.
9
9
  ContentType = { 1 => "text/xml", 2 => "application/soap+xml" }
10
10
 
11
- # Defines whether to log HTTP requests.
12
- @log = true
11
+ # Whether to log HTTP requests.
12
+ @@log = true
13
13
 
14
14
  # The default logger.
15
- @logger = Logger.new STDOUT
15
+ @@logger = Logger.new STDOUT
16
16
 
17
17
  # The default log level.
18
- @log_level = :debug
18
+ @@log_level = :debug
19
19
 
20
- class << self
21
- # Sets whether to log HTTP requests.
22
- attr_writer :log
20
+ # Sets whether to log HTTP requests.
21
+ def self.log=(log)
22
+ @@log = log
23
+ end
23
24
 
24
- # Returns whether to log HTTP requests.
25
- def log?
26
- @log
27
- end
25
+ # Returns whether to log HTTP requests.
26
+ def self.log?
27
+ @@log
28
+ end
28
29
 
29
- # Accessor for the default logger.
30
- attr_accessor :logger
30
+ # Sets the logger.
31
+ def self.logger=(logger)
32
+ @@logger = logger
33
+ end
31
34
 
32
- # Accessor for the default log level.
33
- attr_accessor :log_level
35
+ # Returns the logger.
36
+ def self.logger
37
+ @@logger
34
38
  end
35
39
 
36
- # Expects an endpoint String. Raises an exception in case the given
37
- # +endpoint+ does not seem to be valid.
38
- def initialize(endpoint)
39
- raise ArgumentError, "Invalid endpoint: #{endpoint}" unless
40
- /^(http|https):\/\// === endpoint
40
+ # Sets the log level.
41
+ def self.log_level=(log_level)
42
+ @@log_level = log_level
43
+ end
41
44
 
45
+ # Returns the log level.
46
+ def self.log_level
47
+ @@log_level
48
+ end
49
+
50
+ # Expects a SOAP +endpoint+ String. Also accepts an optional Hash
51
+ # of +options+ for specifying a proxy server.
52
+ def initialize(endpoint, options = {})
42
53
  @endpoint = URI endpoint
54
+ @proxy = options[:proxy] ? URI(options[:proxy]) : URI("")
43
55
  end
44
56
 
45
57
  # Returns the endpoint URI.
46
58
  attr_reader :endpoint
47
59
 
48
- # Retrieves WSDL document and returns the Net::HTTPResponse.
60
+ # Returns the proxy URI.
61
+ attr_reader :proxy
62
+
63
+ # Sets the +username+ and +password+ for HTTP basic authentication.
64
+ def basic_auth(username, password)
65
+ @basic_auth = [username, password]
66
+ end
67
+
68
+ # Retrieves WSDL document and returns the Net::HTTP response.
49
69
  def wsdl
50
70
  log "Retrieving WSDL from: #{@endpoint}"
51
- http.get @endpoint.to_s
71
+ http.endpoint @endpoint.host, @endpoint.port
72
+ http.use_ssl = @endpoint.ssl?
73
+ http.start { |h| h.request request(:wsdl) }
52
74
  end
53
75
 
54
76
  # Executes a SOAP request using a given Savon::SOAP instance and
55
- # returns the Net::HTTPResponse.
77
+ # returns the Net::HTTP response.
56
78
  def soap(soap)
57
79
  @soap = soap
80
+ http.endpoint @soap.endpoint.host, @soap.endpoint.port
81
+ http.use_ssl = @soap.endpoint.ssl?
58
82
 
59
83
  log_request
60
- @response = http.request_post @endpoint.path, @soap.to_xml, http_header
84
+ @response = http.start do |h|
85
+ h.request request(:soap) { |request| request.body = @soap.to_xml }
86
+ end
61
87
  log_response
62
88
  @response
63
89
  end
64
90
 
91
+ # Returns the Net::HTTP object.
92
+ def http
93
+ @http ||= Net::HTTP::Proxy(@proxy.host, @proxy.port).new @endpoint.host, @endpoint.port
94
+ end
95
+
65
96
  private
66
97
 
67
98
  # Logs the SOAP request.
68
99
  def log_request
69
- log "SOAP request: #{@endpoint}"
70
- log http_header.map { |key, value| "#{key}: #{value}" }.join ", "
100
+ log "SOAP request: #{@soap.endpoint}"
101
+ log http_header.map { |key, value| "#{key}: #{value}" }.join(", ")
71
102
  log @soap.to_xml
72
103
  end
73
104
 
@@ -77,13 +108,22 @@ module Savon
77
108
  log @response.body
78
109
  end
79
110
 
80
- # Returns a Net::HTTP instance.
81
- def http
82
- unless @http
83
- @http ||= Net::HTTP.new @endpoint.host, @endpoint.port
84
- @http.use_ssl = true if @endpoint.ssl?
111
+ # Returns a Net::HTTP request for a given +type+. Yields the request
112
+ # to an optional block.
113
+ def request(type)
114
+ request = case type
115
+ when :wsdl then Net::HTTP::Get.new wsdl_endpoint
116
+ when :soap then Net::HTTP::Post.new @soap.endpoint.path, http_header
85
117
  end
86
- @http
118
+ request.basic_auth *@basic_auth if @basic_auth
119
+ yield request if block_given?
120
+ request
121
+ end
122
+
123
+ # Returns the WSDL endpoint.
124
+ def wsdl_endpoint
125
+ return @endpoint.path unless @endpoint.query
126
+ "#{@endpoint.path}?#{@endpoint.query}"
87
127
  end
88
128
 
89
129
  # Returns a Hash containing the header for an HTTP request.
@@ -96,7 +136,7 @@ module Savon
96
136
  self.class.logger.send self.class.log_level, message if log?
97
137
  end
98
138
 
99
- # Returns whether logging is possible.
139
+ # Returns whether to log.
100
140
  def log?
101
141
  self.class.log? && self.class.logger.respond_to?(self.class.log_level)
102
142
  end
@@ -5,19 +5,17 @@ module Savon
5
5
  # Represents the HTTP and SOAP response.
6
6
  class Response
7
7
 
8
- # The default of whether to raise errors.
9
- @raise_errors = true
8
+ # The global setting of whether to raise errors.
9
+ @@raise_errors = true
10
10
 
11
- class << self
12
-
13
- # Sets the default of whether to raise errors.
14
- attr_writer :raise_errors
15
-
16
- # Returns the default of whether to raise errors.
17
- def raise_errors?
18
- @raise_errors
19
- end
11
+ # Sets the global setting of whether to raise errors.
12
+ def self.raise_errors=(raise_errors)
13
+ @@raise_errors = raise_errors
14
+ end
20
15
 
16
+ # Returns the global setting of whether to raise errors.
17
+ def self.raise_errors?
18
+ @@raise_errors
21
19
  end
22
20
 
23
21
  # Expects a Net::HTTPResponse and handles errors.
@@ -30,7 +28,7 @@ module Savon
30
28
 
31
29
  # Returns whether there was a SOAP fault.
32
30
  def soap_fault?
33
- @soap_fault
31
+ @soap_fault ? true : false
34
32
  end
35
33
 
36
34
  # Returns the SOAP fault message.
@@ -38,15 +36,15 @@ module Savon
38
36
 
39
37
  # Returns whether there was an HTTP error.
40
38
  def http_error?
41
- @http_error
39
+ @http_error ? true : false
42
40
  end
43
41
 
44
42
  # Returns the HTTP error message.
45
43
  attr_reader :http_error
46
44
 
47
- # Returns the SOAP response as a Hash.
45
+ # Returns the SOAP response body as a Hash.
48
46
  def to_hash
49
- @body.find_regexp(/.+/).map_soap_response
47
+ @body ||= Crack::XML.parse(@response.body).find_soap_body
50
48
  end
51
49
 
52
50
  # Returns the SOAP response XML.
@@ -54,44 +52,33 @@ module Savon
54
52
  @response.body
55
53
  end
56
54
 
57
- alias :to_s :to_xml
55
+ alias :to_s :to_xml
58
56
 
59
57
  private
60
58
 
61
- # Returns the SOAP response body as a Hash.
62
- def body
63
- unless @body
64
- body = Crack::XML.parse @response.body
65
- @body = body.find_regexp [/.+:Envelope/, /.+:Body/]
66
- end
67
- @body
68
- end
69
-
70
59
  # Handles SOAP faults. Raises a Savon::SOAPFault unless the default
71
60
  # behavior of raising errors was turned off.
72
61
  def handle_soap_fault
73
62
  if soap_fault_message
74
63
  @soap_fault = soap_fault_message
75
- raise Savon::SOAPFault, soap_fault_message if self.class.raise_errors?
64
+ raise Savon::SOAPFault, @soap_fault if self.class.raise_errors?
76
65
  end
77
66
  end
78
67
 
79
68
  # Returns a SOAP fault message in case a SOAP fault was found.
80
69
  def soap_fault_message
81
- unless @soap_fault_message
82
- soap_fault = body.find_regexp [/.+:Fault/]
83
- @soap_fault_message = soap_fault_message_by_version(soap_fault)
84
- end
85
- @soap_fault_message
70
+ @soap_fault_message ||= soap_fault_message_by_version to_hash[:fault]
86
71
  end
87
72
 
88
73
  # Expects a Hash that might contain information about a SOAP fault.
89
74
  # Returns the SOAP fault message in case one was found.
90
75
  def soap_fault_message_by_version(soap_fault)
91
- if soap_fault.keys.include? "faultcode"
92
- "(#{soap_fault['faultcode']}) #{soap_fault['faultstring']}"
93
- elsif soap_fault.keys.include? "code"
94
- "(#{soap_fault['code']['value']}) #{soap_fault['reason']['text']}"
76
+ return unless soap_fault
77
+
78
+ if soap_fault.keys.include? :faultcode
79
+ "(#{soap_fault[:faultcode]}) #{soap_fault[:faultstring]}"
80
+ elsif soap_fault.keys.include? :code
81
+ "(#{soap_fault[:code][:value]}) #{soap_fault[:reason][:text]}"
95
82
  end
96
83
  end
97
84
 
@@ -100,7 +87,7 @@ module Savon
100
87
  def handle_http_error
101
88
  if @response.code.to_i >= 300
102
89
  @http_error = "#{@response.message} (#{@response.code})"
103
- @http_error += ": #{@response.body}" unless @response.body.empty?
90
+ @http_error << ": #{@response.body}" unless @response.body.empty?
104
91
  raise Savon::HTTPError, http_error if self.class.raise_errors?
105
92
  end
106
93
  end
data/lib/savon/soap.rb CHANGED
@@ -14,32 +14,44 @@ module Savon
14
14
  # Content-Types by SOAP version.
15
15
  ContentType = { 1 => "text/xml", 2 => "application/soap+xml" }
16
16
 
17
- # The default SOAP version.
18
- @version = 1
17
+ # The global SOAP version.
18
+ @@version = 1
19
19
 
20
- class << self
21
-
22
- # Returns the default SOAP version.
23
- attr_reader :version
24
-
25
- # Sets the default SOAP version.
26
- def version=(version)
27
- @version = version if Savon::SOAPVersions.include? version
28
- end
20
+ # Returns the global SOAP version.
21
+ def self.version
22
+ @@version
23
+ end
29
24
 
25
+ # Sets the global SOAP version.
26
+ def self.version=(version)
27
+ @@version = version if Savon::SOAPVersions.include? version
30
28
  end
31
29
 
32
- # Expects an +action_map+ containing the name of the SOAP action and input.
33
- def initialize(action_map)
34
- @action = action_map[:name]
35
- @input = action_map[:input]
30
+ def initialize
31
+ @builder = Builder::XmlMarkup.new
36
32
  end
37
33
 
38
34
  # Sets the WSSE options.
39
35
  attr_writer :wsse
40
36
 
41
- # Accessor for the SOAP action.
42
- attr_accessor :action
37
+ # Sets the SOAP action.
38
+ attr_writer :action
39
+
40
+ # Returns the SOAP action.
41
+ def action
42
+ @action ||= ""
43
+ end
44
+
45
+ # Sets the SOAP input.
46
+ attr_writer :input
47
+
48
+ # Returns the SOAP input.
49
+ def input
50
+ @input ||= ""
51
+ end
52
+
53
+ # Accessor for the SOAP endpoint.
54
+ attr_accessor :endpoint
43
55
 
44
56
  # Sets the SOAP header. Expected to be a Hash that can be translated
45
57
  # to XML via Hash.to_soap_xml or any other Object responding to to_s.
@@ -64,6 +76,11 @@ module Savon
64
76
  @namespaces ||= { "xmlns:env" => SOAPNamespace[version] }
65
77
  end
66
78
 
79
+ # Convenience method for setting the "xmlns:wsdl" namespace.
80
+ def namespace=(namespace)
81
+ namespaces["xmlns:wsdl"] = namespace
82
+ end
83
+
67
84
  # Sets the SOAP version.
68
85
  def version=(version)
69
86
  @version = version if Savon::SOAPVersions.include? version
@@ -77,17 +94,9 @@ module Savon
77
94
  # Returns the SOAP envelope XML.
78
95
  def to_xml
79
96
  unless @xml_body
80
- builder = Builder::XmlMarkup.new
81
-
82
- @xml_body = builder.env :Envelope, namespaces do |xml|
83
- xml.env(:Header) do
84
- xml << (header.to_soap_xml rescue header.to_s) + wsse_header
85
- end
86
- xml.env(:Body) do
87
- xml.wsdl(@input.to_sym) do
88
- xml << (@body.to_soap_xml rescue @body.to_s)
89
- end
90
- end
97
+ @xml_body = @builder.env :Envelope, namespaces do |xml|
98
+ xml_header xml
99
+ xml_body xml
91
100
  end
92
101
  end
93
102
  @xml_body
@@ -95,10 +104,34 @@ module Savon
95
104
 
96
105
  private
97
106
 
107
+ # Adds a SOAP XML header to a given +xml+ Object.
108
+ def xml_header(xml)
109
+ xml.env(:Header) do
110
+ xml << (header.to_soap_xml rescue header.to_s) + wsse_header
111
+ end
112
+ end
113
+
114
+ # Adds a SOAP XML body to a given +xml+ Object.
115
+ def xml_body(xml)
116
+ xml.env(:Body) do
117
+ xml.tag!(:wsdl, *input_array) do
118
+ xml << (@body.to_soap_xml rescue @body.to_s)
119
+ end
120
+ end
121
+ end
122
+
123
+ # Returns an Array of SOAP input names to append to the :wsdl namespace.
124
+ # Defaults to use the name of the SOAP action and may be an empty Array
125
+ # in case the specified SOAP input seems invalid.
126
+ def input_array
127
+ return [input.to_sym] unless input.blank?
128
+ return [action.to_sym] unless action.blank?
129
+ []
130
+ end
131
+
98
132
  # Returns the WSSE header or an empty String in case WSSE was not set.
99
133
  def wsse_header
100
- return "" unless @wsse.respond_to? :header
101
- @wsse.header
134
+ @wsse.respond_to?(:header) ? @wsse.header : ""
102
135
  end
103
136
 
104
137
  end
data/lib/savon/wsdl.rb CHANGED
@@ -2,74 +2,121 @@ module Savon
2
2
 
3
3
  # Savon::WSDL
4
4
  #
5
- # Represents a WSDL document.
5
+ # Represents the WSDL document.
6
6
  class WSDL
7
7
 
8
- # Expects a Savon::Request object.
8
+ # Initializer, expects a Savon::Request.
9
9
  def initialize(request)
10
10
  @request = request
11
11
  end
12
12
 
13
- # Returns the namespace URI from the WSDL.
13
+ # Sets whether to use the WSDL.
14
+ attr_writer :enabled
15
+
16
+ # Returns whether to use the WSDL. Defaults to +true+.
17
+ def enabled?
18
+ @enabled.nil? ? true : @enabled
19
+ end
20
+
21
+ # Returns the namespace URI of the WSDL.
14
22
  def namespace_uri
15
- @namespace_uri ||= parse_namespace_uri
23
+ @namespace_uri ||= stream.namespace_uri
16
24
  end
17
25
 
18
- # Returns a Hash of available SOAP actions mapped to snake_case (keys)
19
- # and their original names and inputs in another Hash (values).
26
+ # Returns an Array of available SOAP actions.
20
27
  def soap_actions
21
- @soap_actions ||= parse_soap_operations.inject({}) do |hash, (input, action)|
22
- hash.merge input.snakecase.to_sym => { :name => action, :input => input }
23
- end
28
+ @soap_actions ||= stream.operations.keys
29
+ end
30
+
31
+ # Returns a Hash of SOAP operations including their corresponding
32
+ # SOAP actions and inputs.
33
+ def operations
34
+ @operations ||= stream.operations
35
+ end
36
+
37
+ # Returns the SOAP endpoint.
38
+ def soap_endpoint
39
+ @soap_endpoint ||= stream.soap_endpoint
24
40
  end
25
41
 
26
42
  # Returns +true+ for available methods and SOAP actions.
27
43
  def respond_to?(method)
28
- return true if soap_actions.keys.include? method
44
+ return true if soap_actions.include? method
29
45
  super
30
46
  end
31
47
 
32
- # Returns the WSDL document.
48
+ # Returns the raw WSDL document.
33
49
  def to_s
34
- wsdl_response.body
50
+ @document ||= @request.wsdl.body
35
51
  end
36
52
 
37
53
  private
38
54
 
39
- # Retrieves and returns the WSDL response. Raises an ArgumentError in
40
- # case the WSDL seems to be invalid.
41
- def wsdl_response
42
- unless @wsdl_response
43
- @wsdl_response ||= @request.wsdl
44
- raise ArgumentError, "Invalid WSDL: #{@request.endpoint}" if soap_actions.empty?
55
+ # Returns the Savon::WSDLStream.
56
+ def stream
57
+ unless @stream
58
+ @stream = WSDLStream.new
59
+ REXML::Document.parse_stream to_s, @stream
45
60
  end
46
- @wsdl_response
61
+ @stream
62
+ end
63
+
64
+ end
65
+
66
+ # Savon::WSDLStream
67
+ #
68
+ # Stream listener for parsing the WSDL document.
69
+ class WSDLStream
70
+
71
+ # The main sections of a WSDL document.
72
+ Sections = %w(definitions types message portType binding service)
73
+
74
+ def initialize
75
+ @depth, @operations = 0, {}
47
76
  end
48
77
 
49
- # Returns a REXML::Document of the WSDL.
50
- def document
51
- @document ||= REXML::Document.new wsdl_response.body
78
+ # Returns the namespace URI.
79
+ attr_reader :namespace_uri
80
+
81
+ # Returns the SOAP operations.
82
+ attr_reader :operations
83
+
84
+ # Returns the SOAP endpoint.
85
+ attr_reader :soap_endpoint
86
+
87
+ # Hook method called when the stream parser encounters a starting tag.
88
+ def tag_start(tag, attrs)
89
+ @depth += 1
90
+ tag = tag.strip_namespace
91
+
92
+ @section = tag.to_sym if @depth <= 2 && Sections.include?(tag)
93
+ @namespace_uri ||= attrs["targetNamespace"] if @section == :definitions
94
+ @soap_endpoint ||= URI(attrs["location"]) if @section == :service && tag == "address"
95
+
96
+ operation_from tag, attrs if @section == :binding && tag == "operation"
52
97
  end
53
98
 
54
- # Parses the WSDL for the namespace URI.
55
- def parse_namespace_uri
56
- definitions = document.elements["//wsdl:definitions"]
57
- definitions.attributes["targetNamespace"] if definitions
99
+ # Hook method called when the stream parser encounters a closing tag.
100
+ def tag_end(tag)
101
+ @depth -= 1
58
102
  end
59
103
 
60
- # Parses the WSDL for available SOAP actions and inputs. Returns a Hash
61
- # containing the SOAP action inputs and corresponding SOAP actions.
62
- def parse_soap_operations
63
- wsdl_binding = document.elements["//wsdl:binding"]
64
- return {} unless wsdl_binding
104
+ # Stores available operations from a given tag +name+ and +attrs+.
105
+ def operation_from(tag, attrs)
106
+ @input = attrs["name"] if attrs["name"]
65
107
 
66
- wsdl_binding.elements.inject("//wsdl:operation", {}) do |hash, operation|
67
- action = operation.elements["*:operation"].attributes["soapAction"] || ""
68
- action = operation.attributes["name"] if action.empty?
108
+ if attrs["soapAction"]
109
+ @action = !attrs["soapAction"].blank? ? attrs["soapAction"] : @input
110
+ @input = @action.split("/").last if !@input || @input.empty?
69
111
 
70
- hash.merge action.split("/").last => action
112
+ @operations[@input.snakecase.to_sym] = { :action => @action, :input => @input }
113
+ @input, @action = nil, nil
71
114
  end
72
115
  end
73
116
 
117
+ # Catches calls to unimplemented hook methods.
118
+ def method_missing(method, *args)
119
+ end
120
+
74
121
  end
75
122
  end
data/lib/savon/wsse.rb CHANGED
@@ -11,73 +11,79 @@ module Savon
11
11
  # Namespace for WS Security Utility.
12
12
  WSUNamespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
13
13
 
14
- # Default WSSE username.
15
- @username = ""
14
+ # Global WSSE username.
15
+ @@username = nil
16
16
 
17
- # Default WSSE password.
18
- @password = ""
19
-
20
- # Default for whether to use WSSE digest.
21
- @digest = false
22
-
23
- class << self
17
+ # Returns the global WSSE username.
18
+ def self.username
19
+ @@username
20
+ end
24
21
 
25
- # Returns the default WSSE username.
26
- attr_reader :username
22
+ # Sets the global WSSE username.
23
+ def self.username=(username)
24
+ @@username = username.to_s if username.respond_to? :to_s
25
+ @@username = nil if username.nil?
26
+ end
27
27
 
28
- # Sets the default WSSE username.
29
- def username=(username)
30
- @username = username.to_s if username.respond_to? :to_s
31
- end
28
+ # Global WSSE password.
29
+ @@password = nil
32
30
 
33
- # Returns the default WSSE password.
34
- attr_reader :password
31
+ # Returns the global WSSE password.
32
+ def self.password
33
+ @@password
34
+ end
35
35
 
36
- # Sets the default WSSE password.
37
- def password=(password)
38
- @password = password.to_s if password.respond_to? :to_s
39
- end
36
+ # Sets the global WSSE password.
37
+ def self.password=(password)
38
+ @@password = password.to_s if password.respond_to? :to_s
39
+ @@password = nil if password.nil?
40
+ end
40
41
 
41
- # Sets whether to use WSSE digest by default.
42
- attr_writer :digest
42
+ # Global setting of whether to use WSSE digest.
43
+ @@digest = false
43
44
 
44
- # Returns whether to use WSSE digest by default.
45
- def digest?
46
- @digest
47
- end
45
+ # Returns the global setting of whether to use WSSE digest.
46
+ def self.digest?
47
+ @@digest
48
+ end
48
49
 
50
+ # Global setting of whether to use WSSE digest.
51
+ def self.digest=(digest)
52
+ @@digest = digest
49
53
  end
50
54
 
51
- # Sets the WSSE username.
55
+ # Sets the WSSE username per request.
52
56
  def username=(username)
53
57
  @username = username.to_s if username.respond_to? :to_s
58
+ @username = nil if username.nil?
54
59
  end
55
60
 
56
- # Returns the WSSE username. Defaults to the global default.
61
+ # Returns the WSSE username. Defaults to the global setting.
57
62
  def username
58
63
  @username || self.class.username
59
64
  end
60
65
 
61
- # Sets the WSSE password.
66
+ # Sets the WSSE password per request.
62
67
  def password=(password)
63
68
  @password = password.to_s if password.respond_to? :to_s
69
+ @password = nil if password.nil?
64
70
  end
65
71
 
66
- # Returns the WSSE password. Defaults to the global default.
72
+ # Returns the WSSE password. Defaults to the global setting.
67
73
  def password
68
74
  @password || self.class.password
69
75
  end
70
76
 
71
- # Sets whether to use WSSE digest.
77
+ # Sets whether to use WSSE digest per request.
72
78
  attr_writer :digest
73
79
 
74
- # Returns whether to use WSSE digest. Defaults to the global default.
80
+ # Returns whether to use WSSE digest. Defaults to the global setting.
75
81
  def digest?
76
82
  @digest || self.class.digest?
77
83
  end
78
84
 
79
- # Returns the XML for a WSSE header or an empty String unless username
80
- # and password are specified.
85
+ # Returns the XML for a WSSE header or an empty String unless both
86
+ # username and password were specified.
81
87
  def header
82
88
  return "" unless username && password
83
89