savon 2.1.0 → 2.2.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.
- data/.gitignore +1 -0
- data/.travis.yml +2 -1
- data/CHANGELOG.md +38 -0
- data/CONTRIBUTING.md +46 -0
- data/Gemfile +1 -1
- data/README.md +30 -18
- data/lib/savon.rb +5 -3
- data/lib/savon/builder.rb +14 -2
- data/lib/savon/client.rb +17 -6
- data/lib/savon/message.rb +2 -0
- data/lib/savon/mock.rb +1 -1
- data/lib/savon/operation.rb +15 -7
- data/lib/savon/options.rb +10 -0
- data/lib/savon/soap_fault.rb +14 -6
- data/lib/savon/version.rb +1 -1
- data/savon.gemspec +5 -5
- data/spec/fixtures/wsdl/betfair.xml +2981 -0
- data/spec/fixtures/wsdl/edialog.xml +15416 -0
- data/spec/fixtures/wsdl/interhome.xml +2137 -0
- data/spec/fixtures/wsdl/team_software.xml +1 -0
- data/spec/fixtures/wsdl/wasmuth.xml +153 -0
- data/spec/integration/email_example_spec.rb +1 -1
- data/spec/integration/ratp_example_spec.rb +3 -1
- data/spec/integration/stockquote_example_spec.rb +1 -1
- data/spec/integration/temperature_example_spec.rb +1 -1
- data/spec/integration/zipcode_example_spec.rb +1 -1
- data/spec/savon/builder_spec.rb +6 -0
- data/spec/savon/client_spec.rb +27 -1
- data/spec/savon/features/message_tag_spec.rb +56 -0
- data/spec/savon/mock_spec.rb +16 -0
- data/spec/savon/model_spec.rb +0 -1
- data/spec/savon/operation_spec.rb +11 -1
- data/spec/savon/options_spec.rb +37 -35
- data/spec/savon/soap_fault_spec.rb +32 -0
- data/spec/spec_helper.rb +8 -7
- data/spec/support/integration.rb +9 -0
- data/spec/support/stdout.rb +25 -0
- metadata +22 -15
- data/.rspec +0 -1
- data/savon.sublime-workspace +0 -494
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,41 @@
|
|
1
|
+
### 2.2.0 (2013-04-21)
|
2
|
+
|
3
|
+
* Feature: [#416](https://github.com/savonrb/savon/pull/416) The global `namespace_identifier`
|
4
|
+
option can now be set to `nil` to not add a namespace identifier to the message tag.
|
5
|
+
|
6
|
+
* Feature: [#408](https://github.com/savonrb/savon/pull/408) Added `Savon::Client#service_name`
|
7
|
+
to return the name of the SOAP service.
|
8
|
+
|
9
|
+
* Improvement: When mistyping an option name, Savon used to raise a simple `NoMethodError`.
|
10
|
+
This is because regardless of whether you're using the Hash or block syntax to pass global
|
11
|
+
or local options, both are just method calls on some options object.
|
12
|
+
|
13
|
+
```
|
14
|
+
NoMethodError: undefined method 'wsdk' for #<Savon::GlobalOptions:0x007fed95a55228>
|
15
|
+
```
|
16
|
+
|
17
|
+
As of this change, Savon now catches those errors and raise a `Savon::UnknownOptionError`
|
18
|
+
with a slightly more helpful error message instead.
|
19
|
+
|
20
|
+
```
|
21
|
+
Savon::UnknownOptionError:
|
22
|
+
Unknown global option: :wsdk
|
23
|
+
```
|
24
|
+
|
25
|
+
* Improvement: [#385](https://github.com/savonrb/savon/issues/385) Instead of raising an
|
26
|
+
`ArgumentError` when Wasabi can't find any operations in the WSDL. Savon now raises a
|
27
|
+
`Savon::UnknownOperationError`. This might happen when Wasabi fails to parse the WSDL
|
28
|
+
because of imports for example.
|
29
|
+
|
30
|
+
* Fix: [#430](https://github.com/savonrb/savon/pull/430) allows you to rescue and ignore
|
31
|
+
`Savon::Error` errors in production while still having mocks trigger test failures.
|
32
|
+
|
33
|
+
* Fix: [#393](https://github.com/savonrb/savon/pull/393) changed `Savon::SOAPFault` to work
|
34
|
+
with generic response Hash keys.
|
35
|
+
|
36
|
+
* Fix: [#423](https://github.com/savonrb/savon/issues/423) fixes a problem where Wasabi was
|
37
|
+
not able to find extension base elements defined in imports it didn't follow.
|
38
|
+
|
1
39
|
### 2.1.0 (2013-02-03)
|
2
40
|
|
3
41
|
* Feature: [#372](https://github.com/savonrb/savon/pull/372) added global `ssl_cert_key_password` option.
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Contribution Guide
|
2
|
+
|
3
|
+
This page describes how to contribute changes to Savon.
|
4
|
+
|
5
|
+
Please do not create a pull request without reading this guide first.
|
6
|
+
Make sure to read the documentation for your version at [savonrb.com](http://savonrb.com/)
|
7
|
+
and post questions to the [mailing list](https://groups.google.com/forum/#!forum/savonrb).
|
8
|
+
|
9
|
+
**Bug fixes**
|
10
|
+
|
11
|
+
If you really think you found a bug, please make sure to add as many information as possible
|
12
|
+
to the ticket. You're a developer, we are developers and you know we need tests to reproduce
|
13
|
+
problems and make sure they don't come back.
|
14
|
+
|
15
|
+
So if you can reproduce your problem in a spec, that would be awesome! If you can't, please
|
16
|
+
let us know how we could make this easier for you. Also, provide code and the WSDL of the
|
17
|
+
service your working with so others can try to come up with a spec for your problem.
|
18
|
+
|
19
|
+
After we have a failing spec, it obviously needs to be fixed. Make sure your new spec is the
|
20
|
+
only failing one under the `spec` directory. Travis only runs the "unit tests" at `spec/savon`,
|
21
|
+
but Savon actually has with some additional "integration/example specs" at `spec/integration`,
|
22
|
+
which you need to run locally to make sure the integration with real world services still works.
|
23
|
+
|
24
|
+
Notice that these specs are not run by Travis, because the service's are not guaranteed to work
|
25
|
+
all the time and the specs will timeout after a few seconds when the service is currently down.
|
26
|
+
|
27
|
+
Please follow this basic workflow for pull requests:
|
28
|
+
|
29
|
+
* [Fork the project](https://help.github.com/articles/fork-a-repo)
|
30
|
+
* Create a feature branch and make your bug fix
|
31
|
+
* Add tests for it!
|
32
|
+
* Update the [Changelog](https://github.com/savonrb/savon/blob/master/CHANGELOG.md)
|
33
|
+
* [Send a pull request](https://help.github.com/articles/using-pull-requests)
|
34
|
+
* [Check that your pull request passes the build](https://travis-ci.org/savonrb/savon/pull_requests)
|
35
|
+
|
36
|
+
|
37
|
+
**Improvements and feature requests**
|
38
|
+
|
39
|
+
If you have an idea for an improvement or a new feature, please feel free to
|
40
|
+
[create a new issue](https://github.com/savonrb/savon/issues/new) and describe your idea
|
41
|
+
so that other people can give their insights and opinions. This is also important to avoid
|
42
|
+
duplicate work.
|
43
|
+
|
44
|
+
Pull requests and issues on GitHub are meant to be used to discuss problems and ideas,
|
45
|
+
so please make sure to participate and follow up on questions. In case noone comments
|
46
|
+
on your ticket, please keep updating the ticket with additional information.
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
Savon
|
2
|
-
=====
|
1
|
+
# Savon
|
3
2
|
|
4
3
|
Heavy metal SOAP client
|
5
4
|
|
6
5
|
[Documentation](http://savonrb.com) | [RDoc](http://rubydoc.info/gems/savon) |
|
7
6
|
[Mailing list](https://groups.google.com/forum/#!forum/savonrb) | [Twitter](http://twitter.com/savonrb)
|
8
7
|
|
8
|
+
[](http://travis-ci.org/savonrb/savon)
|
9
|
+
[](http://badge.fury.io/rb/savon)
|
10
|
+
[](https://codeclimate.com/github/savonrb/savon)
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
+
|
13
|
+
## Installation
|
12
14
|
|
13
15
|
Savon is available through [Rubygems](http://rubygems.org/gems/savon) and can be installed via:
|
14
16
|
|
@@ -16,30 +18,40 @@ Savon is available through [Rubygems](http://rubygems.org/gems/savon) and can be
|
|
16
18
|
$ gem install savon
|
17
19
|
```
|
18
20
|
|
21
|
+
or add it to your Gemfile like this:
|
22
|
+
|
23
|
+
```
|
24
|
+
gem 'savon', '~> 2.1.0'
|
25
|
+
```
|
26
|
+
|
19
27
|
|
20
|
-
|
21
|
-
------------
|
28
|
+
## Usage example
|
22
29
|
|
23
30
|
``` ruby
|
24
|
-
require
|
31
|
+
require 'savon'
|
25
32
|
|
26
|
-
# create a client for
|
27
|
-
client = Savon.client(wsdl:
|
33
|
+
# create a client for the service
|
34
|
+
client = Savon.client(wsdl: 'http://service.example.com?wsdl')
|
28
35
|
|
29
36
|
client.operations
|
30
|
-
# => [:
|
37
|
+
# => [:find_user, :list_users]
|
31
38
|
|
32
|
-
#
|
33
|
-
response = client.call(:
|
34
|
-
message(user_id: 1)
|
35
|
-
end
|
39
|
+
# call the 'findUser' operation
|
40
|
+
response = client.call(:find_user, message: { id: 42 })
|
36
41
|
|
37
42
|
response.body
|
38
|
-
# => { :
|
43
|
+
# => { find_user_response: { id: 42, name: 'Hoff' } }
|
39
44
|
```
|
40
45
|
|
46
|
+
For more examples, you should check out the [integration tests](https://github.com/savonrb/savon/tree/master/spec/integration).
|
47
|
+
|
48
|
+
|
49
|
+
## Documentation
|
50
|
+
|
51
|
+
Please make sure to read the documentation for your version:
|
41
52
|
|
42
|
-
|
43
|
-
|
53
|
+
* [Version 2](http://savonrb.com/version2.html)
|
54
|
+
* [Version 1](http://savonrb.com)
|
44
55
|
|
45
|
-
|
56
|
+
And if you find any problems with it or if you think something's missing,
|
57
|
+
feel free to [help out and improve the documentation](https://github.com/savonrb/savonrb.com).
|
data/lib/savon.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
module Savon
|
2
2
|
|
3
|
-
Error
|
4
|
-
InitializationError
|
5
|
-
|
3
|
+
Error = Class.new(RuntimeError)
|
4
|
+
InitializationError = Class.new(Error)
|
5
|
+
UnknownOptionError = Class.new(Error)
|
6
|
+
UnknownOperationError = Class.new(Error)
|
7
|
+
InvalidResponseError = Class.new(Error)
|
6
8
|
|
7
9
|
def self.client(globals = {}, &block)
|
8
10
|
Client.new(globals, &block)
|
data/lib/savon/builder.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "savon/header"
|
2
2
|
require "savon/message"
|
3
|
+
require "nokogiri"
|
3
4
|
require "builder"
|
4
5
|
require "gyoku"
|
5
6
|
|
@@ -27,6 +28,10 @@ module Savon
|
|
27
28
|
@used_namespaces = convert_type_namespaces_to_hash
|
28
29
|
end
|
29
30
|
|
31
|
+
def pretty
|
32
|
+
Nokogiri.XML(to_s).to_xml(:indent => 2)
|
33
|
+
end
|
34
|
+
|
30
35
|
def to_s
|
31
36
|
return @locals[:xml] if @locals.include? :xml
|
32
37
|
|
@@ -72,7 +77,12 @@ module Savon
|
|
72
77
|
def namespaces
|
73
78
|
@namespaces ||= begin
|
74
79
|
namespaces = SCHEMA_TYPES.dup
|
75
|
-
|
80
|
+
|
81
|
+
if namespace_identifier == nil
|
82
|
+
namespaces["xmlns"] = @globals[:namespace] || @wsdl.namespace
|
83
|
+
else
|
84
|
+
namespaces["xmlns:#{namespace_identifier}"] = @globals[:namespace] || @wsdl.namespace
|
85
|
+
end
|
76
86
|
|
77
87
|
key = ["xmlns"]
|
78
88
|
key << env_namespace if env_namespace && env_namespace != ""
|
@@ -91,7 +101,9 @@ module Savon
|
|
91
101
|
end
|
92
102
|
|
93
103
|
def namespaced_message_tag
|
94
|
-
if
|
104
|
+
if namespace_identifier == nil
|
105
|
+
[message_tag, message_attributes]
|
106
|
+
elsif @used_namespaces[[@operation_name.to_s]]
|
95
107
|
[@used_namespaces[[@operation_name.to_s]], message_tag, message_attributes]
|
96
108
|
else
|
97
109
|
[namespace_identifier, message_tag, message_attributes]
|
data/lib/savon/client.rb
CHANGED
@@ -12,9 +12,7 @@ module Savon
|
|
12
12
|
raise_version1_initialize_error! globals
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
BlockInterface.new(@globals).evaluate(block) if block
|
15
|
+
set_globals(globals, block)
|
18
16
|
|
19
17
|
unless wsdl_or_endpoint_and_namespace_specified?
|
20
18
|
raise_initialization_error!
|
@@ -38,14 +36,27 @@ module Savon
|
|
38
36
|
operation(operation_name).call(locals, &block)
|
39
37
|
end
|
40
38
|
|
39
|
+
def service_name
|
40
|
+
raise_missing_wsdl_error! unless @wsdl.document?
|
41
|
+
@wsdl.service_name
|
42
|
+
end
|
43
|
+
|
41
44
|
private
|
42
45
|
|
46
|
+
def set_globals(globals, block)
|
47
|
+
globals = GlobalOptions.new(globals)
|
48
|
+
BlockInterface.new(globals).evaluate(block) if block
|
49
|
+
|
50
|
+
@globals = globals
|
51
|
+
end
|
52
|
+
|
43
53
|
def build_wsdl_document
|
44
54
|
@wsdl = Wasabi::Document.new
|
45
55
|
|
46
|
-
@wsdl.document
|
47
|
-
@wsdl.endpoint
|
48
|
-
@wsdl.namespace
|
56
|
+
@wsdl.document = @globals[:wsdl] if @globals.include? :wsdl
|
57
|
+
@wsdl.endpoint = @globals[:endpoint] if @globals.include? :endpoint
|
58
|
+
@wsdl.namespace = @globals[:namespace] if @globals.include? :namespace
|
59
|
+
@wsdl.servicename = @globals[:servicename] if @globals.include? :servicename
|
49
60
|
|
50
61
|
@wsdl.request = WSDLRequest.new(@globals).build
|
51
62
|
end
|
data/lib/savon/message.rb
CHANGED
@@ -20,6 +20,8 @@ module Savon
|
|
20
20
|
|
21
21
|
if @element_form_default == :qualified
|
22
22
|
translated_operation_name = Gyoku.xml_tag(@operation_name, :key_converter => @key_converter).to_s
|
23
|
+
# XXX: there is no `@request_key_converter` instance variable!
|
24
|
+
# the third argument is therefore always `nil`. [dh, 2013-03-09]
|
23
25
|
@message = QualifiedMessage.new(@types, @used_namespaces, @request_key_converter).to_hash(@message, [translated_operation_name])
|
24
26
|
end
|
25
27
|
|
data/lib/savon/mock.rb
CHANGED
data/lib/savon/operation.rb
CHANGED
@@ -19,8 +19,8 @@ module Savon
|
|
19
19
|
|
20
20
|
def self.ensure_exists!(operation_name, wsdl)
|
21
21
|
unless wsdl.soap_actions.include? operation_name
|
22
|
-
raise
|
23
|
-
|
22
|
+
raise UnknownOperationError, "Unable to find SOAP operation: #{operation_name.inspect}\n" \
|
23
|
+
"Operations provided by your service: #{wsdl.soap_actions.inspect}"
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -37,12 +37,13 @@ module Savon
|
|
37
37
|
@globals = globals
|
38
38
|
end
|
39
39
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
def build(locals = {}, &block)
|
41
|
+
set_locals(locals, block)
|
42
|
+
Builder.new(@name, @wsdl, @globals, @locals)
|
43
|
+
end
|
44
44
|
|
45
|
-
|
45
|
+
def call(locals = {}, &block)
|
46
|
+
builder = build(locals, &block)
|
46
47
|
|
47
48
|
response = Savon.notify_observers(@name, builder, @globals, @locals)
|
48
49
|
response ||= call! build_request(builder)
|
@@ -54,6 +55,13 @@ module Savon
|
|
54
55
|
|
55
56
|
private
|
56
57
|
|
58
|
+
def set_locals(locals, block)
|
59
|
+
locals = LocalOptions.new(locals)
|
60
|
+
BlockInterface.new(locals).evaluate(block) if block
|
61
|
+
|
62
|
+
@locals = locals
|
63
|
+
end
|
64
|
+
|
57
65
|
def call!(request)
|
58
66
|
log_request(request) if log?
|
59
67
|
response = HTTPI.post(request)
|
data/lib/savon/options.rb
CHANGED
@@ -9,6 +9,8 @@ module Savon
|
|
9
9
|
assign options
|
10
10
|
end
|
11
11
|
|
12
|
+
attr_reader :option_type
|
13
|
+
|
12
14
|
def [](option)
|
13
15
|
@options[option]
|
14
16
|
end
|
@@ -30,11 +32,17 @@ module Savon
|
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
35
|
+
def method_missing(option, _)
|
36
|
+
raise UnknownOptionError, "Unknown #{option_type} option: #{option.inspect}"
|
37
|
+
end
|
38
|
+
|
33
39
|
end
|
34
40
|
|
35
41
|
class GlobalOptions < Options
|
36
42
|
|
37
43
|
def initialize(options = {})
|
44
|
+
@option_type = :global
|
45
|
+
|
38
46
|
defaults = {
|
39
47
|
:encoding => "UTF-8",
|
40
48
|
:soap_version => 1,
|
@@ -243,6 +251,8 @@ module Savon
|
|
243
251
|
class LocalOptions < Options
|
244
252
|
|
245
253
|
def initialize(options = {})
|
254
|
+
@option_type = :local
|
255
|
+
|
246
256
|
defaults = {
|
247
257
|
:advanced_typecasting => true,
|
248
258
|
:response_parser => :nokogiri
|
data/lib/savon/soap_fault.rb
CHANGED
@@ -19,20 +19,28 @@ module Savon
|
|
19
19
|
attr_reader :http, :nori
|
20
20
|
|
21
21
|
def to_s
|
22
|
-
|
22
|
+
fault = nori.find(to_hash, 'Fault')
|
23
|
+
message_by_version(fault)
|
23
24
|
end
|
24
25
|
|
25
26
|
def to_hash
|
26
|
-
nori.parse(@http.body)
|
27
|
+
parsed = nori.parse(@http.body)
|
28
|
+
nori.find(parsed, 'Envelope', 'Body')
|
27
29
|
end
|
28
30
|
|
29
31
|
private
|
30
32
|
|
31
33
|
def message_by_version(fault)
|
32
|
-
if fault
|
33
|
-
|
34
|
-
|
35
|
-
|
34
|
+
if nori.find(fault, 'faultcode')
|
35
|
+
code = nori.find(fault, 'faultcode')
|
36
|
+
text = nori.find(fault, 'faultstring')
|
37
|
+
|
38
|
+
"(#{code}) #{text}"
|
39
|
+
elsif nori.find(fault, 'Code')
|
40
|
+
code = nori.find(fault, 'Code', 'Value')
|
41
|
+
text = nori.find(fault, 'Reason', 'Text')
|
42
|
+
|
43
|
+
"(#{code}) #{text}"
|
36
44
|
end
|
37
45
|
end
|
38
46
|
|
data/lib/savon/version.rb
CHANGED
data/savon.gemspec
CHANGED
@@ -11,13 +11,13 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.email = "me@rubiii.com"
|
12
12
|
s.homepage = "http://savonrb.com"
|
13
13
|
s.summary = "Heavy metal SOAP client"
|
14
|
-
s.description =
|
14
|
+
s.description = s.summary
|
15
15
|
|
16
16
|
s.rubyforge_project = s.name
|
17
17
|
|
18
|
-
s.add_dependency "nori", "~> 2.0
|
18
|
+
s.add_dependency "nori", "~> 2.1.0"
|
19
19
|
s.add_dependency "httpi", "~> 2.0.2"
|
20
|
-
s.add_dependency "wasabi", "~> 3.
|
20
|
+
s.add_dependency "wasabi", "~> 3.1.0"
|
21
21
|
s.add_dependency "akami", "~> 1.2.0"
|
22
22
|
s.add_dependency "gyoku", "~> 1.0.0"
|
23
23
|
|
@@ -25,7 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_dependency "nokogiri", ">= 1.4.0"
|
26
26
|
|
27
27
|
s.add_development_dependency "rack"
|
28
|
-
s.add_development_dependency "puma", "
|
28
|
+
s.add_development_dependency "puma", "2.0.0.b4"
|
29
29
|
|
30
30
|
s.add_development_dependency "rake", "~> 0.9"
|
31
31
|
s.add_development_dependency "rspec", "~> 2.10"
|
@@ -33,7 +33,7 @@ Gem::Specification.new do |s|
|
|
33
33
|
s.add_development_dependency "json", "~> 1.7"
|
34
34
|
|
35
35
|
ignores = File.readlines(".gitignore").grep(/\S+/).map(&:chomp)
|
36
|
-
dotfiles = %w[.gitignore .
|
36
|
+
dotfiles = %w[.gitignore .travis.yml .yardopts]
|
37
37
|
|
38
38
|
all_files_without_ignores = Dir["**/*"].reject { |f|
|
39
39
|
File.directory?(f) || ignores.any? { |i| File.fnmatch(i, f) }
|