savon 0.9.2 → 0.9.3

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.
data/.gitignore CHANGED
@@ -3,6 +3,7 @@
3
3
  doc
4
4
  coverage
5
5
  tmp
6
+ *.rbc
6
7
  *~
7
8
  *.gem
8
9
  .bundle
data/.travis.yml CHANGED
@@ -1,7 +1,8 @@
1
- script: "rake"
2
1
  rvm:
3
2
  - 1.8.7
4
3
  - 1.9.2
4
+ - ruby-head
5
5
  - ree
6
6
  - rbx
7
+ - rbx-2.0
7
8
  - jruby
data/CHANGELOG.md CHANGED
@@ -1,6 +1,40 @@
1
+ ## 0.9.3 (2011-06-30)
2
+
3
+ * Fix: [issue 138](https://github.com/rubiii/savon/issues/138) -
4
+ Savon now supports setting a global SOAP header via `Savon.soap_header=`.
5
+
6
+ * Fixed the namespace for wsse message timestamps from `wsse:Timestamp`
7
+ to `wsu:Timestamp` as required by the specification.
8
+
9
+ * Change: Removed support for NTLM authentication until it's stable. If you need it, you can still
10
+ add the following line to your Gemfile:
11
+
12
+ gem "httpi", "0.9.4"
13
+
14
+ * Refactoring:
15
+
16
+ * `Hash#map_soap_response` and some of its helpers are moved to [Nori v1.0.0](http://rubygems.org/gems/nori/versions/1.0.0).
17
+ Along with replacing core extensions with a proper implementation, Nori now contains a number of methods
18
+ for configuring its default behavior:
19
+
20
+ * The option whether to strip namespaces was moved to Nori.strip_namespaces
21
+ * You can disable "advanced typecasting" for SOAP response values
22
+ * And you can configure how SOAP response keys should be converted
23
+
24
+ Please take a look at [Nori's CHANGELOG](https://github.com/rubiii/nori/blob/master/CHANGELOG.md)
25
+ for detailed information.
26
+
27
+ * `Savon::SOAP::XML.to_hash`, `Savon::SOAP::XML.parse` and `Savon::SOAP::XML.to_array` are gone.
28
+ It wasn't worth keeping them around, because they didn't do much. You can simply parse a SOAP
29
+ response and translate it to a Savon SOAP response Hash via:
30
+
31
+ Nori.parse(xml)[:envelope][:body]
32
+
33
+ * `Savon::SOAP::Response#basic_hash` is now `Savon::SOAP::Response#hash`.
34
+
1
35
  ## 0.9.2 (2011-04-30)
2
36
 
3
- * Fix: [issue](https://github.com/rubiii/savon/pull/154) -
37
+ * Fix: [issue 154](https://github.com/rubiii/savon/pull/154) -
4
38
  Timezone format used by Savon now matches the XML schema spec.
5
39
 
6
40
  * Improvement: WSSE basic, digest and timestamp authentication are no longer mutually exclusive.
data/README.md CHANGED
@@ -1,9 +1,10 @@
1
- Savon
1
+ Savon [![Build Status](http://travis-ci.org/rubiii/savon.png)](http://travis-ci.org/rubiii/savon)
2
2
  =====
3
3
 
4
4
  Heavy metal Ruby SOAP client
5
5
 
6
- [Official documentation](http://savonrb.com) | [RDoc](http://rubydoc.info/gems/savon) | [Google Group](http://groups.google.com/group/savon-soap)
6
+ [Documentation](http://savonrb.com) | [RDoc](http://rubydoc.info/gems/savon) |
7
+ [Mailing list](http://groups.google.com/group/savon-soap) | [Twitter](http://twitter.com/savonrb)
7
8
 
8
9
  Installation
9
10
  ------------
@@ -33,7 +34,7 @@ response.to_hash
33
34
  # => { :get_user_response => { :first_name => "The", :last_name => "Hoff" } }
34
35
  ```
35
36
 
36
- Excited to learn more?
37
- ----------------------
37
+ Ready for more?
38
+ ---------------
38
39
 
39
- Then you might want to [go ahead and read the official documentation](http://savonrb.com).
40
+ [Go ahead and read the official documentation](http://savonrb.com).
data/Rakefile CHANGED
@@ -1,39 +1,8 @@
1
1
  require "rake"
2
+ require "rspec/core/rake_task"
2
3
 
3
- begin
4
- require "yard"
5
-
6
- YARD::Rake::YardocTask.new do |t|
7
- t.files = ["README.md", "lib/**/*.rb"]
8
- end
9
- rescue LoadError
10
- desc message = %{run "bundle install" to generate documentation}
11
- task("yard") { abort message }
12
- end
13
-
14
- begin
15
- require "metric_fu"
16
-
17
- MetricFu::Configuration.run do |c|
18
- c.metrics = [:churn, :flog, :flay, :reek, :roodi, :saikuro] # :rcov seems to be broken
19
- c.graphs = [:flog, :flay, :reek, :roodi]
20
- c.flay = { :dirs_to_flay => ["lib"], :minimum_score => 20 }
21
- c.rcov[:rcov_opts] << "-Ilib -Ispec"
22
- end
23
- rescue LoadError
24
- desc message = %{run "bundle install" to generate metrics}
25
- task("metrics:all") { abort message }
26
- end
27
-
28
- begin
29
- require "rspec/core/rake_task"
30
-
31
- RSpec::Core::RakeTask.new do |t|
32
- t.rspec_opts = %w(-c)
33
- end
34
- rescue LoadError
35
- desc message = %{run "bundle install" to run the specs}
36
- task(:spec) { abort message }
4
+ RSpec::Core::RakeTask.new do |t|
5
+ t.rspec_opts = %w(-c)
37
6
  end
38
7
 
39
8
  task :default => :spec
data/lib/savon/client.rb CHANGED
@@ -113,7 +113,7 @@ module Savon
113
113
  soap.namespace_identifier = options[0]
114
114
  soap.namespace = wsdl.namespace
115
115
  soap.element_form_default = wsdl.element_form_default if wsdl.present?
116
- soap.body = options[2].delete(:body) if options[2][:body]
116
+ soap.body = options[2].delete(:body)
117
117
 
118
118
  set_soap_action options[1]
119
119
  set_soap_input *options
@@ -5,7 +5,7 @@ module Savon
5
5
  # Returns +true+ if the Object is nil, false or empty. Implementation from ActiveSupport.
6
6
  def blank?
7
7
  respond_to?(:empty?) ? empty? : !self
8
- end unless defined? blank?
8
+ end unless method_defined?(:blank?)
9
9
 
10
10
  end
11
11
  end
@@ -14,7 +14,7 @@ module Savon
14
14
  str.tr! "-", "_"
15
15
  str.downcase!
16
16
  str
17
- end
17
+ end unless method_defined?(:snakecase)
18
18
 
19
19
  # Returns the String in lowerCamelCase.
20
20
  def lower_camelcase
@@ -29,20 +29,7 @@ module Savon
29
29
  def starts_with?(prefix)
30
30
  prefix = prefix.to_s
31
31
  self[0, prefix.length] == prefix
32
- end unless defined? starts_with?
33
-
34
- # Returns the String without namespace.
35
- def strip_namespace
36
- split(":").last
37
- end
38
-
39
- # Translates SOAP response values to Ruby Objects.
40
- def map_soap_response
41
- return ::DateTime.parse(self) if Savon::SOAP::DateTimeRegexp === self
42
- return true if self.strip.downcase == "true"
43
- return false if self.strip.downcase == "false"
44
- self
45
- end
32
+ end unless method_defined?(:starts_with?)
46
33
 
47
34
  end
48
35
  end
data/lib/savon/global.rb CHANGED
@@ -55,11 +55,15 @@ module Savon
55
55
  # Returns whether to strip namespaces in a SOAP response Hash.
56
56
  # Defaults to +true+.
57
57
  def strip_namespaces?
58
- @strip_namespaces != false
58
+ Savon.deprecate("use Nori.strip_namespaces? instead of Savon.strip_namespaces?")
59
+ Nori.strip_namespaces?
59
60
  end
60
61
 
61
62
  # Sets whether to strip namespaces in a SOAP response Hash.
62
- attr_writer :strip_namespaces
63
+ def strip_namespaces=(strip)
64
+ Savon.deprecate("use Nori.strip_namespaces= instead of Savon.strip_namespaces=")
65
+ Nori.strip_namespaces = strip
66
+ end
63
67
 
64
68
  # Returns the global env_namespace.
65
69
  attr_reader :env_namespace
@@ -67,6 +71,27 @@ module Savon
67
71
  # Sets the global env_namespace.
68
72
  attr_writer :env_namespace
69
73
 
74
+ # Returns the global soap_header.
75
+ attr_reader :soap_header
76
+
77
+ # Sets the global soap_header.
78
+ attr_writer :soap_header
79
+
80
+ # Expects a +message+ and raises a warning if configured.
81
+ def deprecate(message)
82
+ warn("Deprecation: #{message}") if deprecate?
83
+ end
84
+
85
+ # Sets whether to warn about deprecations.
86
+ def deprecate=(deprecate)
87
+ @deprecate = deprecate
88
+ end
89
+
90
+ # Returns whether to warn about deprecation.
91
+ def deprecate?
92
+ @deprecate != false
93
+ end
94
+
70
95
  # Reset to default configuration.
71
96
  def reset_config!
72
97
  self.log = true
@@ -76,6 +101,7 @@ module Savon
76
101
  self.soap_version = SOAP::DefaultVersion
77
102
  self.strip_namespaces = true
78
103
  self.env_namespace = nil
104
+ self.soap_header = {}
79
105
  end
80
106
 
81
107
  end
data/lib/savon/soap.rb CHANGED
@@ -17,8 +17,5 @@ module Savon
17
17
  2 => "http://www.w3.org/2003/05/soap-envelope"
18
18
  }
19
19
 
20
- # SOAP xs:dateTime Regexp.
21
- DateTimeRegexp = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/
22
-
23
20
  end
24
21
  end
@@ -30,7 +30,7 @@ module Savon
30
30
 
31
31
  # Returns the SOAP response body as a Hash.
32
32
  def to_hash
33
- @hash ||= Savon::SOAP::XML.to_hash http.body
33
+ @hash ||= Nori.parse(http.body)[:envelope][:body]
34
34
  end
35
35
 
36
36
  private
@@ -12,6 +12,12 @@ module Savon
12
12
  # Content-Types by SOAP version.
13
13
  ContentType = { 1 => "text/xml;charset=UTF-8", 2 => "application/soap+xml;charset=UTF-8" }
14
14
 
15
+ # Expects an <tt>HTTPI::Request</tt> and a <tt>Savon::SOAP::XML</tt> object
16
+ # to execute a SOAP request and returns the response.
17
+ def self.execute(request, soap)
18
+ new(request, soap).response
19
+ end
20
+
15
21
  # Expects an <tt>HTTPI::Request</tt> and a <tt>Savon::SOAP::XML</tt> object.
16
22
  def initialize(request, soap)
17
23
  self.request = setup(request, soap)
@@ -43,29 +43,38 @@ module Savon
43
43
  @http_error ||= HTTP::Error.new http
44
44
  end
45
45
 
46
- # Returns the SOAP response header as a Hash.
47
- def header
48
- @header_hash ||= basic_hash.find_soap_header
46
+ # Shortcut accessor for the SOAP response body Hash.
47
+ def [](key)
48
+ body[key]
49
49
  end
50
50
 
51
- # Shortcut for the +to_hash+ method.
52
- def [](key)
53
- to_hash[key]
51
+ # Returns the SOAP response header as a Hash.
52
+ def header
53
+ hash[:envelope][:header]
54
54
  end
55
55
 
56
56
  # Returns the SOAP response body as a Hash.
57
- def to_hash
58
- @hash ||= Savon::SOAP::XML.to_hash basic_hash
57
+ def body
58
+ hash[:envelope][:body]
59
59
  end
60
60
 
61
- # Returns the SOAP response body as an Array.
61
+ alias to_hash body
62
+
63
+ # Traverses the SOAP response body Hash for a given +path+ of Hash keys and returns
64
+ # the value as an Array. Defaults to return an empty Array in case the path does not
65
+ # exist or returns nil.
62
66
  def to_array(*path)
63
- Savon::SOAP::XML.to_array to_hash, *path
67
+ result = path.inject body do |memo, key|
68
+ return [] unless memo[key]
69
+ memo[key]
70
+ end
71
+
72
+ result.kind_of?(Array) ? result.compact : [result].compact
64
73
  end
65
74
 
66
75
  # Returns the complete SOAP response XML without normalization.
67
- def basic_hash
68
- @basic_hash ||= Savon::SOAP::XML.parse http.body
76
+ def hash
77
+ @hash ||= Nori.parse http.body
69
78
  end
70
79
 
71
80
  # Returns the SOAP response XML.
@@ -1,9 +1,13 @@
1
1
  require "builder"
2
- require "nori"
3
2
  require "gyoku"
3
+ require "nori"
4
4
 
5
5
  require "savon/soap"
6
- require "savon/core_ext/hash"
6
+
7
+ Nori.configure do |config|
8
+ config.strip_namespaces = true
9
+ config.convert_tags_to { |tag| tag.snakecase.to_sym }
10
+ end
7
11
 
8
12
  module Savon
9
13
  module SOAP
@@ -20,31 +24,6 @@ module Savon
20
24
  "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance"
21
25
  }
22
26
 
23
- # Converts the given SOAP response +value+ (XML or Hash) into a normalized Hash.
24
- def self.to_hash(value)
25
- value = parse value unless value.kind_of? Hash
26
- value.find_soap_body
27
- end
28
-
29
- # Converts a given SOAP response +xml+ to a Hash.
30
- def self.parse(xml)
31
- Nori.parse(xml)
32
- end
33
-
34
- # Expects a SOAP response XML or Hash, traverses it for a given +path+ of Hash keys
35
- # and returns the value as an Array. Defaults to return an empty Array in case the
36
- # path does not exist or returns nil.
37
- def self.to_array(object, *path)
38
- hash = object.kind_of?(Hash) ? object : to_hash(object)
39
-
40
- result = path.inject hash do |memo, key|
41
- return [] unless memo[key]
42
- memo[key]
43
- end
44
-
45
- result.kind_of?(Array) ? result.compact : [result].compact
46
- end
47
-
48
27
  # Accepts an +endpoint+, an +input+ tag and a SOAP +body+.
49
28
  def initialize(endpoint = nil, input = nil, body = nil)
50
29
  self.endpoint = endpoint if endpoint
@@ -74,7 +53,7 @@ module Savon
74
53
 
75
54
  # Returns the SOAP +header+. Defaults to an empty Hash.
76
55
  def header
77
- @header ||= {}
56
+ @header ||= Savon.soap_header.nil? ? {} : Savon.soap_header
78
57
  end
79
58
 
80
59
  # Sets the SOAP envelope namespace.
@@ -181,4 +160,3 @@ module Savon
181
160
  end
182
161
  end
183
162
  end
184
-
data/lib/savon/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Savon
2
2
 
3
- Version = "0.9.2"
3
+ Version = "0.9.3"
4
4
 
5
5
  end
@@ -90,7 +90,7 @@ module Savon
90
90
  # Executes an HTTP GET request to retrieve a remote WSDL document.
91
91
  def http_request
92
92
  request.url = @document
93
- Request.new(request).response.body
93
+ Request.execute(request).body
94
94
  end
95
95
 
96
96
  # Reads the WSDL document from a local file.
@@ -8,6 +8,12 @@ module Savon
8
8
  # Executes WSDL requests.
9
9
  class Request
10
10
 
11
+ # Expects an <tt>HTTPI::Request</tt> to execute a WSDL request
12
+ # and returns the response.
13
+ def self.execute(request)
14
+ new(request).response
15
+ end
16
+
11
17
  # Expects an <tt>HTTPI::Request</tt>.
12
18
  def initialize(request)
13
19
  self.request = request
data/lib/savon/wsse.rb CHANGED
@@ -2,7 +2,6 @@ require "base64"
2
2
  require "digest/sha1"
3
3
 
4
4
  require "savon/core_ext/string"
5
- require "savon/core_ext/hash"
6
5
  require "savon/core_ext/time"
7
6
 
8
7
  module Savon
@@ -56,20 +55,20 @@ module Savon
56
55
  username && password
57
56
  end
58
57
 
59
- # Returns whether to generate a wsse:Timestamp header.
58
+ # Returns whether to generate a wsu:Timestamp header.
60
59
  def timestamp?
61
- created_at || expires_at || @wsse_timestamp
60
+ created_at || expires_at || @wsu_timestamp
62
61
  end
63
62
 
64
- # Sets whether to generate a wsse:Timestamp header.
63
+ # Sets whether to generate a wsu:Timestamp header.
65
64
  def timestamp=(timestamp)
66
- @wsse_timestamp = timestamp
65
+ @wsu_timestamp = timestamp
67
66
  end
68
67
 
69
68
  # Returns the XML for a WSSE header.
70
69
  def to_xml
71
70
  if username_token? && timestamp?
72
- Gyoku.xml wsse_username_token.merge!(wsse_timestamp) {
71
+ Gyoku.xml wsse_username_token.merge!(wsu_timestamp) {
73
72
  |key, v1, v2| v1.merge!(v2) {
74
73
  |key, v1, v2| v1.merge!(v2)
75
74
  }
@@ -77,7 +76,7 @@ module Savon
77
76
  elsif username_token?
78
77
  Gyoku.xml wsse_username_token.merge!(hash)
79
78
  elsif timestamp?
80
- Gyoku.xml wsse_timestamp.merge!(hash)
79
+ Gyoku.xml wsu_timestamp.merge!(hash)
81
80
  else
82
81
  ""
83
82
  end
@@ -88,33 +87,34 @@ module Savon
88
87
  # Returns a Hash containing wsse:UsernameToken details.
89
88
  def wsse_username_token
90
89
  if digest?
91
- wsse_security "UsernameToken",
90
+ security_hash :wsse, "UsernameToken",
92
91
  "wsse:Username" => username,
93
92
  "wsse:Nonce" => nonce,
94
93
  "wsu:Created" => timestamp,
95
94
  "wsse:Password" => digest_password,
96
95
  :attributes! => { "wsse:Password" => { "Type" => PasswordDigestURI } }
97
96
  else
98
- wsse_security "UsernameToken",
97
+ security_hash :wsse, "UsernameToken",
99
98
  "wsse:Username" => username,
100
99
  "wsse:Password" => password,
101
100
  :attributes! => { "wsse:Password" => { "Type" => PasswordTextURI } }
102
101
  end
103
102
  end
104
103
 
105
- # Returns a Hash containing wsse:Timestamp details.
106
- def wsse_timestamp
107
- wsse_security "Timestamp",
104
+ # Returns a Hash containing wsu:Timestamp details.
105
+ def wsu_timestamp
106
+ security_hash :wsu, "Timestamp",
108
107
  "wsu:Created" => (created_at || Time.now).xs_datetime,
109
108
  "wsu:Expires" => (expires_at || (created_at || Time.now) + 60).xs_datetime
110
109
  end
111
110
 
112
- # Returns a Hash containing wsse:Security details for a given +tag+ and +hash+.
113
- def wsse_security(tag, hash)
111
+ # Returns a Hash containing wsse/wsu Security details for a given
112
+ # +namespace+, +tag+ and +hash+.
113
+ def security_hash(namespace, tag, hash)
114
114
  {
115
115
  "wsse:Security" => {
116
- "wsse:#{tag}" => hash,
117
- :attributes! => { "wsse:#{tag}" => { "wsu:Id" => "#{tag}-#{count}", "xmlns:wsu" => WSUNamespace } }
116
+ "#{namespace}:#{tag}" => hash,
117
+ :attributes! => { "#{namespace}:#{tag}" => { "wsu:Id" => "#{tag}-#{count}", "xmlns:wsu" => WSUNamespace } }
118
118
  },
119
119
  :attributes! => { "wsse:Security" => { "xmlns:wsse" => WSENamespace } }
120
120
  }