savon 2.1.0 → 2.2.0
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 +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
|
+
[![Build Status](https://secure.travis-ci.org/savonrb/savon.png)](http://travis-ci.org/savonrb/savon)
|
9
|
+
[![Gem Version](https://badge.fury.io/rb/savon.png)](http://badge.fury.io/rb/savon)
|
10
|
+
[![Code Climate](https://codeclimate.com/github/savonrb/savon.png)](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) }
|