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 +1 -0
- data/.travis.yml +2 -1
- data/CHANGELOG.md +35 -1
- data/README.md +6 -5
- data/Rakefile +3 -34
- data/lib/savon/client.rb +1 -1
- data/lib/savon/core_ext/object.rb +1 -1
- data/lib/savon/core_ext/string.rb +2 -15
- data/lib/savon/global.rb +28 -2
- data/lib/savon/soap.rb +0 -3
- data/lib/savon/soap/fault.rb +1 -1
- data/lib/savon/soap/request.rb +6 -0
- data/lib/savon/soap/response.rb +21 -12
- data/lib/savon/soap/xml.rb +7 -29
- data/lib/savon/version.rb +1 -1
- data/lib/savon/wsdl/document.rb +1 -1
- data/lib/savon/wsdl/request.rb +6 -0
- data/lib/savon/wsse.rb +16 -16
- data/savon.gemspec +6 -5
- data/spec/savon/core_ext/string_spec.rb +24 -31
- data/spec/savon/soap/request_spec.rb +14 -6
- data/spec/savon/soap/response_spec.rb +45 -15
- data/spec/savon/soap/xml_spec.rb +5 -58
- data/spec/savon/soap_spec.rb +0 -5
- data/spec/savon/wsdl/request_spec.rb +9 -1
- data/spec/savon/wsse_spec.rb +3 -2
- data/spec/spec_helper.rb +5 -4
- data/spec/support/fixture.rb +3 -5
- metadata +24 -71
- data/lib/savon/core_ext/hash.rb +0 -70
- data/spec/savon/core_ext/hash_spec.rb +0 -121
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
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
|
-
[
|
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
|
-
|
37
|
-
|
37
|
+
Ready for more?
|
38
|
+
---------------
|
38
39
|
|
39
|
-
|
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
|
-
|
4
|
-
|
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)
|
116
|
+
soap.body = options[2].delete(:body)
|
117
117
|
|
118
118
|
set_soap_action options[1]
|
119
119
|
set_soap_input *options
|
@@ -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
|
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
|
-
|
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
|
-
|
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
data/lib/savon/soap/fault.rb
CHANGED
data/lib/savon/soap/request.rb
CHANGED
@@ -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)
|
data/lib/savon/soap/response.rb
CHANGED
@@ -43,29 +43,38 @@ module Savon
|
|
43
43
|
@http_error ||= HTTP::Error.new http
|
44
44
|
end
|
45
45
|
|
46
|
-
#
|
47
|
-
def
|
48
|
-
|
46
|
+
# Shortcut accessor for the SOAP response body Hash.
|
47
|
+
def [](key)
|
48
|
+
body[key]
|
49
49
|
end
|
50
50
|
|
51
|
-
#
|
52
|
-
def
|
53
|
-
|
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
|
58
|
-
|
57
|
+
def body
|
58
|
+
hash[:envelope][:body]
|
59
59
|
end
|
60
60
|
|
61
|
-
|
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
|
-
|
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
|
68
|
-
@
|
76
|
+
def hash
|
77
|
+
@hash ||= Nori.parse http.body
|
69
78
|
end
|
70
79
|
|
71
80
|
# Returns the SOAP response XML.
|
data/lib/savon/soap/xml.rb
CHANGED
@@ -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
|
-
|
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
data/lib/savon/wsdl/document.rb
CHANGED
data/lib/savon/wsdl/request.rb
CHANGED
@@ -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
|
58
|
+
# Returns whether to generate a wsu:Timestamp header.
|
60
59
|
def timestamp?
|
61
|
-
created_at || expires_at || @
|
60
|
+
created_at || expires_at || @wsu_timestamp
|
62
61
|
end
|
63
62
|
|
64
|
-
# Sets whether to generate a
|
63
|
+
# Sets whether to generate a wsu:Timestamp header.
|
65
64
|
def timestamp=(timestamp)
|
66
|
-
@
|
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!(
|
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
|
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
|
-
|
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
|
-
|
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
|
106
|
-
def
|
107
|
-
|
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
|
113
|
-
|
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
|
-
"
|
117
|
-
:attributes! => { "
|
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
|
}
|