savon 0.9.2 → 0.9.3

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